Nel mio codice programma ci sono vari oggetti piuttosto piccoli che vanno da un byte o da 2 fino a circa 16. E.g. Vector2 (2 * T), Vector3 (3 * T), Vector4 (4 * T), ColourI32 (4), LightValue16 (2), Tile (2), ecc. (Dimensioni in byte tra parentesi).Prestazioni oggetti piccoli C++
Stava facendo un po 'di profiling (basato su campioni) che mi ha portato ad alcune funzioni più lente del previsto, ad es.
//4 bits per channel natural light and artificial RGB
class LightValue16
{
...
explicit LightValue16(uint16_t value);
LightValue16(const LightValueF &);
LightValue16(int r, int g, int b, int natural);
int natural()const;
void natural(int v);
int artificialRed()const;
...
uint16_t data;
};
...
LightValue16 World::getLight(const Vector3I &pos)
{ ... }
Questa funzione esegue alcuni calcoli di ricercare il valore tramite una coppia di matrici, con alcuni valori predefiniti per sopra la parte popolata del mondo. I contenuti sono ben adattati e osservando l'aspetto del disassemblaggio quanto di meglio si può ottenere. Con circa 100 istruzioni. Tuttavia una cosa spiccava, su tutti i siti di ritorno è stato attuato con qualcosa di simile:
mov eax, dword pyt [ebp + 8]
mov cx, word ptr[ecx + edx * 2] ; or say mov ecx, Fh
mov word ptr [eax], cx
pop ebp
ret 10h
Per x64 ho visto più o meno la stessa cosa. Non ho controllato la mia build GCC, ma sospetto che faccia più o meno la stessa cosa.
Ho fatto un po 'di sperimentazione e ho trovato usando un tipo di ritorno uint16_t. In effetti, la funzione World :: getLight si è in linea (sembravano praticamente le stesse 80 istruzioni di base o così, nessun cheat con condizionali/cicli diversi) e l'utilizzo totale della CPU per la funzione esterna che stavo investigando per passare da 16,87 Da% a 14.04% Mentre posso farlo basandomi caso per caso (insieme a provare la forza di cose in linea, suppongo), ci sono dei modi pratici per evitare problemi di questo tipo per cominciare? Forse anche ottenere un paio di% più veloce attraverso l'intero codice?
Il meglio che riesco a pensare solo ora è quello di usare solo i tipi primitivi in questi casi (< 4 o forse 8 byte oggetti) e spostare tutti gli elementi del membro corrente in funzioni non membro, quindi più come fatto in C , solo con namespace.
Pensando a questo credo che ci sia spesso un costo per cose come "t foo (const Vector3f & p)" over "t foo (float x, float y, z galleggiante)"? E se è così, su un programma che usa estensivamente il const &, potrebbe aggiungere una differenza significativa?
bene , la differenza nel caso dichiarato è che si restituisce un oggetto con tutto il sovraccarico associato mentre si restituisce un int unsigned a 16 bit. Dato che per il primo caso, devi copiare l'intero oggetto piuttosto che solo l'int, mi aspetto che consumi un po 'più di tempo CPU anche quando RVO entra in gioco. –
L'allocazione dell'oggetto in stack anziché heap può influire sulle prestazioni in questa situazione? –
Timo: perché l'oggetto completo richiede più di 2 byte di memoria? Il compilatore non dovrebbe mettere un vtable in là, penserei. –