Ho una classe come questa:Struttura di array e array di strutture - differenza di prestazioni
//Array of Structures
class Unit
{
public:
float v;
float u;
//And similarly many other variables of float type, upto 10-12 of them.
void update()
{
v+=u;
v=v*i*t;
//And many other equations
}
};
Creo un array di oggetti di tipo Unit. E chiama l'aggiornamento su di loro.
int NUM_UNITS = 10000;
void ProcessUpdate()
{
Unit *units = new Unit[NUM_UNITS];
for(int i = 0; i < NUM_UNITS; i++)
{
units[i].update();
}
}
Al fine di accelerare le cose, e possibilmente autovectorize ciclo, i convertiti AoS strutturare degli array.
//Structure of Arrays:
class Unit
{
public:
Unit(int NUM_UNITS)
{
v = new float[NUM_UNITS];
}
float *v;
float *u;
//Mnay other variables
void update()
{
for(int i = 0; i < NUM_UNITS; i++)
{
v[i]+=u[i];
//Many other equations
}
}
};
Quando il ciclo non riesce ad autotetettizzare, sto ottenendo una prestazione pessima per la struttura degli array. Per 50 unità, l'aggiornamento di SoA è leggermente più veloce di AoS. Ma da 100 unità in poi, SoA è più lento di AoS. A 300 unità, SoA è quasi il doppio peggiore. A 100K unità, SoA è 4x più lento di AoS. Mentre la cache potrebbe essere un problema per SoA, non mi aspettavo che la differenza di prestazioni fosse così alta. Il profiling su cachegrind mostra un numero simile di errori per entrambi gli approcci. La dimensione di un oggetto Unit è 48 byte. La cache L1 è 256K, L2 è 1MB e L3 è 8MB. Cosa mi manca qui? È davvero un problema di cache?
Modifica: Sto utilizzando gcc 4.5.2. Le opzioni del compilatore sono -o3 -msse4 -ftree-vectorize.
Ho fatto un altro esperimento in SoA. Invece di allocare dinamicamente gli array, ho allocato "v" e "u" in fase di compilazione. Quando ci sono unità da 100 K, ciò fornisce una prestazione che è 10 volte più veloce della SoA con array allocati dinamicamente. Cosa sta succedendo qui? Perché c'è una tale differenza di prestazioni tra memoria statica e memoria allocata dinamicamente?
Quali opzioni del compilatore utilizzate per creare questo? –
Non sono sicuro se questo farebbe la differenza, ma [std :: valarray] (http://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a00738.html) può (o non può) Aiuto. È progettato per eseguire operazioni matematiche sull'intero array (sintassi più pulita per tale), ma suppongo che gli implementatori abbiano sovraccarichi speciali per cercare di ottimizzare tali operazioni e realizzare allocazioni intelligenti, ecc. Quando possibile. Potrebbe non essere affatto d'aiuto, ma potrebbe valere la pena dare un'occhiata. – pstrjds
Cosa succede quando azzeri il set di dati prima di eseguire il benchmark? La virgola mobile non inizializzata ha un'alta probabilità di essere [denormalizzata] (http://stackoverflow.com/a/9314926/922184). Non vuoi che rovini il tuo benchmark. – Mysticial