2012-10-10 16 views
5
  1. C'è una differenza tra i seguenti due blocchi di codice in termini del codice macchina risultante quando si utilizzano i compilatori llvm o gcc?
  2. Quando è davvero utile questa ottimizzazione, se mai?

non ottimizzato:Vale la pena precedere il condizionale in un ciclo for?

for (int i=0; i<array.count; i++) { 
    //do some work 
} 

ottimizzata:

int count = array.count; 
for (int i=0; i<count; i++) { 
    //do some work 
} 

EDIT: I sottolineare che array è immutabile e array.count non cambia durante l'esecuzione del ciclo.

+2

Spesso non è necessario in quanto il compilatore molto probabilmente lo farà comunque. Ma l'unico modo per essere sicuri è testare entrambi i modi e misurare. Per quanto riguarda il codice macchina risultante, puoi facilmente controllare te stesso, sia clang che gcc hanno i flag per generare i file assembler, e potresti sempre smontare l'eseguibile se non altro. –

+1

In questo caso, c'è un messaggio inviato a un oggetto, dubito che il compilatore interferisca con esso, quindi la mia ipotesi sarebbe che il metodo 'count' sarà chiamato su ogni iterazione. Tuttavia, è probabilmente una chiamata molto economica. Il modo migliore in questo caso particolare sarebbe utilizzare l'enumerazione rapida sull'array. – Guillaume

+3

"array is immutable e array.count non cambia" - Non conosco Objective-C, se "immutable" è una proprietà che il compilatore capisce, ma per scopi di ottimizzazione non importa se o no array.count' cambia, è importante che il compilatore possa provare a se stesso che 'array.count' non cambia. –

risposta

3
  1. È davvero necessario controllare da soli. La mia ipotesi è che ci sia è una differenza nel codice emesso, ma potrebbe dipendere dal compilatore e dalle opzioni del compilatore, e certamente può dipendere dalla definizione di array.
  2. Quasi mai, partendo dal presupposto che la valutazione di array.count è quasi sempre insignificante rispetto a "un po 'di lavoro". Il modo per misurarlo, tuttavia, consiste nell'utilizzare un profiler (o equivalente) e osservare quale percentuale del tempo di esecuzione del tuo programma viene speso in quella riga di codice. A patto che il profiler sia accurato, è la più che potresti sperare di ottenere cambiando.

Supponiamo array.count è qualcosa di molto lento, che vi capita di conoscere restituirà sempre lo stesso risultato, ma il compilatore non sa che. Quindi potrebbe valer la pena di sollevarlo manualmente. strlen viene utilizzato come esempio. E 'discutibile quanto spesso strlen è realtà lenta, in pratica, ma facili da produrre esempi che possono correre più lento di quello di cui hanno bisogno a:

char some_function(char a) { 
    return (a * 2 + 1) & 0x3F; 
} 

for (int i = 0; i < strlen(ptr); ++i) { 
    ptr[i] = some_function(ptr[i]); // faster than strlen for long enough strings. 
} 

Tu ed io sappiamo che some_function mai restituisce 0, e quindi la lunghezza del la stringa non cambia mai. Il compilatore potrebbe non vedere la definizione di some_function e anche se vede la definizione potrebbe non rendersi conto che la sua non-zero-restituzione è importante.

1

La risposta di Steve Jessop è buona. Voglio solo aggiungere:

Personalmente, io uso sempre la versione ottimizzata. È solo nel mio insieme di buone pratiche rimuovere ogni componente costante dal ciclo. Non è molto lavoro e rende il codice più pulito. Non è "ottimizzazione prematura" e non introduce problemi o compromessi. Semplifica il debugging (stepping). E potrebbe potenzialmente rendere il codice più veloce. Quindi è un gioco da ragazzi per me.