2016-02-02 26 views
7

Ho codice hotspot che viene eseguito in un loop stretto:Evitare ripetizioni/loop unswitching

for (i = 0; i < big; i++) 
{ 
    if (condition1) { 
     do1(); 
    } else if (condition2) { 
     do2(); 
    } else { 
     do3(); 
    } 
    // Shared code goes here 
    // More shared code goes here 
} 

Dal condition1 e condition2 sono invarianti, io non commutata il ciclo per

if (condition1) { 
    for (i = 0; i < big; i++) 
    { 
     do1(); 
     // Shared code goes here 
     // More shared code goes here 
    } 
} else if (condition 2) { 
    for (i = 0; i < big; i++) 
    { 
     do2(); 
     // Shared code goes here 
     // More shared code goes here 
    } 
} else { 
    for (i = 0; i < big; i++) 
    { 
     do3(); 
     // Shared code goes here 
     // More shared code goes here 
    } 
} 

Questo funziona molto meglio, ma mi chiedo se c'è un modo intelligente per farlo senza ripetermi?

+0

Forse potresti utilizzare un puntatore a funzione. Impostalo in base alle condizioni, quindi utilizzalo all'interno di un singolo ciclo. –

+0

Le condizioni1 e le condizioni2 sono note al momento della compilazione? – Straw1239

+0

@ Straw1239: No, possono differire ogni volta che viene chiamata la funzione. – Charles

risposta

4

Un altro, forse un po 'più efficiente opzione è quella di utilizzare una macro per costruire il codice per voi:

#define DO_N(name, ...) for(int i = 0; i < big; i++){name(__VA_ARGS__);/*shared code*/} 

if (condition1) { 
    DO_N(do1, .../*arguments here*/) 
} else if (condition 2) { 
    DO_N(do2, ...) 
} else { 
    DO_N(do3, ...) 
} 

#undef DO_N 

E ' s brutto, ma penso che faccia quello che vuoi, e potrebbe consentire di inlining dove un puntatore di funzione non lo fa.

Inoltre, è possibile che sia più leggibile inserire il codice condiviso in una macro o funzione separata.

+0

Vedere [il mio altro commento] (http://stackoverflow.com/questions/35161175/avoiding-repetition-loop-unswitching#comment58041402_35161313), in cui le chiamate tramite i puntatori di funzione sono (potenzialmente) in linea. Vale la pena misurare e giocare con il collegamento prima di arrivare alle conclusioni sulle prestazioni. – chris

+0

@chris l'ho visto, ed è bello sapere che i compilatori sono bravi in ​​questo. Non ero sicuro, così ho detto "potrebbe". – Straw1239

+0

Sì, sarei sicuramente cauto nel presumere che * saranno * inline con la stessa facilità. Per quanto ne so, i puntatori di funzione sono molto più frequenti e mi sembra che GCC avesse bisogno di un po 'di stimolazione, al punto da poter eliminare completamente la funzione. – chris

3

penso che si può dichiarare un puntatore a funzione e qualche funzione foo():

typedef void (*fp)(void); 

void foo(int big, fp f) { 
    for (int i = 0; i < big; ++i) { 
     f(); 
     // Shared code goes here 
     // More shared code goes her 
    } 
} 

quindi modificare il codice per qualcosa di simile:

if (condition1) { 
    foo(big, do1); 
} else if (condition2) { 
    foo(big, do2); 
} else { 
    foo(big, do3); 
} 
+0

Sì, questa è una buona idea. Ma (mi dispiace!) Ho dimenticato di menzionare che nel mio codice 'do1',' do2' e 'do3' hanno diverse firme. – Charles

+0

@Charles Hmmm, in questo caso è necessaria un'altra soluzione ... –

+2

@Charles, poiché 'do1(); DO2(); do3(); 'nel post prendono tutti gli stessi argomenti (nessuno), questa risposta risponde bene a questo post. Magari pubblicane un altro con le tue restrizioni aggiuntive. – chux