2012-07-15 12 views
7

Ho cercato di limitare i puntatori qualificati e ho riscontrato un problema. Il seguente programma è solo uno semplice per presentare il problema.Limita i puntatori e la sottolineatura

Il calc_function utilizza tre puntatori, che è limitato in modo che "NON" si alias l'uno con l'altro. Quando si compila questo codice in Visual Studio, la funzione verrà evidenziata, quindi per nessun motivo Visual Studio 2010 ignora i qualificatori. Se disabilito l'inlining, il codice viene eseguito più di sei volte più velocemente (da 2200ms a 360ms). Ma non voglio disabilitare la funzione di inlining nell'intero progetto né l'intero file (perché in tal caso si tratta di overhead di chiamate, ad esempio, di tutti i getter e setter, il che sarebbe orribile).

(potrebbe l'unica soluzione quella di disabilitare inlining di questa funzione solo?)

Ho cercato di creare limitare temporanea puntatori qualificati nella funzione, sia nella parte superiore e nel ciclo interno per cercare di raccontare la compilatore che prometto che non esiste aliasing, ma il compilatore non mi crede e non funzionerà. Ho anche provato a modificare le impostazioni del compilatore, ma l'unico che ho trovato funziona, è disabilitare la funzione di inlining.

Apprezzerei un po 'di aiuto per risolvere questo problema di ottimizzazione.

Per eseguire il programma (in realeasemode) non dimenticare di utilizzare gli argomenti 0 1000 2000. Perché l'uso degli argomenti userinput/programma è quello di essere sicuri che il compilatore non possa sapere se c'è o non è t aliasing tra i puntatori a, b e c.

#include <cstdlib> 
#include <cstdio> 
#include <ctime> 

// Data-table where a,b,c will point into, so the compiler cant know if they alias. 
const size_t listSize = 10000; 
int data[listSize]; 

//void calc_function(int * a, int * b, int * c){ 
void calc_function(int *__restrict a, int *__restrict b, int *__restrict c){ 
    for(size_t y=0; y<1000*1000; ++y){ // <- Extra loop to be able to messure the time. 
     for(size_t i=0; i<1000; ++i){ 
      *a += *b; 
      *c += *a; 
     } 
    } 
} 
int main(int argc, char *argv[]){ // argv SHALL be "0 1000 2000" (with no quotes) 
    // init 
    for(size_t i=0; i<listSize; ++i) 
     data[i] = i; 

    // get a, b and c from argv(0,1000,2000) 
    int *a,*b,*c; 
    sscanf(argv[1],"%d",&a); 
    sscanf(argv[2],"%d",&b); 
    sscanf(argv[3],"%d",&c); 
    a = data + int(a); // a, b and c will (after the specified argv) be, 
    b = data + int(b); // a = &data[0], b = &data[1000], c = &data[2000], 
    c = data + int(c); // So they will not alias, and the compiler cant know. 

    // calculate and take time 
    time_t start = clock(); 
     funcResticted(a,b,c); 
    time_t end = clock(); 
    time_t t = (end-start); 
    printf("funcResticted  %u (microSec)\n", t); 

    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+1

+1 per buone pratiche di profilazione. Opterò per non lamentarmi dell'identificatore di formato. Post scriptum 'clock' restituisce un' clock_t', non un 'time_t'. – Hurkyl

+1

Provare a sorvegliare la chiamata di funzione controllando che gli offset siano sufficientemente grandi. Probabilmente dovrai usare le vere variabili 'int' per memorizzare gli offset, piuttosto che l'hack che hai usato. – Hurkyl

+0

@Hurkyl Ho pensato che clock_t e time_t fossero entrambi typedefs alla stessa cosa, ma tu hai ragione. (Btw, come modifico il mio questionario?) – Boll

risposta

3

Se si dichiara una funzione con __declspec(noinline), si costringerà a non essere inline:

http://msdn.microsoft.com/en-us/library/kxybs02x%28v=vs.80%29.aspx

È possibile utilizzare questo per disabilitare manualmente inline su una base per-funzione.


Per quanto riguarda restrict, il compilatore è libero di usarlo solo quando vuole. Quindi giocare con versioni diverse dello stesso codice è in qualche modo inevitabile quando si tenta di "ingannare" i compilatori per fare tali ottimizzazioni.

+0

Questa soluzione funziona, sia nel codice di test nella domanda, sia nella mia vera applicazione. Ma ci saranno alcuni problemi se una funzione molto piccola, che viene chiamata più volte, necessita di limitatori qualificati limitati, in cui __declspec (noinline) imporrà un overhead di chiamata abbastanza grande. Perciò, aspetterò accettando questa come la migliore risposta. – Boll

+0

Sì, lo so cosa intendi. La mia ipotesi è che l'analisi alias-puntatore utilizzata in VS2010 sia solo a livello di granularità a livello di funzione. Quindi non è in grado di distinguere i puntatori non aliasing che sono "generati" nel mezzo di una funzione. Non sono sicuro che 'restrict' possa essere usato su puntatori dichiarati localmente. Se lo fa, potrebbe essere qualcosa da provare. – Mysticial

+0

Hai perfettamente ragione, e ho provato a utilizzare localmente i puntatori dichiarati con restrizioni senza fortuna.Il tuo "__declspec (noinline)" è la soluzione migliore e funziona nel mio caso corrente (la mia domanda), quindi lo accetto come la risposta. Grazie. – Boll