若要设置一块内存为指定值,最简单莫过于memset了,然而它要求pattern是一个字节,如果想设置一个宽点的类型,例如整型,那么memset基本就无法发挥功效,除非设置的是0或者-1或者其它值能满足所有字节一样。
下面提供几个方法,并大致比较一下:
1> 普通的for循环,一次设置数组各个元素为指定值
2> 滚动拷贝,1变2,2变4,4变8,越来越多……
3> Duff's Device, 达夫设备,是一个叫Duff的人发明的,将循环的比较次数降为1/8,将switch和while糅合在一起。
注意:所有函数都没有做参数检查,要求输入count必须大于0,否则会出错!
代码如下:
#include <stdio.h> #include <memory.h> #include <intrin.h> #pragma intrinsic __rdtsc int A[1000000]; float B[1000000]; double C[1000000]; template <typename T> void memsetSimple( T* begin, int count, const T& value ) { T* end = begin + count; while( begin != end ) *begin++ = value; } template <typename T> void memsetPower( T* begin, int count, const T& value ) { int size = 1, mid = count / 2; *begin = value; while( size <= mid ) { memcpy( begin + size, begin, sizeof(T) * size ); size *= 2; } memcpy( begin + size, begin, sizeof(T) * (count - size) ); } template <typename T> void memsetDuff( T* begin, int count, const T& value ) { T* end = begin + count; switch( count & 7 ) { case 0:while( begin != end ){ *begin++ = value; case 7: *begin++ = value; case 6: *begin++ = value; case 5: *begin++ = value; case 4: *begin++ = value; case 3: *begin++ = value; case 2: *begin++ = value; case 1: *begin++ = value;} } } #define TEST( X, Y, Z ) / t0 = __rdtsc();/ X( Y, sizes[i], Z );/ t1 = __rdtsc();/ printf("%-12lld/t", t1 - t0 ) int main() { getchar(); printf("DataTypeSize/tmemsetSimple/tmemsetPower/tmemsetDuff/n"); int sizes[] = {100, 1000, 10000, 100000, 1000000}; int i; __int64 t0, t1; for( i = 0; i < sizeof(sizes) / sizeof(int); i++ ) { printf("int %8d/t", sizes[i] ); TEST( memsetSimple, A, 1025 ); TEST( memsetPower, A, 1025 ); TEST( memsetDuff, A, 1025 ); printf("/n"); } for( i = 0; i < sizeof(sizes) / sizeof(int); i++ ) { printf("flt %8d/t", sizes[i] ); TEST( memsetSimple, B, 1025.f ); TEST( memsetPower, B, 1025.f ); TEST( memsetDuff, B, 1025.f ); printf("/n"); } for( i = 0; i < sizeof(sizes) / sizeof(int); i++ ) { printf("dbl %8d/t", sizes[i] ); TEST( memsetSimple, C, 1025. ); TEST( memsetPower, C, 1025. ); TEST( memsetDuff, C, 1025. ); printf("/n"); } return 0; }
开了/O2优化,结果如下:
start DataTypeSize memsetSimple memsetPower memsetDuff int 100 690 10185 360 int 1000 15675 16425 1890 int 10000 74280 12855 16995 int 100000 731040 187515 170610 int 1000000 9857580 7229400 6007875 flt 100 1950 5355 1335 flt 1000 29040 5310 2775 flt 10000 94365 12255 18300 flt 100000 887940 262050 197910 flt 1000000 8499810 7190445 9663630 dbl 100 1635 6195 1755 dbl 1000 84836 5970 3975 dbl 10000 171585 41640 27240 dbl 100000 1617465 879840 610665 dbl 1000000 27381930 16337850 14561535
分析如下:
memcpy是被高度优化的(memsetPower中被调用),据说是用汇编写的,所以非常快,开不开/O2影响不大,而普通循环的影响很大,速度直逼memsetPower。而Duff's Device表现得非常令人吃惊,基本都是最快的。
当然我的环境可能有局限性,欢迎大家测试代码,找到最适合自己的方法。