这个问题虽然比较老,但是却需要一些基准测试,因为它要求的不是最惯用的方式,也不是可以用最少的行数编写的方法,而是最快的方法。在没有实际测试的情况下回答这个问题是很愚蠢的。因此,我比较了四种解决方案,即AnT答案的memset与std :: fill与ZERO与我使用AVX内部函数制作的解决方案。
请注意,此解决方案不是通用的,它仅适用于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的低精度时钟功能,时间标记为毫秒,表示一百万次迭代。
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杀死了gcc,这是MSVC的典型斑点优化(它在静态数组上完成了令人印象深刻的死代码消除,然后具有糟糕的填充性能)。尽管我的实现明显更快,但这可能仅是因为它认识到位清除的开销比任何其他设置操作要少得多。
Clang的实现值得关注,因为它的速度明显更快。一些额外的测试表明,它的内存集实际上专用于零-400字节数组的非零内存集要慢得多(〜220ms),与gcc相当。但是,具有800字节数组的非零内存设置不会造成速度差异,这可能就是为什么在这种情况下,其内存集的性能比我的实现差的原因-专业化仅适用于小型数组,截止时间恰好在800字节左右。还要注意,gcc的“ fill”和“ ZERO”没有针对内存集进行优化(查看生成的代码),gcc只是生成具有相同性能特征的代码。
结论:memset并没有像人们想象的那样针对此任务进行真正的优化(否则gcc和msvc以及llvm的memset具有相同的性能)。如果性能很重要,那么memset并不是最终的解决方案,尤其是对于这些笨拙的中型数组,因为它不是专门用于位清除的,而且它的手动优化也没有编译器自己能做的更好。
new
是 C ++ ...