2014-11-20 9 views
5

Innanzitutto per rendere più leggibile il codice C++; Sto programmando compilatore, e ho dato:È possibile utilizzare char [] come parametri, return ed ecc eventuali problemi di prestazioni?

var swap = (int x, y) => { //Assign method that returns two ints, and gets two ints as parameter to variable named swap. 
    var NewX = y 
    var NewY = x 
} 
var increment = (int x) => { 
    var Result = x + 1 
} 

NOTA: Le funzioni restituiscono qualsiasi variabile che è prima lettera è maiuscola. swap può essere utilizzato come ... = swap(x, y).NewX, ma increment può essere utilizzato come solo ... = increment(x).

Dopo un po 'di ottimizzazione ha generato: (Made swap e increment effettiva funzione invece di variabili, ed ottimizzate pila swap s')

template<int BytesCount> struct rawdata { //struct from some header 
    char _[ BytesCount ]; 
    inline char &operator[] (int index) { 
     return _[ index ]; 
    } 
}; 

//... 

rawdata<8> generatedfunction0(rawdata<8> p) { // var swap = (int x, y) => { 
    return{ p[ 4 ], p[ 5 ], p[ 6 ], p[ 7 ], p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] }; 
} 
rawdata<4> generatedfunction1(rawdata<4> p) { // var increment = (int x) => { 
    rawdata<4> r = { p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] }; 
    ++*((int*)&r[ 0 ]); 
    return r; 
} 

Sono quasi sicuro che non lo farà ++*((int*)&r[ 0 ]); indirezione inutile, ma come circa return{ p[ 4 ], p[ 5 ], p[ 6 ], p[ 7 ], p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] };? C'è qualche fonte che garantisce che lo ottimizzerà come se fossero due interi che vengono messi in array invece di 8 o più istruzioni che mettono byte per byte? Non sto parlando solo di questo caso particolare, ma di qualcosa di simile.

Se dipende, quindi sto utilizzando GCC per compilare il codice generato.

+0

Esistono pochissime garanzie in merito al codice generato da un compilatore dopo l'ottimizzazione. In questo caso, no, non c'è alcuna garanzia su come riempirà l'array di memoria, e sarei sorpreso se avesse fatto qualcosa di meglio di un riempimento byte per byte qui. –

+0

@JasonR In questo caso particolare lo ha ottimizzato come se conoscesse il risultato. (Ho provato a fare 'printf', ecc.) Se vuoi vedere un esempio simile [dai un'occhiata] (http://stackoverflow.com/questions/26378197/è-il-componente-per-per-optimizzare-spaghetti -codice). – LyingOnTheSky

risposta

4

Sì, può danneggiare le prestazioni, ma non sempre. Il problema è nell'accesso esplicito dei singoli byte.

Un compilatore "intelligente" riconoscerebbe l'accesso alla memoria contigua e tenta di ottimizzarlo. Tuttavia per qualche ragione non funziona affatto con gcc, clang o icc (non ho provato msvc). C'è ancora spazio per miglioramenti per gli ottimizzatori del compilatore, e IIRC lo standard non richiede alcuna ottimizzazione.

Swap:

Quindi, cerchiamo di elaborare ogni funzione, a partire da swap. Ho aggiunto altre 2 funzioni per completezza, vedere dopo il frammento di codice:

#include <stdint.h> 

rawdata<8> genSWAP(rawdata<8> p) 
{ 
    return { p[ 4 ], p[ 5 ], p[ 6 ], p[ 7 ], p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] }; 
} 

rawdata<8> genSWAPvar(rawdata<8> p) 
{ 
    return { p._[ 4 ], p._[ 5 ], p._[ 6 ], p._[ 7 ], p._[ 0 ], p._[ 1 ], p._[ 2 ], p._[ 3 ] }; 
} 

rawdata<8> genSWAP32(rawdata<8> p) 
{ 
    rawdata<8> res = p; 
    uint32_t* a = (uint32_t*)&res[0]; 
    uint32_t* b = (uint32_t*)&res[4]; 
    uint32_t tmp = *a; 
    *a = *b; 
    *b = tmp; 
    return res; 
} 
  • genSWAP: la vostra funzione
  • genSWAPvar: uguali ai suoi, ma senza usare la operator[] si è definito
  • genSWAP32: esplicitamente imballaggio i tuoi byte 32 bit per 32 bit

È possibile visualizzare the generated asm here.

genSWAP e genSWAPvar non sono diversi, il che significa che il sovraccarico operator[] è appena ottimizzato. Tuttavia, ciascun byte è accessibile individualmente nella memoria e anche elaborato individualmente. Questo non va bene poiché su architetture a 32 bit il processore carica 4 byte contemporaneamente dalla memoria (8 per architetture a 64 bit). Quindi in breve gcc/clang/icc stanno emettendo istruzioni per contrastare le reali possibilità delle architetture a 32 bit ...

genSWAP32 è molto più efficiente, facendo il numero minimo di carichi (per 32 bit) e usando correttamente i registri (nota per architetture a 64 bit dovrebbe essere possibile eseguire solo un carico invece di 2).

E infine, some real measures: su Ideone genSWAP32 è quasi 4x più veloce (il che ha senso, perché ha 2 carichi anziché 8 e meno istruzioni di calcolo).

Incremento:

Stesso qui, la funzione vs "ottimizzata" uno:

rawdata<4> genINC(rawdata<4> p) 
{ 
    rawdata<4> r = { p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] }; 
    ++*((int*)&r[ 0 ]); 
    return r; 
} 

rawdata<4> genINC32(rawdata<4> p) 
{ 
    rawdata<4> res = p; 
    uint32_t* a = (uint32_t*)&res[0]; 
    ++*a; 
    return res; 
} 

Il generated asm is here.

Per clang e icc, il killer non è l'incremento ma l'inizializzazione, in cui si accede singolarmente a ciascun byte. gcc e icc probabilmente lo fanno di default perché l'ordine dei byte potrebbe essere diverso da quello 0 1 2 3. Sorprendentemente, clang riconosce che l'ordine dei byte e lo ottimizza correttamente - nessuna differenza di perf.

Poi succede qualcosa di interessante: la funzione is slower on gccgenINC32, ma più veloce su msvc (* non vedo un pulsante permalink su rise4fun, così go there e incolla il codice testato su Ideone). Senza vedere l'assemblatore generato da msvc e confrontandolo, non ho alcuna spiegazione.

In conclusione, mentre è possibile avere un compilatore per ottimizzare correttamente tutto il codice, non fare affidamento su quello ora, quindi non accedere a ogni byte singolarmente se non necessario.

+0

Alla fine, rispondendo al tuo "In conclusione". Non posso usare 'int's ed ecc. Perché il livello prima che la generazione del codice non mi permetta di indovinare quali sono le dimensioni dell'oggetto che sta passando. (Forse un cattivo design) Penso che applicherò qualche ottimizzazione al livello di generazione del codice per raggruppare i byte in 'int' ed ecc. Grazie per la tua ricerca, mi ha aiutato a trovare nuovi modi. – LyingOnTheSky

Problemi correlati