есть две функции которые принимают на вход два массива и работают над ними. написал две функции которые делают одно и тоже, одна обычная другая через MMX Код (Text): ; ESI - первый буфер ; EDI - второй буфер ; ECX - размер буфера CalcVals_nonMMX: shr ecx, 1 .loop: mov ax, [esi] mov dx, [edi] add ax, dx shl ax, 1 shr dx, 1 sub ax, dx mov [esi], dx mov [edi], ax add esi, 2 add edi, 2 dec ecx jnz .loop ret CalcVals_MMX: shr ecx, 3 .loop: movq mm0, [esi] movq mm1, [edi] paddw mm0, mm1 psllw mm0, 1 psrlw mm1, 1 psubw mm0, mm1 movq [esi], mm1 movq [edi], mm0 add esi, 8 add edi, 8 dec ecx jnz .loop ret cсобственно тестирование Код (Text): BufferSize dd 16*1024*1024 call [GetTickCount] push eax rdtsc push edx push eax mov ebx, 100 @@: mov esi, [nonMMX_Buffer1] mov edi, [nonMMX_Buffer2] mov ecx, [BufferSize] call CalcVals_nonMMX dec ebx jnz @b rdtsc pop ecx pop ebx sub eax, ecx sbb edx, ebx call [GetTickCount] pop ecx sub eax, ecx call [GetTickCount] push eax rdtsc push edx push eax mov ebx, 100 @@: mov esi, [MMX_Buffer1] mov edi, [MMX_Buffer2] mov ecx, [BufferSize] call CalcVals_MMX dec ebx jnz @b rdtsc pop ecx pop ebx sub eax, ecx sbb edx, ebx call [GetTickCount] pop ecx sub eax, ecx результаты не очень сильно различаются. замер через rdtsc даёт мизерное преимущество MMX. GetTickCount даёт одинаковое время. где подвох?
Подвох в размере массива. Оба алгоритма работают работают быстро, но вот при таком большом размере кэш не работает и основная задержка идёт на чтение и запись. Вот будь алгоритм по сложнее или массив по корочи к примеру уменьши его в 16 раз сразу увидишь 4-х кратное увеличение скорости.
пробовал 64К, 1М и 4М, тоже самое спасибо. попробовал миллион раз с размером 4КБ, MMX быстрее примерно в 3.8 раза
заметил что чем сложнее алгоритм тем больше прирост даёт MMX например вот два алгоритма. MMX даёт прирост в более чем 10 раз. но есть косяк. в 5-4% результаты вычислений различаются. кому не лень помогите пожалуйста найти косяк. Весь день глаза мозолю, не могу найти ошибку Код (Text): CalcValsV2_nonMMX: shr ecx, 1 .loop: mov ax, [esi] mov dx, [edi] add ax, dx shl ax, 1 shr dx, 1 add dx, ax inc dx rcr dx, 1 xor dx, ax sub ax, dx imul dx xor ax, dx mov [esi], dx mov [edi], ax add esi, 2 add edi, 2 dec ecx jnz .loop ret CalcValsV2_MMX: shr ecx, 3 .loop: movq mm0, [esi] movq mm1, [edi] paddw mm0, mm1 psllw mm0, 1 psrlw mm1, 1 pavgw mm1, mm0 pxor mm1, mm0 psubw mm0, mm1 movq mm2, mm1 pmulhw mm1, mm0 ; mm1 - high words pmullw mm2, mm0 ; mm2 - low words pxor mm2, mm1 movq [esi], mm1 movq [edi], mm2 add esi, 8 add edi, 8 dec ecx jnz .loop ret
нашёл. Код (Text): pavgw mm1, mm0 её аналог с без MMX Код (Text): add dx, ax inc dx ; <------ CF теряется rcr dx, 1 что делать? реализовывать через edx : eax ?
программа работает в Win32, поэтому проканает только lea edx, [eax+1]. вопрос совершенно в другом, не в том как сложить, а как сделать это наиболее оптимизированно и быстро. lea здесь не катит.
Тогда юзай movzx и 32-битные регистры lea edx,[edx+eax+1] shr edx,1 PS: Работа с частичными флагами типа inc+rcr и stc+adc особенно в NetBurst - это еще те тормоза