この質問はかなり古いですが、最も慣用的な方法ではなく、最少数の行で記述できる方法で最速の方法を要求するため、いくつかのベンチマークが必要です。そして、実際のテストなしにその質問に答えることはばかげています。そこで、memsetとstd :: fillとAnTの答えのZEROと、AVX組み込み関数を使用して作成したソリューションの4つのソリューションを比較しました。
このソリューションは一般的なものではなく、32ビットまたは64ビットのデータでのみ機能することに注意してください。このコードが間違っている場合はコメントしてください。
#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;\
};\
}\
}
私は低レベルの最適化の専門家ではないので、これが最速の方法であるとは主張しません。むしろ、これはmemsetよりも高速な正しいアーキテクチャ依存の実装の例です。
次に、結果について説明します。静的および動的に割り当てられたサイズ100 intおよびlong long配列のパフォーマンスを計算しましたが、静的配列でデッドコードの除去を行ったmsvcを除いて、結果は非常に類似していたため、動的配列のパフォーマンスのみを示します。タイムマーキングは、time.hの低精度クロック関数を使用して、100万回の反復でmsです。
clang 3.8(clang-clフロントエンドを使用して、最適化フラグ= / 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(最適化フラグ:-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(最適化フラグ:/ 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
ここでは多くの興味深いことが行われています:llvm killing gcc、MSVCの典型的なむらのある最適化(静的配列で印象的なデッドコードの除去を行い、fillのパフォーマンスがひどい)。私の実装は大幅に高速ですが、これは、ビットのクリアが他のどの設定操作よりもオーバーヘッドがはるかに少ないことを認識しているためである可能性があります。
Clangの実装は、大幅に高速であるため、より詳細に検討するメリットがあります。いくつかの追加のテストは、そのmemsetが実際にゼロに特化していることを示しています-400バイト配列の非ゼロmemsetsははるかに遅く(〜220ms)、gccに匹敵します。ただし、800バイトの配列を使用したゼロ以外のmemsettingは速度の違いをもたらさないため、おそらくその場合、それらのmemsetは私の実装よりもパフォーマンスが悪いのです-特殊化は小さな配列でのみ行われ、カットオフは約800バイトです。また、gccの「fill」と「ZERO」はmemsetに最適化されていない(生成されたコードを見る)ことに注意してください。gccは、同じパフォーマンス特性を持つコードを生成するだけです。
結論:memsetはこのタスクに対して実際には最適化されておらず、人々はそれをそうするふりをします(そうでなければ、gccとmsvcとllvmのmemsetは同じパフォーマンスになります)。パフォーマンスが重要な場合、特にこれらの厄介な中規模の配列の場合、memsetは最終的なソリューションであってはなりません。これは、ビットクリアに特化しておらず、コンパイラーが単独で実行できるよりも手で最適化されていないためです。
new
される C ++ ...