1. Поиграй с длиной куска для заполнения. 16,32,64 бита за раз. Что-то даст профит по сравнению с остальным. НЕ по байту-это точно.
2. Поищи сторониие реализации типа того же memset от Intel
stream
> Зачем делать buf[k] = buf[k-1]? Какой тут профит, кроме лишнего чтения из
> памяти.
Команда movsd работает быстрее, чем stosd.
Лишние чтения во время интенсивной записи могут помочь, если кусок не в кеше. Они кешируют кусок. А запись этого не делает.
kas
> какие твои доказательства? ты мерял, или так, языком почесать?
Напиши superpuper_memzero(.....) , чтобы работало в тыщщу раз быстрее.
innuendo
> сравни memset и заполнение по mmx\sse
Сам сравни.. создай новый проект и ставни...
Делать нех больше как хнёй страдать.
memset по идее уже оптимизирован под максимально быструю работу. Его и использовать.
zlos
> memset по идее уже оптимизирован под максимально быструю работу. Его и
> использовать.
Причем интеловский мемсет (___intel_VEC_memzero) оптимизирован под разные процы одновременно. Вот например кусок из него:
.text:004019A8 test ___intel_cpu_indicator, 400h .text:004019B2 jnz loc_401B00 .text:004019B8 test ___intel_cpu_indicator, 0FFFFFE00h .text:004019C2 jnz loc_4019F0 .text:004019C8 test ___intel_cpu_indicator, 0FFFFFF80h .text:004019D2 jnz loc_401B00 .text:004019D8 test ___intel_cpu_indicator, 0FFFFFFFFh .text:004019E2 jnz loc_401B20 .text:004019E8 call ___intel_cpu_indicator_init
И один из этих переходов в зависимости от модели CPU содержит:
.text:00401A20 movdqa oword ptr [edi], xmm0 .text:00401A24 movdqa oword ptr [edi+10h], xmm0 .text:00401A29 movdqa oword ptr [edi+20h], xmm0 .text:00401A2E movdqa oword ptr [edi+30h], xmm0 .text:00401A33 movdqa oword ptr [edi+40h], xmm0 .text:00401A38 movdqa oword ptr [edi+50h], xmm0 .text:00401A3D movdqa oword ptr [edi+60h], xmm0 .text:00401A42 movdqa oword ptr [edi+70h], xmm0 .text:00401A47 lea edi, [edi+80h] .text:00401A4D dec ecx .text:00401A4E jnz short loc_401A20
Интел компилятор просто ухахатывается с потуг .L провелосипедить в нулевом посте и смотрит на остальных как сами знаете на что.
RtlFillMemory ^_^
Alexander K
> RtlFillMemory ^_^
И получи максимально тупой вариант:
http://pastebin.com/enea3Trh
entryway
По скорости тоже самое, что и memset, и ручное задание каждого байта (не на асме).
Простейше-тупейший memset который я всегда юзаю, работает быстрее орегинала в 4*num_cpu_cores раз =)
void _memset(void *data, int ch, size_t len) { int *ptr = ( int*)data; #pragma omp parallel for for( size_t i = 0; i < len; i++) ptr[i] = ch; }
OpenDX
Твой мемсет (без прагмы омп) у меня выдаёт 0.017-0.018 мс, против 0.012 мс RtlFillMemory на одних и тех же данных.
Alexander K
> По скорости тоже самое, что и memset
Компиляторы бывают разные. Не у всех memset это аналог (или тоже самое, но по 4 байта):
while (count--) { *( char *)dst = ( char)val; dst = ( char *)dst + 1; }
Хотя я и не уверен, что весь этот еханснутый оверхед как-то заметно помогает.
Alexander K
Ну вот, практически догнал Micro$, а по сравнению с их версией memset, мой код на выставку тока xD
Вот их memset
EXTERN_C void * __cdecl memset(void *d, int v, size_t c) { if ( ( ( ( ADDRESS) d) | c) & ( sizeof( UINT) - 1)) { BYTE *pD = ( BYTE *) d; BYTE *pE = ( BYTE *) ( ( ( ADDRESS) d) + c); while ( pD != pE) *( pD++) = ( BYTE) v; } else { UINT *pD = ( UINT *) d; UINT *pE = ( UINT *) ( BYTE *) ( ( ( ADDRESS) d) + c); UINT uv; uv = ( ( UINT) ( v & 0xff)) | ( ( ( UINT) ( v & 0xff)) << 8); /* Our processors are at least 32 bits */ uv |= uv << 16; #if ( _UINTSIZE == 64) /* They might be 64 bits */ uv |= uv << 32; #endif while ( pD != pE) *( pD++) = uv; } return d; }
А вот еще какой-то мемсет из интернета на Си:
void * memset(dst0, c0, length) void *dst0; register int c0; register size_t length; #endif { register size_t t; register u_int c; register u_char *dst; dst = dst0; /* * If not enough words, just fill bytes. A length >= 2 words * guarantees that at least one of them is `complete' after * any necessary alignment. For instance: * * |-----------|-----------|-----------| * |00|01|02|03|04|05|06|07|08|09|0A|00| * ^---------------------^ * dst dst+length-1 * * but we use a minimum of 3 here since the overhead of the code * to do word writes is substantial. */ if ( length < 3 * wsize) { while ( length != 0) { *dst++ = VAL; --length; } RETURN; } #ifndef BZERO if ( ( c = ( u_char)c0) != 0) { /* Fill the word. */ c = ( c << 8) | c; /* u_int is 16 bits. */ #if UINT_MAX > 0xffff c = ( c << 16) | c; /* u_int is 32 bits. */ #endif #if UINT_MAX > 0xffffffff c = ( c << 32) | c; /* u_int is 64 bits. */ #endif } #endif /* Align destination by filling in bytes. */ if ( ( t = ( int)dst & wmask) != 0) { t = wsize - t; length -= t; do { *dst++ = VAL; } while ( --t != 0); } /* Fill words. Length was >= 2*words so we know t >= 1 here. */ t = length / wsize; do { *( u_int *)dst = WIDEVAL; dst += wsize; } while ( --t != 0); /* Mop up trailing bytes, if any. */ t = length & wmask; if ( t != 0) do { *dst++ = VAL; } while ( --t != 0); RETURN; }
entryway
> while (count--) { *(char *)dst = (char)val; dst = (char *)dst + 1; }
0.012 мс.
P.S. компилятор MSVC++ или как он там называется, короче Visual Studio 2008.
OpenDX
> uv = ((UINT) (v & 0xff)) | (((UINT) (v & 0xff)) << 8);
Это в микрософте так пишут v & 0xffff?
OpenDX
> & (sizeof(UINT) - 1)
> #if (_UINTSIZE == 64)
Это 2 строчки писали 2 разных человека?
Alexander K
> RtlFillMemory
Это же rep stosd?
TarasB
> > RtlFillMemory
>
> Это же rep stosd?
Не знаю, не проверял. Вроде как это тот же самый memset.
Тема в архиве.