Questa domanda, sebbene piuttosto vecchia, necessita di alcuni benchmark, in quanto non richiede il modo più idiomatico, o il modo che può essere scritto nel minor numero di righe, ma il modo più veloce . Ed è sciocco rispondere a questa domanda senza alcuni test effettivi. Quindi ho confrontato quattro soluzioni, memset vs std :: fill vs ZERO della risposta di AnT rispetto a una soluzione che ho realizzato utilizzando AVX intrinsics.
Si noti che questa soluzione non è generica, funziona solo su dati di 32 o 64 bit. Si prega di commentare se questo codice sta facendo qualcosa di sbagliato.
#include<immintrin.h>
#define intrin_ZERO(a,n){\
size_t x = 0;\
const size_t inc = 32 / sizeof(*(a));/*size of 256 bit register over size of variable*/\
for (;x < n-inc;x+=inc)\
_mm256_storeu_ps((float *)((a)+x),_mm256_setzero_ps());\
if(4 == sizeof(*(a))){\
switch(n-x){\
case 3:\
(a)[x] = 0;x++;\
case 2:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
else if(8 == sizeof(*(a))){\
switch(n-x){\
case 7:\
(a)[x] = 0;x++;\
case 6:\
(a)[x] = 0;x++;\
case 5:\
(a)[x] = 0;x++;\
case 4:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 3:\
(a)[x] = 0;x++;\
case 2:\
((long long *)(a))[x] = 0;break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
}
Non affermerò che questo sia il metodo più veloce, poiché non sono un esperto di ottimizzazione di basso livello. Piuttosto è un esempio di una corretta implementazione dipendente dall'architettura che è più veloce di memset.
Ora, sui risultati. Ho calcolato le prestazioni per array di dimensioni 100 int e long long, allocati sia staticamente che dinamicamente, ma con l'eccezione di msvc, che ha eseguito un'eliminazione del codice morto su array statici, i risultati erano estremamente comparabili, quindi mostrerò solo le prestazioni dell'array dinamico. I contrassegni del tempo sono ms per 1 milione di iterazioni, utilizzando la funzione di orologio a bassa precisione di time.h.
clang 3.8 (Utilizzando il frontend clang-cl, flag di ottimizzazione = / OX / arch: AVX / Oi / Ot)
int:
memset: 99
fill: 97
ZERO: 98
intrin_ZERO: 90
long long:
memset: 285
fill: 286
ZERO: 285
intrin_ZERO: 188
gcc 5.1.0 (flag di ottimizzazione: -O3 -march = native -mtune = native -mavx):
int:
memset: 268
fill: 268
ZERO: 268
intrin_ZERO: 91
long long:
memset: 402
fill: 399
ZERO: 400
intrin_ZERO: 185
msvc 2015 (flag di ottimizzazione: / OX / arch: AVX / Oi / Ot):
int
memset: 196
fill: 613
ZERO: 221
intrin_ZERO: 95
long long:
memset: 273
fill: 559
ZERO: 376
intrin_ZERO: 188
C'è molto di interessante qui: llvm killing gcc, le tipiche ottimizzazioni spotty di MSVC (esegue un'impressionante eliminazione del codice morto su array statici e quindi ha prestazioni terribili per il riempimento). Sebbene la mia implementazione sia significativamente più veloce, ciò potrebbe essere dovuto solo al fatto che riconosce che la cancellazione dei bit ha un sovraccarico molto inferiore rispetto a qualsiasi altra operazione di impostazione.
L'implementazione di Clang merita un'analisi più approfondita, poiché è significativamente più veloce. Alcuni test aggiuntivi mostrano che il suo memset è in realtà specializzato per zero - i memset diversi da zero per array da 400 byte sono molto più lenti (~ 220ms) e sono paragonabili a quelli di gcc. Tuttavia, il memset diverso da zero con un array di 800 byte non fa differenza di velocità, motivo per cui in quel caso il loro memset ha prestazioni peggiori della mia implementazione: la specializzazione è solo per piccoli array e il cuttoff è di circa 800 byte. Si noti inoltre che gcc 'fill' e 'ZERO' non si ottimizzano per memset (guardando il codice generato), gcc sta semplicemente generando codice con caratteristiche di prestazioni identiche.
Conclusione: memset non è realmente ottimizzato per questo compito così come le persone vorrebbero fingere che lo sia (altrimenti gcc, msvc e memset di llvm avrebbero le stesse prestazioni). Se le prestazioni contano, memset non dovrebbe essere una soluzione definitiva, specialmente per questi scomodi array di medie dimensioni, perché non è specializzato per la cancellazione dei bit e non è ottimizzato a mano meglio di quanto il compilatore possa fare da solo.
new
è C ++ ...