Здравствуйте уважаемые! Возникла острая необходимость в алгоритме быстрого подсчёта контрольной суммы UDP пакета. Разбираться во всяких RFC и т.п., а так же во многих статьях, где про это умомянуто так, вскользь, типа это все знают и описывать не будем, дельного мало. Нужен именно оптимизированный по скорости алгоритм. Если на ассемблере, то просто супер!!! С огромным уважением и заранее благодарен, PavPS.
На атлонеХР для блоков 1-64 Кб получается примерно 0.55-0.6 такта/байт: Код (Text): sum:;(ptr +4, len +8) mov esi,[esp+4] ;ptr mov ecx,[esp+8] ;len xor eax,eax shr ecx,1 jnc .l0 add al,[esi+ecx*2] .l0: shr ecx,1 jnc .l2 add ax,[esi+ecx*4] adc ax,0 .l2: shr ecx,1 jnc .l3 add eax,[esi+ecx*8] adc eax,0 .l3: jecxz .exit .l1: adc eax,[esi+ecx*8-8] adc eax,[esi+ecx*8-4] loop .l1 adc eax,0 .exit: ; метка должна быть здесь!!! mov edx,eax shr eax,16 add ax,dx adc ax,0 ; .exit: а не здесь ret 8 Еще есть MMX вариант, но он в два с половиной раза хуже: Код (Text): summmx: mov esi,[esp+4] mov ecx,[esp+8] pxor mm0,mm0 pxor mm1,mm1 pxor mm7,mm7 shr ecx,2 .l0: paddd mm0,mm1 movd mm1,[esi] add esi,4 punpcklwd mm1,mm7 loop .l0 paddd mm0,mm1 sub esp,8 movq [esp],mm0 pop edx pop eax add eax,edx mov edx,eax shr eax,16 add ax,dx adc ax,0 ret 8 Работает только с блоками кратными двойному слову размером не более 65535 двойных слов. Если переписать для SSE2 и малость развернуть цикл, то может он и догонит первый вариант. Исправлено: первый вариант не правильно обрабатывал блоки длиной 4-7 байт.
Теперь MMX вариант стал самым быстрым - 0.46-0.5 тактов/байт: Код (Text): summmx: mov esi,[esp+4] mov ecx,[esp+8] shr ecx,4 movq mm7,qword [.c8000] movq mm0,mm7 movq mm2,mm7 .l0: movq mm1,[esi] movq mm3,[esi+8] paddw mm0,mm1 paddw mm2,mm3 pxor mm1,mm7 pxor mm3,mm7 pcmpgtw mm1,mm0 pcmpgtw mm3,mm2 psubw mm0,mm1 psubw mm2,mm3 add esi,16 loop .l0 pxor mm2,mm7 paddw mm0,mm2 pxor mm2,mm7 pcmpgtw mm2,mm0 psubw mm0,mm2 pxor mm0,mm7 sub esp,8 movq [esp],mm0 pop edx pop eax add eax,edx adc eax,0 mov edx,eax shr eax,16 add ax,dx adc ax,0 ret 8 .c8000 dw $8000,$8000,$8000,$8000 Если переписать под SSE2, то ускорение будет еще в два раза.
SSE2 позволил удвоить скорость на больших массивах помещающихся в кеш: Код (Text): sumsse2:;(buf +4, len +8) mov edx,[esp+4] mov eax,31 sub eax,[esp+8] mov ecx,eax and eax,31 sub ecx,eax movdqu xmm0,[.mask+eax] movdqu xmm2,[.mask+eax+16] sub edx,ecx pand xmm0,[edx] pand xmm2,[edx+16] jecxz .exit movdqu xmm7,dqword [.hbit] pxor xmm0,xmm7 pxor xmm2,xmm7 .loop: movdqa xmm1,[edx+ecx] movdqa xmm3,[edx+ecx+16] paddd xmm0,xmm1 paddd xmm2,xmm3 pxor xmm1,xmm7 pxor xmm3,xmm7 pcmpgtd xmm1,xmm0 pcmpgtd xmm3,xmm2 psubd xmm0,xmm1 psubd xmm2,xmm3 add ecx,32 jnz .loop pxor xmm0,xmm7 pxor xmm2,xmm7 .exit: sub esp,32 movdqu [esp],xmm0 movdqu [esp+16],xmm2 pop eax mov ecx,7 .add: pop edx adc eax,edx loop .add adc eax,0 shld edx,eax,16 add ax,dx adc ax,0 movzx eax,ax ret 8 .hbit dd 80000000h,80000000h,80000000h,80000000h .mask: times 31 db -1 times 32 db 0