2009-11-12 19 views
10
void Send(int * to, const int* from, const int count) 
{ 
    int n = (count+7)/8; 
    switch(count%8) 
    { 
     case 0: do { *to++ = *from++; 
     case 7:  *to++ = *from++; 
     case 6:  *to++ = *from++; 
     case 5:  *to++ = *from++; 
     case 4:  *to++ = *from++; 
     case 3:  *to++ = *from++; 
     case 2:  *to++ = *from++; 
     case 1:  *to++ = *from++; 
     } while (--n>0); 
    } 
} 
+4

Come altri hanno detto, il dispositivo di Duff. Non lo implementerei se non dovessi farlo, troppo esoterico/offuscato. Preferisco il codice leggibile ;-) Sebbene, se racchiuso in una funzione come questa, con buoni commenti/documentazione, lo userei se non dovessi toccarlo. –

+0

Non avrei grossi problemi con l'uso del dispositivo di Duff dove appropriato. Si parla in modo approfondito e il commento più importante necessario sarebbe un URL di cui si parla pienamente. – Jon

+2

Wow: qualcuno si è davvero preso la briga di usare il dispositivo di Duff per l'ottimizzazione, ma non ha trasformato il modulo e la divisione in un turno ??? – Aaron

risposta

17

Questo è Duff's Device per la copia dei buffer di memoria.

+6

Le risposte di collegamento sono sbagliate! –

+6

@Seth perché le risposte ai collegamenti sono sbagliate? Non ho mai sentito parlare di Duff's Device in precedenza, e un link al suo articolo su Wikipedia è stato abbastanza bello da trovare nella risposta più votata. –

+4

Il contenuto collegato tende a scomparire nel tempo. Probabilmente non è una grande preoccupazione per Wikipedia, ma di solito è una buona idea copiare lo snippet pertinente nella tua risposta e aggiungere il link come riferimento. –

3

leggere su Duff's Device

+2

Si prega di non fornire risposte di collegamento –

7

Questa commistione di un'istruzione switch e un ciclo while si chiama "Dispositivo di Duff". È un modo per srotolare i loop, che era un'ottimizzazione spesso utilizzata in passato.

Quindi questo codice copia ancora il contenuto della memoria da un posto all'altro, ma potrebbe essere più efficiente. Attenzione, sulle architetture di oggi dovresti sempre misurarlo, perché con la localizzazione della cache e le CPU incredibilmente veloci il ciclo di srotolamento è spesso una cattiva idea. Dispositivo

4

Duff's device

In computer science, Duff è un optimizedimplementation di una copia seriale che utilizza una tecnica ampiamente applicata in assembly language per loop unwinding. La sua scoperta è accreditata allo Tom Duff nel novembre 1983, che all'epoca stava lavorando per Lucasfilm. È forse l'uso più drammatico di case label fall-through nel C programming language fino ad oggi. Duff non rivendica credito per scoprire il concetto di loop unrolling, proprio questa particolare espressione in C.

5

Questo è funzionalmente identico al codice di seguito:

for(int i=0;i<n;i++) 
{ 
    *to++=*from++; 
} 

La differenza è che il codice srotola il ciclo in modo che sia richiesta una sola iterazione del ciclo per ogni 8 numeri interi copiati. Poiché non vi sono interruzioni per nessuno dei casi , l'esecuzione passa dall'etichetta di ogni caso alla successiva.

Quando il conteggio% 8 == 0, 8 copie sono eseguite all'interno del ciclo per la prima iterazione

quando il contatore% 8 == 7, 7 copie vengono eseguite per la prima iterazione

e così via. Dopo la prima iterazione con% 8 copie, esattamente 8 copie avvengono per iterazione.

Svolgendo il ciclo in questo modo, l'overhead del loop viene significativamente ridotto. È importante notare l'ordine dei valori del caso (0,7,6,5,4,3,2,1) che si prestano ad essere tradotti in una tabella di salto dal compilatore.

aggiornamento

Un problema con il codice di esempio inviato da OP è che un valore di conteggio di 0 causerà 8 copie avvengano, potenzialmente un buffer overflow.

+2

La tua spiegazione sembra poco chiara. Se non sbaglio, l'interruttore serve solo a determinare il numero di assegnazioni srotolate da eseguire durante la prima iterazione (per compensare che la lunghezza del buffer potrebbe non essere equamente divisibile per 8). – UncleBens

+0

Questo è corretto. Scusa per la spiegazione nuvolosa. –

15

Questo è Duff's Device. È un metodo di loop di srotolamento che evita di dover aggiungere un ciclo di correzione secondario per gestire le volte in cui il numero di iterazioni del ciclo non è noto per essere un multiplo esatto del fattore di srotolamento.

Poiché la maggior parte delle risposte qui sembra essere generalmente positiva, parlerò apertamente.

Con questo codice un compilatore farà fatica ad applicare qualsiasi ottimizzazione al corpo del loop. Se hai appena scritto il codice come un semplice ciclo, un moderno compilatore dovrebbe essere in grado di gestire lo srotolamento per te. In questo modo si mantiene la leggibilità e le prestazioni e si spera che altre ottimizzazioni vengano applicate al corpo del loop.

L'articolo di Wikipedia a cui si fa riferimento da altri dice anche quando questo "modello" è stato rimosso dalle prestazioni del codice sorgente Xfree86 effettivamente migliorate.

Questo risultato è tipico della mano cieca che ottimizza qualsiasi codice che pensi possa averne bisogno. Impedisce al compilatore di svolgere correttamente il suo lavoro, rende il tuo codice meno leggibile e più incline a bug e in genere rallenta. Se stavate facendo le cose nel modo giusto in primo luogo, cioè scrivendo codice semplice, quindi creando profili per i colli di bottiglia, quindi ottimizzando, non avreste mai nemmeno pensato di usare qualcosa del genere. Non con una CPU e un compilatore moderni comunque.

Va bene a capirlo, ma sarei sorpreso se lo usassi mai davvero.

+0

+1 per questo bel commento sullo sfondo. –

+1

+1 per dare un'opinione corretta su quella cosa brutta e oscura. Tutti dovrebbero sapere perché * non * usarlo. –