Diese Frage ist zwar ziemlich alt, erfordert jedoch einige Benchmarks, da sie nicht den idiomatischsten oder den Weg erfordert, der in der geringsten Anzahl von Zeilen geschrieben werden kann, sondern den schnellsten Weg. Und es ist albern, diese Frage ohne tatsächliche Tests zu beantworten. Also habe ich vier Lösungen verglichen, memset vs. std :: fill vs. ZERO der Antwort von AnT mit einer Lösung, die ich mit AVX intrinsics erstellt habe.
Beachten Sie, dass diese Lösung nicht generisch ist, sondern nur mit Daten von 32 oder 64 Bit funktioniert. Bitte kommentieren Sie, wenn dieser Code etwas falsch macht.
#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;\
};\
}\
}
Ich werde nicht behaupten, dass dies die schnellste Methode ist, da ich kein Experte für Optimierung auf niedriger Ebene bin. Es ist vielmehr ein Beispiel für eine korrekte architekturabhängige Implementierung, die schneller als memset ist.
Nun zu den Ergebnissen. Ich habe die Leistung für Arrays der Größe 100 int und long long berechnet, sowohl statisch als auch dynamisch zugewiesen. Mit Ausnahme von msvc, das bei statischen Arrays eine Eliminierung des toten Codes durchgeführt hat, waren die Ergebnisse äußerst vergleichbar, sodass nur die Leistung dynamischer Arrays angezeigt wird. Zeitmarkierungen sind ms für 1 Million Iterationen unter Verwendung der niedrigpräzisen Uhrfunktion von time.h.
clang 3.8 (Mit dem clang-cl-Frontend Optimierungsflags = / 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 (Optimierungsflags: -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 (Optimierungsflags: / 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
Hier ist viel Interessantes los: llvm töten gcc, MSVCs typische fleckige Optimierungen (es führt eine beeindruckende Eliminierung von totem Code auf statischen Arrays durch und hat dann eine schreckliche Leistung beim Füllen). Obwohl meine Implementierung erheblich schneller ist, kann dies nur daran liegen, dass das Löschen von Bits viel weniger Aufwand verursacht als jede andere Einstellungsoperation.
Die Implementierung von Clang verdient mehr Aufmerksamkeit, da sie erheblich schneller ist. Einige zusätzliche Tests zeigen, dass sein Memset tatsächlich auf Null-Nicht-Null-Memsets für 400-Byte-Arrays spezialisiert ist, die viel langsamer sind (~ 220 ms) und mit gccs vergleichbar sind. Das Memsetting ungleich Null mit einem 800-Byte-Array macht jedoch keinen Geschwindigkeitsunterschied, weshalb in diesem Fall das Memset wahrscheinlich eine schlechtere Leistung aufweist als meine Implementierung - die Spezialisierung gilt nur für kleine Arrays, und der Cuttoff liegt bei etwa 800 Byte. Beachten Sie auch, dass gcc 'fill' und 'ZERO' nicht für memset optimiert sind (unter Berücksichtigung des generierten Codes). Gcc generiert einfach Code mit identischen Leistungsmerkmalen.
Fazit: memset ist nicht wirklich für diese Aufgabe optimiert, so wie es die Leute vorgeben würden (andernfalls hätten das memset von gcc und msvc und llvm die gleiche Leistung). Wenn es auf die Leistung ankommt, sollte memset keine endgültige Lösung sein, insbesondere für diese umständlichen mittelgroßen Arrays, da es nicht auf das Löschen von Bits spezialisiert ist und nicht besser von Hand optimiert wird, als es der Compiler alleine tun kann.
new
ist C ++ ...