Bu soru, oldukça eski olmasına rağmen, en deyimsel yolu ya da en az sayıda satırla yazılabilecek yolu değil, en hızlı yolu istediği için bazı ölçütlere ihtiyaç duyar . Ve bu soruyu gerçek bir test yapmadan cevaplamak aptalca. Bu yüzden, dört çözümü karşılaştırdım, memset ile std :: fill ve SIFIR'ın AnT cevabı ile AVX intrinsics kullanarak yaptığım bir çözüm.
Bu çözümün genel olmadığını, yalnızca 32 veya 64 bitlik veriler üzerinde çalıştığını unutmayın. Bu kod yanlış bir şey yapıyorsa lütfen yorum yapın.
#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;\
};\
}\
}
Düşük seviye optimizasyon uzmanı olmadığım için bunun en hızlı yöntem olduğunu iddia etmeyeceğim. Aksine, memset'ten daha hızlı olan doğru bir mimariye bağlı uygulama örneğidir.
Şimdi sonuçlara bakalım. Boyut 100 int ve uzun uzun diziler için performansı hem statik hem de dinamik olarak tahsis edilmiş olarak hesapladım, ancak statik dizilerde ölü kodu ortadan kaldıran msvc dışında, sonuçlar son derece karşılaştırılabilirdi, bu nedenle yalnızca dinamik dizi performansını göstereceğim. Zaman işaretleri, time.h'nin düşük hassasiyetli saat işlevi kullanılarak 1 milyon yineleme için ms'dir.
clang 3.8 (clang-cl ön ucunu kullanarak, optimizasyon bayrakları = / 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 (optimizasyon işaretleri: -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 (optimizasyon işaretleri: / 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
Burada çok ilginç şeyler oluyor: llvm, MSVC'nin tipik sivilceli optimizasyonları olan gcc'yi öldürüyor (statik dizilerde etkileyici bir ölü kod ortadan kaldırıyor ve ardından doldurma için korkunç bir performansa sahip). Uygulamam önemli ölçüde daha hızlı olsa da, bunun nedeni bit temizlemenin diğer ayar işlemlerinden çok daha az ek yüke sahip olduğunu fark etmesi olabilir.
Clang'ın uygulaması, önemli ölçüde daha hızlı olduğu için daha fazla bakmayı hak ediyor. Bazı ek testler, memset'in aslında 400 baytlık dizi için sıfır olmayan - sıfır olmayan memset'ler için özelleştirilmiş olduğunu, çok daha yavaş (~ 220ms) ve gcc'lerle karşılaştırılabilir olduğunu gösteriyor. Bununla birlikte, 800 baytlık bir diziyle sıfırdan farklı memsetting hız farkı yaratmaz, bu nedenle muhtemelen bu durumda, onların memset'leri benim uygulamamdan daha kötü performansa sahiptir - uzmanlık yalnızca küçük diziler içindir ve kesme değeri yaklaşık 800 bayttır. Ayrıca, gcc 'doldurma' ve 'SIFIR'ın memset için optimizasyon yapmadığını (üretilen koda bakarak), gcc'nin aynı performans özelliklerine sahip kod ürettiğini unutmayın.
Sonuç: memset, bu görev için gerçekten optimize edilmemiştir ve insanların öyle olduğunu düşündüğü gibi (aksi takdirde gcc ve msvc ve llvm'nin memset'i aynı performansa sahip olacaktır). Performans önemliyse, memset, özellikle bu garip orta büyüklükteki diziler için nihai bir çözüm olmamalıdır, çünkü bit temizleme için özel değildir ve derleyicinin kendi başına yapabileceğinden daha iyi elle optimize edilmemiştir.
new
bir C ++ ...