Costante incorporato per l’ottimizzazione delle condizioni del ciclo in C ++ con gcc

Un compilatore ottimizzerà i tih:

bool someCondition = someVeryTimeConsumingTask(/* ... */); for (int i=0; i<HUGE_INNER_LOOP; ++i) { if (someCondition) doCondition(i); else bacon(i); } 

in:

 bool someCondition = someVeryTimeConsumingTask(/* ... */); if (someCondition) for (int i=0; i<HUGE_INNER_LOOP; ++i) doCondition(i); else for (int i=0; i<HUGE_INNER_LOOP; ++i) bacon(i); 

someCondition è banalmente costante all’interno del ciclo for.

Questo può sembrare ovvio e che dovrei farlo da solo, ma se hai più di una condizione, hai a che fare con permeanze di cicli for, quindi il codice sarebbe un po ‘più lungo. Sto decidendo se farlo (sto già ottimizzando) o se sarà uno spreco del mio tempo.

È ansible che il compilatore possa scrivere il codice come hai fatto tu, ma non ho mai visto tale ottimizzazione.

Tuttavia c’è qualcosa chiamato branch forecast nella CPU moderna. In pratica significa che quando viene richiesto al processore di eseguire un salto condizionato, inizierà a eseguire quello che è ritenuto il ramo più probabile prima di valutare la condizione. Questo è fatto per mantenere la pipeline piena di istruzioni.

Nel caso in cui il processore fallisca (e prenda il ramo cattivo) causerà un flush della pipeline: si parla di errata previsione.

Un tratto molto comune di questa caratteristica è che se lo stesso test produce lo stesso risultato più volte in una riga, allora verrà considerato produrre lo stesso risultato dall’algoritmo di predizione del ramo … che è ovviamente adattato per i loop: )

Mi fa sorridere perché ti preoccupi del if nel corpo mentre il for sé causa una previsione del ramo >> la condizione deve essere valutata ad ogni iterazione per verificare se continuare o meno;)

Quindi, non ti preoccupare, costa meno di una mancanza di cache.

Ora, se sei davvero preoccupato per questo, c’è sempre l’approccio del functor.

 typedef void (*functor_t)(int); functor_t func = 0; if (someCondition) func = &doCondition; else func = &bacon; for (int i=0; i 

che sicuramente sembra molto meglio, vero? L'ovvio inconveniente è la necessità di firme compatibili, ma è ansible scrivere wrapper attorno alle funzioni per quello. Finché non hai bisogno di rompere / tornare, starai bene con questo. Altrimenti avresti bisogno di un if nel corpo del ciclo: D

Non sembra farlo con le ottimizzazioni -O2 o -O3. Questo è qualcosa che puoi (e dovresti, se ti preoccupi dell’ottimizzazione) testare te stesso – compilare con l’ottimizzazione che ti interessa ed esaminare il linguaggio assembly emesso.

Hai profilato la tua app per scoprire dove sono i rallentamenti? Altrimenti, perché stai pensando all’ottimizzazione? Finché non sai quali metodi devono essere ottimizzati, stai sprecando tempo a preoccuparti delle micro-ottimizzazioni come questa.

È questa la posizione del rallentamento? Se è così, allora quello che stai facendo può essere utile. Sì, il compilatore può ottimizzare questo, ma non è garantito che lo faccia. Se questa non è la posizione del rallentamento, guarda altrove; il costo di un ramo aggiuntivo ogni volta attraverso il ciclo è probabilmente banale rispetto a tutti gli altri lavori che stai facendo.