бенч Код (Text): #include <stdio.h> #include <time.h> void main(){ char *b1, *b2; int i; unsigned clkb1, clkl1; time_t tb1, te1; unsigned clkb4, clkl4; time_t tb4, te4; b1 = (char*)malloc(10*1024*1024); b2 = (char*)malloc(10*1024*1024); __asm{ push esi push edi push ecx push edx } // by dword copying bench tb4 = time(0); __asm{ rdtsc mov clkl4,eax mov clkb4,edx } // 1.000x copy b1 --> b2 by dwords with format coversion //for( i=0; i<1000; i++){ __asm{ mov edx,1000 } test_loop_4: __asm{ mov esi,b1 mov edi,b2 mov ecx,10*1024*1024/4 } copy4_loop: __asm{ lodsd bswap eax stosd dec ecx jnz short copy4_loop } __asm{ dec edx jnz short test_loop_4 } //} __asm{ rdtsc sub eax,clkl4 sbb edx,clkb4 mov clkl4,eax mov clkb4,edx } te4 = time(0); // by byte copying bench tb1 = time(0); __asm{ rdtsc mov clkl1,eax mov clkb1,edx } // 1.000x copy b1 --> b2 by bytes //for( i=0; i<1000; i++){ __asm{ mov edx,1000 } test_loop_1: __asm{ mov esi,b1 mov edi,b2 mov ecx,10*1024*1024/4 } copy1_loop: __asm{ mov eax,[esi] shr eax,24 stosb ;-- mov eax,[esi] shr eax,16 and eax,0ffh stosb ;-- mov eax,[esi] shr eax,8 and eax,0ffh stosb ;-- lodsd and eax,0ffh stosb ;-- dec ecx jnz short copy1_loop } __asm{ dec edx jnz short test_loop_1 } //} __asm{ rdtsc sub eax,clkl1 sbb edx,clkb1 mov clkl1,eax mov clkb1,edx } te1 = time(0); __asm{ pop edx pop ecx pop edi pop esi } printf("1.000x copys b1[ 10meg ] --> b2[ 10meg ] \n" "---\n" "by dword with conversion between 'le' and 'be' forms takes \n" "\t0x%X:%X processor clocks or \n" "\t%.0f seconds\n" "---\n" "by byte with conversion between 'le' and 'be' as proposed takes \n" "\t0x%X:%X processor clocks or \n" "\t%.0f seconds", clkb4, clkl4, difftime(te4, tb4), clkb1, clkl1, difftime(te1, tb1) ); } выдает мне резулт неужели все эти сдвиги/энды так быстро работают?
Мое имхо что у тебя все основное время жреццо на эти lodsd/stosb (а все остальное мелочь), а если сделать по 8 или 16 байт блоки типа add esi,8 mov eax,[esi-8] mov ebx,[esi-4] ... bswap eax bswap ebx ... mov [edi-8],eax то будет другая картина..
А какой процессор? У меня коре 2 дуе. У тебя используется медленная инструкция lodsd/stosb. Медленная она по двум причинам первая это потому чото использует для чтения и записи байты. На которые тратятся по тику или 0.5 По этому если читать писать блоками по несколько байт DWord к примеру то экономим в скорости в 4 раза. Поэтому лучше через MMX или SSE 64 и 128бит читаются и пишуться за раз. Процессор за один такт может выполнять несколько не зависимых инструкций. Так что хорошим результатом будет 1 тик чтение и 1 запись так как зависимые инструкции и еще 0-1 на вычисления. lodsd/stosb вторая особенность это тормоза из за того что помимо сложений она выполняет увелечение счетчиков что неспариваются поэтому инструкция выполняется медленее. А эти вещи можно загнать в вычисления адресса которое может делаться паралельно. Остается учесть размеры данных и скорость интерфейса. И получить новый придел в 8*800=64 ГБайт/с.
без лодс/стос Код (Text): #include <stdio.h> #include <time.h> void main(){ char *b1, *b2; int i; unsigned clkb1, clkl1; time_t tb1, te1; unsigned clkb4, clkl4; time_t tb4, te4; b1 = (char*)malloc(10*1024*1024); b2 = (char*)malloc(10*1024*1024); __asm{ push esi push edi push ecx push edx } // by dword copying bench tb4 = time(0); __asm{ rdtsc mov clkl4,eax mov clkb4,edx } // 1.000x copy b1 --> b2 by dwords with format coversion //for( i=0; i<1000; i++){ __asm{ mov edx,1000 } test_loop_4: __asm{ mov esi,b1 mov edi,b2 mov ecx,10*1024*1024/4 } copy4_loop: __asm{ mov eax,[esi] bswap eax mov [edi],eax add esi,4 add edi,4 dec ecx jnz short copy4_loop } __asm{ dec edx jnz short test_loop_4 } //} __asm{ rdtsc sub eax,clkl4 sbb edx,clkb4 mov clkl4,eax mov clkb4,edx } te4 = time(0); // by byte copying bench tb1 = time(0); __asm{ rdtsc mov clkl1,eax mov clkb1,edx } // 1.000x copy b1 --> b2 by bytes //for( i=0; i<1000; i++){ __asm{ mov edx,1000 } test_loop_1: __asm{ mov esi,b1 mov edi,b2 mov ecx,10*1024*1024/4 } copy1_loop: __asm{ mov eax,[esi] shr eax,24 mov [edi],al inc edi ;-- mov eax,[esi] shr eax,16 and eax,0ffh mov [edi],al inc edi ;-- mov eax,[esi] shr eax,8 and eax,0ffh mov [edi],al inc edi ;-- mov eax,[esi] and eax,0ffh mov [edi],al inc edi ;-- add esi,4 dec ecx jnz short copy1_loop } __asm{ dec edx jnz short test_loop_1 } //} __asm{ rdtsc sub eax,clkl1 sbb edx,clkb1 mov clkl1,eax mov clkb1,edx } te1 = time(0); __asm{ pop edx pop ecx pop edi pop esi } printf("1.000x copys b1[ 10meg ] --> b2[ 10meg ] \n" "---\n" "by dword with conversion between 'le' and 'be' forms takes \n" "\t0x%X:%X processor clocks or \n" "\t%.0f seconds\n" "---\n" "by byte with with conversion between 'le' and 'be' as proposed takes \n" "\t0x%X:%X processor clocks or \n" "\t%.0f seconds", clkb4, clkl4, difftime(te4, tb4), clkb1, clkl1, difftime(te1, tb1) ); } еще меньше разницы. видать потому, что лодсы/стосы не спариваются нет, я конечно понимаю, что кэш выравнивает байты и дворды и что основную задержку вносит чтение/запись линеек кэша.. но всетаки я удивлен такой микроскопической разницей. ath 2000+, pc2100
У тебя получился не тест инструкций, а тест кеша/пропускной способности памяти. Похожий результат получал недавно тестируя сумму векторов на FPU vs SSE2. При размере векторов до 10000 (16-тибайтных структур) SSE2 рвал FPU в полтора-два раза, но при увеличении массивов разрыв стремительно сокращался и при 100000 разница была уже порядка 8 процентов. Потому что тест уперся в пропускную способность памяти.
aa_dav вот и я так думаю. гдето правда читал, что для доступа к кэшам тратятся лишние такты, но память видать очень сильнее перекрывает. кстати почему не тест инструкций? побочное наблюдение - при работе с большим объемом памяти даже подряд идущей, что 2 команды, что десяток.
Вот, кстати, при обсуждении того же теста FPU vs SSE2 один человек высказал эмпирический принцип, который вроде как в современных x86 имеет место соблюдаться - что на 1 инструкцию работающую с памятью должно быть не менее 5 инструкций, работающих с регистрами, чтобы соблюсти паритет узких мест. Т.е. если 1 инструкция доступа к памяти и от 1 до 5 команд работающих чисто с регистрами будут работать с одинаковой скоростью, т.к. всё упрется в память. Более (примерно) 5 команд на 1 доступ к памяти уже упираться будут в скорость этих команд. Как-то так.