Aktív témák

  • P.H.

    senior tag

    Skeleton of code adjusted to Zen(1) and Zen+ (i. e. placeholder codes omitted).

    Runs constantly at 3.4 IPC (of maximum 4.0 due to the 4 available ALU-s) for 50x50 matrices, this means 85% utilization.

    Since more than 90% percent of instructions need ALU, so important theorem is the way of instruction distribution among the ALUs. This is true for all other microarchitectures as well.

    { } movsx ebx,byte ptr [eax+E.FIELD0+00h]
    { } mov esi,ebp
    { } xor edx,edx
    { } and esi,-8
    { } mov [edi+__A],ebp
    { } mov ecx,ebp
    @init:
    { } mov [edi+esi*08h+(00h*08h)+__B],edx
    { } mov [edi+esi*08h+(04h*08h)+__B],edx
    { } sub esi,-8
    { } jnz @init
    @@a:
    { } cmp ebx,ebp
    { } lea esi,[ebp+ebx*04h]
    { } movsx ebx,byte ptr [eax+E.FIELD0+01h]
    { } lea eax,[eax+01h]
    { } mov [edi+esi*08h+__B],ebp
    { } cmova esi,edx
    { } mov [edi+ecx*08h+__C],esi
    { } add ecx,04h
    { } jnz @@a
    { } mov eax,[edi+ebp*08h+__C]
    { } mov ebx,ebp
    { } mov edx,edi
    { } jmp @b
    @@ROWS:
    { } mov eax,[edi+ebx*08h+(04h*08h)+__C]
    { } add ebx,04h
    { } jz @@COLS
    @next0b:
    { } mov [edi+ebx*08h+__D],eax
    { } sub edx,ebp
    { } mov [edi+ebx*08h+R],eax
    { } add eax,ebp
    { } jc @@ROWS
    { } lea ecx,[ebp+04h]
    { } mov esi,[edx+ebp]
    { } or esi,[edi+ebp*08h+__B]
    { } and ecx,-8
    { } mov ebp,[edi+ecx*08h+__B]
    @findr:
    { } or ebp,[edx+ecx+00h]
    { } cmp ebp,eax
    { } cmovb eax,ebp
    { } mov ebp,[edx+ecx+04h]
    { } or ebp,[edi+ecx*08h+(04h*08h)+__B]
    { } cmp ebp,esi
    { } cmovb esi,ebp
    { } mov ebp,[edi+ecx*08h+(08h*08h)+__B]
    { } add ecx,08h
    { } jnz @findr
    { } cmp eax,esi
    { } mov ebp,[edi+__A]
    { } cmovb esi,eax
    { } neg esi
    { } mov [edi+__L+ebx*08h+__F],esi
    { } jle @ROWS
    @@EXIT:
    { } mov esi,[esp+_X]
    { } mov [esi+E.O],7FFFFFFFh
    { } jmp @outside
    @free0col:
    { } add [edi+__0],ebp
    { } mov [edi+__Y],esi
    { } mov ecx,0FFFFFFFFh
    @@COLS:
    { } mov [edi+ebp*08h-(04h*08h)+__B],ebx
    @mark:
    { } mov [edi+__L+ebx*08h+__CC],esi
    { } mov esi,[edi+__L+ebp*08h+__F]
    { } mov edx,ebp
    @nextc:
    { } lea eax,[ebx-04h]
    { } mov [edi+__L+ebx*08h+__M],ecx
    { } mov ecx,[edi+ebx*08h-(04h*08h)+__B]
    { } mov ebx,eax
    { } sub eax,ebp
    { } jc @@init0
    { } xor ecx,-1
    { } jns @nextc
    @findc:
    { } add esi,[eax+edi]
    { } or esi,[edi+edx*08h+__D]
    { } lea edx,[edx+04h]
    { } jz @testr
    { } sub eax,ebp
    { } cmp esi,ecx
    { } cmovb ecx,esi
    { } mov esi,[edi+__L+edx*08h+__F]
    { **} cmp edx,00h
    { **} jnz @findc
    { } mov eax,ebx
    { } mov edx,ebp
    { } mov esi,ecx
    { **} cmp ecx,00h
    { **} js @@EXIT
    @seek0:
    { } mov ecx,[edi+__L+edx*08h+__F]
    { } sub eax,ebp
    { } add edx,04h
    { } jg @free0col
    { } add ecx,[eax+edi]
    { **} cmp ecx,esi
    { **} jnz @seek0
    @testr:
    { } lea ecx,[edx-04h]
    { **} test [edi+edx*08h-(04h*08h)+__C],ebx
    { **} js @seek0col
    { } mov [edi+ebx*08h+__B],ecx
    { } mov [edi+edx*08h-(04h*08h)+__C],ebx
    { } xor ecx,ecx
    { } jmp @mark
    @@init0:
    { } mov [edi+__I],ecx
    { } mov eax,ecx
    { } sal ecx,10h
    { } jnz @scan
    { } mov eax,edi
    { } mov esi,[esp+_X]
    { } jmp outside
    @@1ST_STEP:
    { } movsx esi,ax
    { } mov esi,[edi+esi*08h+__C]
    { } neg edx
    @1ST_STEP:
    { } movsx ecx,byte ptr [edi+__L+ebx*08h+__S+__M]
    { } and ecx,edx
    { } sub [edi+__L+ebx*08h+__CC],ecx
    { } movsx ecx,byte ptr [edi+ebx*08h+__S+R]
    { } and ecx,edx
    { } sub [edi+__L+ebx*08h+__F],ecx
    { } add ebx,04h
    { } jnz @1ST_STEP
    { } mov ecx,[edi+__I]
    { } movsx ebx,ax
    { } sar eax,10h
    { **} test esi,esi
    { **} jz @@2ND_STEP
    { } add dword ptr [edi+__A],-1
    { } mov [edi+ebx*08h+R],eax
    { } mov [edi+__L+esi*08h+__M],ebx
    { } cmp esi,ecx
    { } cmovb ecx,esi
    { } mov ebx,ebp
    { } mov [edi+__I],ecx
    { } jmp @@6TH_STEP
    @pass:
    { } mov eax,ecx
    { } sar ecx,10h
    { } cmovnc eax,[edi+__W]
    { } mov [edi+__W],eax
    { } lea ebx,[ebp+00h]
    { } mov [edi+__L+ecx*08h+__M],esi
    @nx:
    { } mov esi,[edi+__L+ecx*08h+__M +(04h*08h)]
    { } add ecx,04h
    { } jz @@1ST_STEP
    { **} cmp esi,[edi+__A]
    { **} jbe @nx
    @@6TH_STEP:
    { } mov esi,[edi+__L+ecx*08h+__CC]
    { } lea ebx,[ebp-04h]
    { } { x1 } nop
    { } mov eax,ecx
    { } mov [edi+__Y],esi
    @ffd:
    { } sal ecx,10h
    { } mov esi,[edi+__L+ebx*08h+(04h*08h)+__F]
    @z:
    { **} cmp ebx,-4
    { **} jz @pass
    @scan:
    { } add ebx,04h
    { } sub eax,ebp
    { } sub esi,[edi+__Y]
    { } add esi,[edi+eax]
    { } or esi,[edi+ebx*08h+R]
    { } jz @@5TH_STEP
    { } cmp esi,edx
    { } cmovb cx,bx
    { } cmovb edx,esi
    { } mov esi,[edi+__L+ebx*08h+(04h*08h)+__F]
    { **} cmp ebx,-4
    { **} jz @pass
    { } add ebx,04h
    { } sub eax,ebp
    { } sub esi,[edi+__Y]
    { } add esi,[edi+eax]
    { } or esi,[edi+ebx*08h+R]
    { } jz @@5TH_STEP
    { } cmp esi,edx
    { } cmovb cx,bx
    { } cmovb edx,esi
    { } mov esi,[edi+__L+ebx*08h+(04h*08h)+__F]
    { } db $66,$66,$66; nop
    { } jmp @zZ
    @@5TH_STEP:
    { } mov esi,ecx
    { } sar ecx,10h
    { } cmovnc esi,[edi+__W]
    { } mov [edi+__W],esi
    { } mov esi,[edi+ebx*08h+__C]
    { **} test esi,esi
    { **} jz @2ND_STEP
    { } mov [edi+ebx*08h+R],ecx
    { } mov [edi+__L+esi*08h+__M],0FFFFFFFFh
    { **} cmp word ptr [edi+__W],bx
    { **} jz @re
    { **} cmp esi,ecx
    { **} jae @ffd
    { } mov ecx,esi
    { } mov eax,[edi+__I]
    { } cmp esi,eax
    { } cmovb eax,esi
    { } mov [edi+__I],eax
    { } jmp @@6TH_STEP
    @re:
    { } mov ecx,[edi+__I]
    { } add dword ptr [edi+__A],-1
    { } mov edx,esi
    { } cmp esi,ecx
    { } cmovb ecx,esi
    { } mov [edi+__I],ecx
    { } jmp @@6TH_STEP
    @@2ND_STEP:
    { } mov ecx,eax
    @2ND_STEP:
    { } mov [edi+ebx*08h+__C],ecx
    { } mov edx,[edi+ecx*08h+__B]
    { } mov [edi+ecx*08h+__B],ebx
    { } mov ecx,[edi+edx*08h+R]
    { } mov ebx,edx
    { } add edx,ebp
    { } jc @2ND_STEP
    { } mov ecx,esi
    { } sub [edi+__0],ebp
    { } jz @@outside
    @@9ST_STEP:
    { } mov eax,[edi+esi*08h-(04h*08h)+__B]
    { } xor eax,-1
    { } mov [edi+__L+esi*08h-(04h*08h)+__M],eax
    { } lea esi,[esi-04h]
    { } cmovs ecx,esi
    { } mov ebx,[edi+esi*08h+__D]
    { } mov eax,[edi+esi*08h-(04h*08h)+__B]
    { } mov [edi+esi*08h+R],ebx
    { **} cmp ebp,esi
    { **} jz @i9
    { } xor eax,-1
    { } mov [edi+__L+esi*08h-(04h*08h)+__M],eax
    { } lea esi,[esi-04h]
    { } cmovs ecx,esi
    { } mov eax,[edi+esi*08h+__D]
    { } mov [edi+esi*08h+R],eax
    { **} cmp ebp,esi
    { **} jnz @@9ST_STEP
    @i9:
    { } mov [edi+__I],ecx
    {- } jmp @@6TH_STEP

  • P.H.

    senior tag

    válasz P.H. #105 üzenetére

    Örömmel jelentem, hogy lassabb nem lett

    .............................

    { } movsx ebx,byte ptr [edx]
    { } xor eax,eax
    { } mov esi,ebp
    { } mov [edi+__N],ebp
    { } and esi,-8
    { } mov ecx,ebp
    @init:
    { } mov [edi+esi*08h+(00h*08h)+__K],eax
    { } mov [edi+esi*08h+(04h*08h)+__K],eax
    { } add esi,08h
    { } jnz @init
    @argument
    { } cmp ebx.00h
    { } lea eax,[ebp+ebx*04h]
    { } movsx ebx,byte ptr [edx+01h]
    { } lea edx,[edx+01h]
    { } mov [edi+eax*08h+__K],ebp
    { } cmovs eax,esi
    { } mov [edi+ecx*08h+__F],eax
    { } add ecx,04h
    { } jnz @argument
    { } mov [edi+ebp*08h-(04h*08h)+__K],esi
    { } lea edx,[ebp-04h]
    { } mov ebx,edi
    { } jmp @next0row
    @ROWS:
    { } mov [edi+__LEFT1+edx*08h+__W],esi
    @next0row:
    { } mov eax,[edi+edx*08h+(04h*08h)+__S]
    { } add edx,04h
    { } jz @@COLUMNS
    { } mov [edi+edx*08h+B],eax
    { } xor esi,esi
    { } mov [edi+edx*08h+_R],eax
    { } sub ebx,ebp
    { **} test eax,eax
    { **} jnz @@ROWS
    { } lea ecx,[ebp+04h]
    { } mov esi,[ebx+ebp]
    { } or esi,[edi+ebp*08h+__K]
    { } and ecx,-8
    @findrowmin:
    { } mov eax,[ebx+ecx]
    { } or eax,[edi+ecx*08h+__K]
    { } add ecx,08h
    { } cmp eax,ebp
    { } cmovb ebp,eax
    { } mov eax,[ebx+ecx-04h]
    { } or eax,[edi+ecx*08h-(04h*08h)+__K]
    { } cmp eax,esi
    { } cmovb esi,eax
    { **} cmp ecx,00h
    { **} jnz @findrowmin
    { } cmp ebp,esi
    { } cmovb esi,ebp
    { } mov ebp,[edi+__N]
    { } neg esi
    { } jle @@ROWS
    @@XXX:
    { } mov esi,[esp+_A]
    { } mov ecx,[esp+_I]
    { } mov dword ptr [esi+A.OPTIMUM],?
    { } mov ebx,[esi+TRESULT.NEXT]
    { } jmp ecx
    @free0col:
    { } add dword ptr [edi+__0COUNTER],-1
    { } mov [edi+__CCOLMIN],esi
    { } mov ecx,0FFFFFFFFh
    { } mov [edi+ebp*08h-(04h*08h)+__K],edx
    @0col:
    { } mov [edi+__LEFT1+edx*08h+__COLMOD],esi
    @@COLUMNS:
    { -} mov ebx,ebp
    @next0col:
    { } mov [edi+__LEFT1+edx*08h+__C],ecx
    { } mov ecx,edi+edx*08h-(04h*08h)+__K]
    { } lea eax,[edx-04h]
    { } sub eax,ebp
    { } js @@INIT0COL
    { } sub edx,04h
    { } xor ecx,-1
    { } jns @next0col
    @findcolmin:
    { } mov esi,[eax+edi]
    { } add esi,[edi+__LEFT1+ebx*08h+__U]
    { } or esi,[edi+ebx*08h+__S]
    { } jz @test0row
    { } sub eax,ebp
    { } cmp esi,ecx
    { } cmovb ecx,esi
    { } add ebx,04h
    { } jnz @findcolmin
    { } mov eax,edx
    { } lea ebx,[ebp-04h]
    { } mov esi,ecx
    { } cmp ecx,00h
    { } js @@XXX
    @seek0col:
    { } mov ecx,[edi+__LEFT1+ebx*08h+(04h*08h)+__W]
    { } sub eax,ebp
    { } add ebx,04h
    { } jz @free0col
    { } add ecx,[eax+edi]
    { **} cmp ecx,esi
    { **} jnz @seek0col
    @test0row:
    { } mov ecx,[edi+ebx*08h+B]
    { **} test ecx,ecx
    { **} js @seek0col
    { } mov [edi+ebx*08h+B],edx
    { } mov [edi+edx*08h+__K],ebx
    { } jmp @0col
    @@INIT0COL:
    { } lea eax,[edi+ecx]
    { } mov [edi+__L],ecx
    { } neg ebp
    { } sal ecx,10h
    { } jnz @init2col
    { -} xor esi,esi
    { } jmp @@FINISHED
    @@5TH_STEP:
    { -} mov edx,esi
    { } movsx esi,si
    { } sar eax,10h
    @5TH_STEP:
    { } movsx ecx,byte ptr [edi+__LEFT1+ebx*08h+__SIGN+__C]
    { } and ecx,edx
    { } add [edi+__LEFT1+ebx*08h+__COLMOD],ecx
    { } movsx ecx,byte ptr [edi+ebx*08h+__SIGN+_R]
    { } and ecx,edx
    { } add [edi+__LEFT1+ebx*08h+__W],ecx
    { } add ebx,04h
    { } jnz @5TH_STEP
    { } mov edx,es:[edi+esi*08h+B]
    { } db $8B,$8C,$3B,__L,?,?,?
    { **} test edx,edx
    { **} jz @@4TH_STEP
    { } add dword ptr [edi+__PN],-1
    { } mov [edi+esi*08h+_R],eax
    { } mov [edi+__LEFT1+edx*08h+__C],esi
    { } cmp edx,ecx
    { } cmovb ecx,edx
    { } sub ebx,ebp
    { } mov [edi+__L],ecx
    { } jmp @@9ND_STEP
    @fast6forward:
    { } mov esi,[edi+__LEFT1+ebx*08h+(04h*08h)+__W]
    { } add ebx,04h
    { } jz @pass8col
    { } sal ecx,10h
    { } jmp @loop
    @pass8col:
    { } mov eax,[edi+__N]
    { } sub ebx,ebp
    { } mov [edi+__LEFT1+ecx*08h+__C],eax
    @next20col:
    { } add ecx,04h
    { } jz @@5TH_STEP { clears ECX register
    { **} cmp [edi+__LEFT1+ecx*08h+__C],eax
    {0**} jbe @next20col
    @@8ND_STEP:
    { } mov esi,[edi+__LEFT1+ecx*08h+__COLMOD]
    { } lea eax,[edi+ecx]
    { } mov [edi+__CCOL],esi
    { } imul ecx,00010000h
    @init2col:
    { } add eax,ebp
    { } mov esi,[edi+ebx*08h+__W]
    @loop:
    { } sub esi,[edi+__COLMIN]
    { } add esi,[eax]
    { } lea eax,[eax+ebp]
    { } jo @over6flow
    { } or esi,[edi+ebx*08h+_R]
    { } jz @@11D_STEP
    { } cmp esi,edx
    { } cmovb edx,esi
    { } cmovb cx,bx
    @over6flow:
    { } mov esi,[edi+__LEFT1+ebx*08h+(04h*08h)+__W]
    { } add ebx,04h
    { } jnz @loop
    { -} mov eax,ecx
    { } sar ecx,10h
    { } cmovc esi,eax
    { } mov [edi+__MC],esi
    { } jmp @pass8col
    @@11D_STEP:
    { -} mov esi,ecx
    { } sar ecx,10h
    { } cmovnc esi,[edi+__M]
    { } mov [edi+__MC],esi
    { } mov esi,[edi+ebx*08h+B]
    { **} test esi,esi
    { **} jz @4TH_STEP
    { } mov [edi+ebx*08h+_R],ecx
    { } mov [edi+__LEFT1+esi*08h+__C],-1
    { **} cmp word ptr [edi+__MC],bx
    { **} jz @re2start
    { **} cmp esi,ecx
    { **} jae @fast6forward
    { } mov ecx,esi
    { } xor ebx,ebx
    { } mov eax,[edi+__L]
    { } sub ebx,ebp
    { } cmp esi,eax
    { } cmovb eax,esi
    { } mov [edi+__L],eax
    { } jmp @@7ND_STEP
    @re2start:
    { } mov ecx,[edi+__L]
    { } xor ebx,ebx
    { } add dword ptr [edi+__PN],-1
    { } mov edx,esi
    { } cmp esi,ecx
    { } cmovb ecx,esi
    { } sub ebx,ebp
    { } mov [edi+__L],ecx
    { } jmp @@6ND_STEP
    @@4TH_STEP:
    { } mov ecx,eax
    { } mov ebx,esi
    @4TH_STEP:
    { } mov [edi+ebx*08h+BB],ecx
    { } mov edx,[edi+ecx*08h+__K]
    { } mov [edi+ecx*08h+__K],ebx
    { } mov ebx,edx
    { } mov ecx,[edi+edx*08h+_R]
    { } sub edx,ebp
    { } jnc @4TH_STEP
    { } xor esi,esi
    { } mov ebx,edx
    { } sub dword ptr [edi+__0COUNTER],-1
    { } jz @@FINISHED
    @@1ST_STEP:
    { } mov eax,[edi+esi*08h-(04h*08h)+__K]
    { } xor eax,-1
    { } mov [edi+__LEFT1+esi*08h-(04h*08h)+__C],eax
    { } lea esi,[esi-04h]
    { } mov eax,[edi+esi*08h+__S]
    { } cmovs ecx,esi
    { } mov [edi+esi*08h+_R],eax
    { **} cmp edx,esi
    { **} jnz @@1ST_STEP
    { } nop
    { } mov [edi+__L],ecx
    { } jmp @@5ND_STEP

    @@FINISHED:
    { } mov eax,edi
    { } mov ecx,[esp+_KIMENET]
    { } mov ebp,edx
    @@results:
    { } mov ebx,[edi+edx*08h+__B]
    { } sub eax,ebp
    { } add esi,[eax+ebx]
    { } sub ebx,ebp
    { } shr ebx,02h
    { } mov [ecx],bl
    { } add ecx,01h
    { } add edx,04h
    { } jnz @@results
    (CODE)

  • P.H.

    senior tag

    válasz P.H. #108 üzenetére

    Egy program sosincs befejezve, csak abbahagyva van.

    @FIX_character:
    {@A2} {0} mov [edi],al
    {1-} mov ecx,edx
    {2} add edi,01h
    @@FIX_symbol:
    {@A9} {0} mov eax,(($1 shl ZFIX_aMAXBITS)-1)
    {1} shl ebp,cl
    {@B0} {2} xor ecx,(03h shl 03h)
    {0} and ax,bx
    {1} or edx,(03h shl 03h)
    {2} shr ecx,03h
    {0} or ebx,ebp
    {1} add esi,ecx
    @@FIX_code:
    {@C0} {2} mov ecx,dword ptr [ZFIXED_RELOC+eax*08h+_SIZE]
    {0} mov ebp,[esi]
    {1} mov eax,dword ptr [ZFIXED_RELOC+eax*08h+_CODE]
    {@D0} {2} shr ebx,cl
    {0*} sub edx,ecx
    {1*} jnc @FIX_character
    @FIX_length:
    {2} sar ecx,10h
    {0} and al,bl
    {1} sub dl,cl
    {2} shr ebx,cl
    {@FF} {0-} movzx ecx,al
    {@02} {1} sar eax,10h
    {2} jz @NXSECTION
    {0} sub eax,ecx
    {1-} movzx ecx,bl
    @FIX_distance:
    {@10} {2} sub edx,ZFIX_dBITS
    {0} mov [esp+_MOVELEN],eax
    {1} sub edi,eax
    {2} mov eax,dword ptr [ZFIXED_DISTx8+ecx*04h]
    {@20} {0-} movzx ecx,dl
    {1} shr ebx,ZFIX_dBITS
    @FIX_load:
    {2} or edx,(03h shl 03h)
    {0} shl ebp,cl
    {1} xor ecx,(03h shl 03h)
    {2} shr ecx,03h
    {@31} {0} or ebx,ebp
    {1} mov ebp,[esp+_MOVELEN]
    {2} movzx edx,dl
    {0} add esi,ecx
    {1-} mov ecx,eax
    {2} sar eax,10h
    {@41} {0} jns @FIX_movechar
    {1} jc @FIX_moveword
    {2} mov ebp,00000001h
    @FIX_movedword:
    {0} sub dl,cl
    {1} shl ebp,cl
    {2} add eax,edi
    {@50} {0} add ebp,0FFFFFFFFh
    {1} and ebp,ebx
    {2} shr ebx,cl
    {0} mov ecx,[esp+_MOVELEN]
    {1} sub eax,ebp
    @FIX_move4byte:
    {@60} {0} mov ebp,[ecx+eax+00h]
    {1} mov [edi+ecx+00h],ebp
    {2} mov ebp,[ecx+eax+04h]
    {0} mov [edi+ecx+04h],ebp
    {1*} add ecx,08h
    {@71} {2*} js @FIX_move4byte
    {0-} mov ecx,edx
    {1} mov ebp,[esi]
    {2} jmp @@FIX_symbol
    { x4 } lea eax,[edx+edx+01h]
    @FIX_movechar:
    {@60} {0} movzx eax,byte ptr [ebp+edi-01h]
    {0} imul ecx,eax
    {1-} mov eax,ebx
    @FIX_move1byte:
    {0} mov [edi+ebp+00h],ecx
    {@70} {1} mov [edi+ebp+04h],ecx
    {2*} add ebp,08h
    {0*} js @FIX_move1byte
    {1} and eax,(($1 shl ZFIX_aMAXBITS)-1)
    {2} jmp @@FIX_code
    @FIX_moveword:
    {@80} {0} add eax,edi
    @FIX_move2byte:
    {@82} {0} movzx ecx,word ptr [eax+ebp+00h]
    {1} mov [edi+ebp+00h],cx
    {2} movzx ecx,word ptr [eax+ebp+02h]
    {@8F} {0} mov [edi+ebp+02h],cx
    {@94} {1*} add ebp,04h
    {2*} js @FIX_move2byte
    {0-} mov eax,ebx
    {1} and eax,(($1 shl ZFIX_aMAXBITS)-1)
    {@A0} {2} jmp @@FIX_code

  • P.H.

    senior tag

    Procuction Code. P4 ready. Core2-n, K10-en, Bulldozeren, P4-en 12%-kal gyorsabb, mint a W..R.r.

    @samechar:
    {@80} {0**} cmp edx,ebp
    {1**} jae @initrepeat
    @compression:
    {2} cmp cl,[esi+edx+01h]
    {0} lea edx,[edx+01h]
    {1} jz @samechar
    @initrepeat:
    { } { x1 } and ebp,00h
    {@90} { **} cmp edx,(03+01)
    { **} jae @special { long jump instruction }
    { } mov ch,cl
    { } { x1 } mov ss:[esp+_ENCODED],edi
    @repeat:
    {@A0} {0-} lea edi,[eax+ebx]
    {1} and eax,(__WINDOW-1)
    {2**} cmp edi,-(__WINDOW)
    {0**} jbe @pre_encode
    {@B0} {1} add edi,esi
    {2} mov eax,[esp+_PREV+eax*04h]
    {0**} cmp ch,[edi+ebp]
    {1**} jnz @repeat
    {2**} cmp cl,[edi+00h]
    {0**} jnz @repeat
    {@C0} {1-} xor edx,edx
    @length:
    {@C2} {0**} cmp edx,[esp+_MAXRANGE]
    {1**} jae @maximum_repeat
    {2} movzx ecx,byte ptr [esi+edx+01h]
    {0} cmp cl,[edi+edx+01h]
    {@D1} {1} lea edx,[edx+01h]
    {2} jz @length
    {0} movzx ecx,byte ptr [esi+00h]
    {1} mov ch,[esi+ebp]
    {2**} cmp edx,ebp
    {0**} jbe @repeat
    {@E0} {1-} mov ebp,edx
    {2} mov ch,[esi+edx]
    {0} mov [esp+_MOVEDIST],edi
    {2} jmp @repeat
    { x6 } test ebx,00000000h
    {@F0} { x4 } xor ebp,ebp; xor esi,esi
    @maximum_repeat:
    {@F4} {0} mov [esp+_MOVEDIST],edi
    {1} mov ebp,00000028
    {2-} xor eax,eax
    {0-} xor ebx,ebx
    {@00} {1} mov edi,[esp+_ENCODED]
    {2**} cmp edx,00000258
    {0**} jz @indexed
    {1} movzx ecx,byte ptr [esi+00h]
    {2-} mov ebp,edx
    @pre_encode:
    {@11} {0} mov edi,[esp+_ENCODED]
    {1-} xor ebx,ebx
    {2*} sub ebp,03h
    {0*} jb @encode_alpha
    {@20} {1-} movzx eax,bl
    {2} lea edx,[ebp+03h]
    { } jz @indexed
    @encode_length:
    {---} bsr ecx,ebp
    {0*} sub ecx,02h
    {1*} jle @indexed
    {@30} {2-} mov ebx,ebp
    {0} shr ebp,cl
    {1-} mov eax,ebp
    {2} lea ebp,[ebp+ecx*04h+00h]
    {0} shl eax,cl
    {1} xor ebx,eax
    {2-} mov eax,ecx
    @indexed:
    {@40} {0} mov ecx,dword ptr [ZFIXED_ENCODE+257*04h+ebp*0
    {1} mov ebp,[esp+_ZIPPED]
    {2} add al,cl
    {0} shl ebx,cl
    {1} shr ecx,10h
    {@52} {2} or ebx,ecx
    {0-} mov ecx,edi
    {1} and ecx,07h
    {2} shr edi,03h
    {0} shl ebx,cl
    {1} or bl,[edi+ebp]
    {@61} {2} add ecx,eax
    {0} mov eax,[esp+_MOVEDIST]
    @writelength:
    {0} mov [edi+ebp],bl
    {1} add edi,01h
    {2} shr ebx,08h
    {0*} sub ecx,08h
    {@72} {1*} jge @writelength
    @encode_distance:
    { } { x3 } mov ebp,00000000h
    { } sub eax,esi
    { } xor eax,-1
    {@80} { } lea edi,[edi*08h+ecx*08h+00]
    { } jz @distindexed
    {---} bsr ecx,eax
    {0*} sub ecx,01h
    {1*} js @distindexed
    {2-} mov ebx,eax
    {@90} {0} shr eax,cl
    {1-} mov ebp,eax
    {2} lea eax,[ecx*02h+eax]
    {0} shl ebp,cl
    {1} xor ebx,ebp
    {2-} mov ebp,ecx
    {0} shl ebx,05h
    @distindexed:
    {@A0} {0} or ebx,dword ptr [REVERSE2_5+eax*04h]
    {1-} mov ecx,edi
    {0} shr edi,03h
    {2} mov eax,[esp+_ZIPPED]
    {@B0} {1} and ecx,07h
    {2} shl ebx,cl
    {0} or bl,[edi+eax]
    {1} lea ecx,[ecx+ebp+05h]
    {2} mov ebp,[esp+_HASH]
    @writedistance:
    {@C0} {0} mov [edi+eax],bl
    {1} add edi,01h
    {2} shr ebx,08h
    {0*} sub ecx,08h
    {1*} jge @writedistance
    { } add edx,esi
    {@D0} { } lea edi,[edi*08h+ecx]
    { -} mov eax,ebp
    { } jmp @administration
    { x9 } xor eax,eax; xor ebp,ebp; mov edx,00000000h
    {@00} { x4 } xor edx,edx; xor ecx,ecx
    @encode_alpha:
    {@04} {0} mov ebp,[esp+_ZIPPED]
    {1-} movzx edx,cl
    {2-} mov ecx,edi
    {0} shr edi,03h
    {@10} {1} mov edx,dword ptr [ZFIXED_ENCODE+edx*04h]
    {2} and ecx,07h
    {0} movzx eax,dx
    {1} shr edx,10h
    {@20} {2} shl edx,cl
    {0} add ecx,eax
    {1} mov eax,[esp+_HASH]
    {2} or dl,[edi+ebp]
    @writechar:
    {0} mov [edi+ebp],dl
    {1} add edi,01h
    {@31} {2} shr edx,08h
    {0*} sub ecx,08h
    {1*} jge @writechar
    { } lea edx,[esi+01h]
    { } lea edi,[edi*08h+ecx+00h]
    @administration:
    {@20} {0} mov ecx,[esp+_LAST+eax*04h]
    {1} mov [esp+_LAST+eax*04h],esi
    {2} shl eax,__BITS
    {0} and eax,__LOOKUP-1
    {1-} mov ebp,esi
    {2} xor al,[esi+03h]
    {0} add esi,01h
    {1} and ebp,(__WINDOW-1)
    {2} mov [esp+_PREV+ebp*04h],ecx
    {0**} cmp esi,edx
    {1**} jnz @administration
    @nextloop:
    {0} mov [esp+_HASH],eax
    {@70} {1} mov ebp,[esp+_LEN]
    {2} sub ebx,esi
    {0} mov eax,[esp+_LAST+eax*04h]
    {1-} xor edx,edx
    {2} movzx ecx,byte ptr [esi+00h]
    {0*} sub ebp,esi
    {1*} jz @finalize
    {2**} cmp ebp,00000258
    {@90} {0**} jae @compression
    { } mov [esp+_MAXRANGE],ebp
    { } jmp @compression
    { x1 } nop
    {@80} { x1 } nop
    @special:

  • P.H.

    senior tag

    Production code. P4 ready. Core2-n, K10-en, Bulldozeren, P4-en 2.5x gyorsabb, mint a W..R.r.

    @FIX_character:
    {@A1} {0} mov [edi],al
    {1} add edi,01h
    @@FIX_DECODE: { bpos >= 9 }
    {2} mov eax,[esi]
    {0-} mov ecx,edx
    {1} mov ebp,((-1 shl ZFIX_aMAXBITS) xor -1)
    {@AF} {2} shr edx,03h
    {@B2} {0} xor edx,03h
    {1} and ebp,ebx
    {2} shl eax,cl
    {0} add esi,edx
    {1} lea edx,[ecx+edx*08h]
    {2} or ebx,eax
    @FIX_code:
    {@C0} {0} mov eax,dword ptr [ZFIXED_RELOC+ebp*08h+_CODE]
    {1} mov ecx,dword ptr [ZFIXED_RELOC+ebp*08h+_SIZE]
    {2} sub edx,ecx
    {@D0} {0} shr ebx,cl
    {1**} cmp eax,00000100h
    {2**} jb @FIX_character
    @FIX_length:
    {0-} mov ecx,eax
    {1-} movzx ebp,ah
    {2} jz @SECTION { short jump instruction }
    {@E0} {0} and ebp,ebx
    {1} shr eax,10h
    {2} add ebp,eax
    {0-} mov eax,ebx
    {1} add edi,ebp
    @FIX_distance:
    {2} shr eax,cl
    {0} add cl,ZFIX_dBITS
    {@F0} {1} neg ebp
    {2} sub dl,cl
    {0} and eax,((-1 shl ZFIX_dBITS) xor -1)
    {1} shr ebx,cl
    {2} mov eax,dword ptr [ZFIXED_DIST+eax*04h]
    @FIX_load:
    {@00} {0} mov [esp+_MOVELEN],ebp
    {1} mov ebp,[esi]
    {2-} mov ecx,edx
    {0} shr edx,03h
    {1} xor edx,03h
    {2} shl ebp,cl
    {@10} {0} add esi,edx
    {1} lea edx,[ecx+edx*08h]
    {2} or ebx,ebp
    {0} mov ebp,[esp+_MOVELEN]
    {1**} test al,0FFh
    {2**} js @FIX_movechar
    {@20} {0} jz @FIX_moveword
    @FIX_movedword:
    {1} mov ebp,00000001h
    {2-} mov ecx,eax
    {0} sub dl,al
    {1} sar eax,10h
    {2} shl ebp,cl
    {@30} {0} xor ebp,0FFFFFFFFh
    {1} add eax,edi
    {2} and ebp,ebx
    {0} shr ebx,cl
    {1} mov ecx,[esp+_MOVELEN]
    {@40} {2} sub eax,ebp
    @FIX_move4byte:
    {0} mov ebp,dword ptr [ecx+eax+00h]
    {1} mov [edi+ecx+00h],ebp
    {2} mov ebp,dword ptr [ecx+eax+04h]
    {0} mov [edi+ecx+04h],ebp
    {@50} {1*} add ecx,08h
    {2*} js @FIX_move4byte
    { } jmp @@FIX_DECODE
    { x6 } cmp esi,00h; cmp edx,00h
    @FIX_moveword:
    {@60} {0} sar eax,10h
    {1} add eax,edi
    @FIX_move2byte:
    {@65} {0} movzx ecx,word ptr [eax+ebp+00h]
    {1} mov [edi+ebp+00h],cx
    {@6D} {2} movzx ecx,word ptr [eax+ebp+02h]
    {@72} {0} mov [edi+ebp+02h],cx
    {1*} add ebp,04h
    {2*} js @FIX_move2byte
    { } jmp @@FIX_DECODE
    @FIX_movechar:
    {@81} {1} movzx eax,byte ptr [ebp+edi-01h]
    @FIX_repeat:
    {@86} {0} mov [edi+ebp+00h],al
    {1} mov [edi+ebp+01h],al
    {2*} add ebp,02h
    {@90} {0*} js @FIX_repeat
    { } jmp @@FIX_DECODE

  • P.H.

    senior tag

    válasz P.H. #106 üzenetére

    és befele:

    @program:
    {0} movzx ecx,byte ptr [esi+00h]
    @x:
    {0**} cmp edx,ebp
    {1**} jae @init
    {2} add edx,01h
    {0**} cmp cl,[esi+edx]
    {1**} jz @x
    @init:
    { **} cmp edx,(03+01)
    { **} jae @long_jump
    { -} xor ebp,ebp
    { } mov [esp+_Q],edi
    { } mov ch,cl
    @repeat:
    {0-} mov edi,eax
    {1} and eax,(__WINDOW-1)
    {2} sub edi,ebx
    {0} mov eax,[esp+_PREV+eax*04h]
    {1**} cmp edi,-(__WINDOW)
    {2**} jbe @pre_encode { JLE = JBE for 2 negative numbers }
    {0} add edi,esi
    {1**} cmp ch,[edi+ebp]
    {2**} jnz @repeat
    {0**} cmp cl,[edi+00h]
    {1**} jnz @repeat
    {2-} xor edx,edx
    @length:
    {0**} cmp edx,[esp+...]
    {1**} jae @QQ
    {2} movzx ecx,byte ptr [esi+edx+01h]
    {0} cmp cl,[edi+edx+01h]
    {1} lea edx,[edx+01h]
    {2} jz @length
    {0} movzx ecx,byte ptr [esi+00h]
    {1} sub edi,esi
    {2} cmp edx,ebp
    {0} cmova ebp,edx
    {1} mov ch,[esi+ebp]
    {2} jbe @repeat
    {0} mov [esp+...],edi
    {1} jmp @repeat
    @QQ:
    {0} movzx ecx,byte ptr [esi+00h]
    {1} sub edi,esi
    {2} mov ebp,00000028
    {0} mov [esp+...],edi
    {1} mov edi,[esp+_Q]
    {2-} xor eax,eax
    {0**} cmp edx,???
    {1**} jz @QQQ
    {2-} mov ebp,edx
    @pre_encode:
    {0} mov edi,[esp+_Q]
    {1-} xor eax,eax
    {2*} sub ebp,03h
    {0*} jb @encode_alpha
    {1} lea edx,[ebp+03h]
    @QQQ:
    { } mov [esp+...],ebx
    { -} mov ebx,eax
    { } jz @indexed
    {---} bsr ecx,ebp
    {0*} sub ecx,02h
    {1*} jle @indexed
    {2} mov ebx,dword ptr [...+ecx*04h]
    {0-} mov eax,ecx
    {1} and ebx,ebp
    {2} shr ebp,cl
    {0} lea ebp,[ebp+ecx*04h+00h]
    @indexed:
    {0} mov ecx,dword ptr [...+ebp*04h]
    {1} mov ebp,[esp+_ZIPPED]
    {2} add al,cl
    {0} shl ebx,cl
    {1} shr ecx,10h
    {2} or ebx,ecx
    {0-} mov ecx,edi
    {1} and ecx,07h
    {2} shr edi,03h
    {0} shl ebx,cl
    {1} or bl,[edi+ebp]
    {2} add ecx,eax
    {0} mov eax,[esp+...]
    @write:
    {0} mov [edi+ebp],bl
    {1} add edi,01h
    {2} shr ebx,08h
    {0*} sub ecx,08h
    {1*} jge @write
    { } xor eax,-1
    { } mov ebp,00000005h
    { } lea edi,[edi*08h+ecx]
    { } jz @distindexed
    {---} bsr ecx,eax
    {0*} sub ecx,01h
    {1*} js @distindexed
    {2} mov ebx,dword ptr [...+ecx*04h]
    {0} add ebp,ecx
    {1} and ebx,eax
    {2} shr eax,cl
    {0} lea eax,[ecx*02h+eax]
    {1} shl ebx,05h
    @distindexed:
    {0-} mov ecx,edi
    {1} or ebx,dword ptr [...+eax*04h]
    {2} mov eax,[esp+_ZIPPED]
    {0} shr edi,03h
    {1} and ecx,07h
    {2} shl ebx,cl
    {0} add ecx,ebp
    {1} or bl,[edi+eax+00h]
    {2} mov ebp,[esp+_HASH]
    @write:
    {0} mov [edi+eax],bl
    {1} add edi,01h
    {2} shr ebx,08h
    {0*} sub ecx,08h
    {1*} jge @write
    { } add esi,edx
    { } neg edx
    { } mov ebx,[esp+...]
    { -} mov eax,ebp
    { } lea edi,[edi*08h+ecx]
    { } jmp @administration
    @encode_alpha:
    {0} mov ebp,[esp+_ZIPPED]
    {1} movzx edx,cl
    {2-} mov ecx,edi
    {1} mov edx,dword ptr [...+edx*04h]
    {0} shr edi,03h
    {2} and ecx,07h
    {0-} mov eax,edx
    {1} shr edx,10h
    {2} shl edx,cl
    {0} add cl,al
    {1} mov eax,[esp+_HASH]
    {2} or dl,[edi+ebp]
    @write:
    {0} mov [edi+ebp],dl
    {1} add edi,01h
    {2} shr edx,08h
    {0*} sub ecx,08h
    {1*} jge @write
    { } xor edx,-1
    { } mov ebp,eax
    { } add esi,01h
    { } lea edi,[edi*08h+ecx]
    @administration:
    {0} shl eax,__BITS
    {1} and eax,__LOOKUP-1
    {2} xor al,[esi+edx+03h]
    {0} mov ecx,[esp+_LAST+ebp*04h]
    {1} mov [esp+_LAST+ebp*04h],ebx
    {2-} mov ebp,ebx
    {0} add ebx,01h
    {1} and ebp,(__WINDOW-1)
    {2} mov [esp+_PREV+ebp*04h],ecx
    {1} add edx,01h
    {0-} mov ebp,eax
    {2} jnz @administration
    { } mov [esp+_HASH],eax
    { } mov ebp,[esp+_LEN]
    { } mov eax,[esp+_LAST+eax*04h]
    { *} sub ebp,ebx
    { *} jz @finalize
    { **} cmp ebp,???
    { **} jae @program
    { } mov [esp+...],ebp
    { } jmp @program
    @long_jump:

  • P.H.

    senior tag

    válasz P.H. #92 üzenetére

    Egy Pentium 4 1 nagyságrenddel nagyobb teljesítményre képes, mint egy Java-ban írt program ARM-on (legalábbis mert léteznek pointerek, nincs szigorú típusosság, nincs byte-nál automatikus előjeles kiterjesztés 4 byte-ra, amit le kell küzdeni, stb.); még úgy is, hogy a branch prediction success rate 87% körüli.

    A ciklus ASM-ben:

    @character:
    {@65} { } mov [edi],al
    { } add edi,01h
    @@DECODE:
    {@6A} { } mov eax,[esp+_aMAXMINBITS]
    @read_raw: { BPOS may be 20h since decreased soon }
    { } movzx ebp,byte ptr [esi]
    {@70} { -} mov ecx,edx
    { } sub edx,(24+1)
    { } shl ebp,cl
    { } shr edx,1Fh
    { } add esi,edx
    { } lea edx,[ecx+edx*08h]
    { } or ebx,ebp
    {@81} { **} cmp dl,al
    { **} jb @read_raw
    @createABCcode:
    { } movzx ebp,bl
    { } movzx ecx,bh
    { } shr eax,10h
    { } { x1 } mov ebp,dword ptr es:[REVERSE2hi+ebp*04h]
    { } { x1 } add ebp,dword ptr es:[REVERSE2lo+ecx*04h]
    { -} mov ecx,eax
    {@A0} { } mov eax,offset(EXT_AMINMAXCODE)
    @seekABC:
    {@A5} {0**} cmp [eax+ecx*08h+00h+_MAX],ebp
    {1**} jnbe @foundABC
    {2} cmp [eax+ecx*08h-08h+_MAX],ebp
    {0} lea ecx,[ecx-02h]
    {@B1} {1} jbe @seekABC
    { } add ecx,01h
    @foundABC:
    {@B6} {0} mov eax,[eax+ecx*08h+_MIN]
    {1} shr ebp,cl
    {2} { x1 } mov eax,es:[eax+ebp*04h]
    {@C0} {0} neg ecx
    {1} add ecx,10h
    {2} sub edx,ecx
    {0} shr ebx,cl
    {1**} cmp eax,255
    {2**} jna @character { SHORT jump instruction offset: -6Bh }
    @repeatABC:
    {@D0} {0-} mov ecx,eax
    {1} movzx ebp,ah
    {2} shr eax,10h
    {0} jz @@SECTION
    {1} sub dl,cl
    {@E0} {2} and ebp,ebx
    {0} shr ebx,cl
    {1} add ebp,eax
    {2} { x1 } mov eax,ss:[esp+_dMAXMINBITS]
    {0} add edi,ebp
    {1} neg ebp
    {2} mov [esp+_MOVELEN],ebp
    @read__raw: { BPOS may be 20h since decreased soon }
    {@F3} {0} movzx ebp,byte ptr [esi]
    {1-} mov ecx,edx
    {2} sub edx,(24+1)
    {0} shl ebp,cl
    {1} shr edx,1Fh
    {@00} {2} add esi,edx
    {0} lea edx,[ecx+edx*08h]
    {1} or ebx,ebp
    {2**} cmp dl,al
    {0**} jb @read__raw
    @createDISTcode:
    { } movzx ebp,bl
    { } movzx ecx,bh
    {@11} { } shr eax,10h
    { } { x1 } mov ebp,dword ptr es:[REVERSE2hi+ebp*04h]
    { } { x1 } add ebp,dword ptr es:[REVERSE2lo+ecx*04h]
    {@24} { -} mov ecx,eax
    { } mov eax,offset(EXT_DMINMAXCODE)
    @seekDIST:
    {0**} cmp [eax+ecx*08h+00h+_MAX],ebp
    {1**} jnbe @foundDIST
    {@90} {2} cmp [eax+ecx*08h-08h+_MAX],ebp
    {0} lea ecx,[ecx-02h]
    {1} jbe @seekDIST
    { } add ecx,01h
    @foundDIST:
    {0} mov eax,[eax+ecx*08h+_MIN]
    {@A0} {1} shr ebp,cl
    {2} mov eax,[eax+ebp*04h]
    {0} neg ecx
    {1} add ecx,10h
    {2} sub edx,ecx
    {0} shr ebx,cl
    {1**} cmp al,00h
    {@70} {2**} js @xxx
    {0} jz @yyy
    @DISTbits: { BPOS may be 20h since decreased soon }
    {0} movzx ebp,byte ptr [esi]
    {1-} mov ecx,edx
    {2} sub edx,(24+1)
    {@80} {0} shr edx,1Fh
    {1} add esi,edx
    {2} lea edx,[ecx+edx*08h]
    {0} shl ebp,cl
    {1} or ebx,ebp
    {2**} cmp edx,16
    {0**} jb @DISTbits
    @srcposition:
    {@91} {1} movzx ecx,ax
    {2} sar eax,10h
    {0} mov ebp,dword ptr [OFF+ecx*04h]
    {1} sub edx,ecx
    {@A0} {2} add eax,edi
    {0} and ebp,ebx
    {1} shr ebx,cl
    @copy: ...

  • P.H.

    senior tag

    Nincs többé külön K10-nek tetsző és külön Core2-nek tetsző verzió: egyetlen van, amely mindkettőn jó, kb. 0.5% veszteséggel.

    Core2 (2.5 GHz): 58 sec alatt megoldja a feladatot
    K10 (2.9 GHz): 44 sec alatt megoldja a feladatot
    Prescott (2.26 GHz): 60 sec alatt 220000 mátrix
    Northwood (2.4 GHz): 60 sec alatt 248000 mátrix

    {@04-} { x1 } movsx ebx,byte ptr es:[edx]
    {1-} mov esi,ebp
    {2-} xor eax,eax
    {0} and esi,-8
    @init:
    {@0F} mov [edi+esi*08h+(00h*08h)+__0STARROW],eax
    {1} mov [edi+esi*08h+(04h*08h)+__0STARROW],eax
    {2*} add esi,08h
    {0*} jnz @init { clears ESI register }
    { } add edx,01h
    { -} mov ecx,ebp
    @@ARGUMENT: { K10:2.6 Core2:2.9 - 3.3 uop/clk - 1640*2+6550 }
    {@20} cmp ebx,esi { 4 AGU + 9 EX uops on Kaveri }
    {1} lea eax,[ebp+ebx*04h+00h] { 3 clk 8 ALU ops on Core 2 }
    {2} movsx ebx,byte ptr [edx]
    {0} lea edx,[edx+01h] { db $8D,$52,$00 }
    {1} mov [edi+eax*08h+__0STARROW],ebp { __0COUNTER <- EBP }
    {2} cmovs eax,esi
    {0} mov [edi+ecx*08h+__FIXEDROW],eax
    {1*} add ecx,04h
    {2*} jnz @@ARGUMENT { clears ECX register }
    { -} { x2 } xor ecx,ecx
    { -} mov eax,edi
    { -} push ebp
    {@40-} lea edx,[ebp-04h]
    @@REDUCE_ROWS:
    {@43} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1} mov esi,[edi+edx*08h+(04h*08h)+__FIXEDROW]
    {2*} add edx,04h
    {0*} jz @@REDUCE_COLUMNS
    {@50} mov [edi+edx*08h+__0STAR],esi
    {2-} xor ecx,ecx
    {0} sub eax,ebp
    {1**} test esi,esi { JS/JNS can only fuse with TEST }
    {2**} js @@REDUCE_ROWS
    { -} mov ebx,ebp { EBX < 0 for even minimum }
    { } mov ecx,[eax+ebp]
    {@61} or ecx,[edi+ebp*08h+__0STARROW]
    { } and ebp,04h
    { } add ebp,ebx
    {@69} @findrowmin: { K10:2.8 Core2:2.2 - 2.6 uop/clk - 1100*2+5000 }
    {0} mov esi,[eax+ebp] { 4 AGU + 8 EX uops on Kaveri }
    {1} or esi,[edi+ebp*08h+(00h*08h)+__0STARROW] { 3 clk 10 ALU ops on Core 2 }
    {2} add ebp,08h
    {@72} cmp esi,ebx
    {1} cmovb ebx,esi
    {2} mov esi,[eax+ebp-04h]
    {0} or esi,[edi+ebp*08h-(04h*08h)+__0STARROW]
    {1} cmp esi,ecx
    {@81} cmovb ecx,esi
    {0**} test ebp,ebp
    {1**} jnz @findrowmin
    { } mov ebp,[esp+00h]
    { } cmp ebx,ecx
    { } cmovb ecx,ebx
    {@90} neg ecx
    { } jle @@REDUCE_ROWS
    { -} { x1 } nop
    @@ABNORMAL_EXIT:
    {@95} pop eax
    {1} { x3 } or edx,0FFFFFFFFh
    {2} mov esi,[esp+__MARKS]
    {@A0} mov [esi+TRESULT.OPTIMUM],edx
    {1} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {2} jmp dword ptr [esp+_INVALIDRESULT]
    { x1 } nop
    {@AB} @init0col:
    {0} mov [edi+__INITCOL],ecx
    {1-} mov esi,ebp
    {@B0} neg ebp
    {0} mov ebx,0FFFFFFFFh
    {1*} sub ecx,04h
    {2*} jnz @@1ST_STEP { long jump instruction } { forced conditional jump for Sandy Bridge }
    {@C0} { x2 } xor eax,eax
    {@C2} @free0col:
    { } mov [edi+edx*08h+__COLMODIFIER],esi { no need to initialize __COLMODIFIER of fixed column }
    { -} mov ecx,edx
    {@C8} @next0col:
    { **} cmp edx,ebp
    { **} jz @init0col
    @@REDUCE_COLUMNS: { no need to initialize -initcol in ECX }
    {0} mov eax,[edi+edx*08h-(04h*08h)+__0STARROW]
    {@D0} sub edx,04h
    {2*} sub eax,01h
    {0*} jnc @next0col
    { } { x1 } lea ebx,es:[edi+edx]
    { -} mov ecx,ebp
    { } sub ebx,ebp
    {@E0} @findcolmin: { K10:3.0 Core2:_._ - _._ uop/clk - ____*2+____
    {0} mov esi,[ebx] { 3 AGU + 8 EX uops on Kaveri }
    {1} add esi,[edi+ecx*08h+__ROWMODIFIER] { 3 clk 9 ALU ops on Core 2 }
    {2} or esi,[edi+ecx*08h+__FIXEDROW]
    {0} jz @test0row
    {1} sub ebx,ebp
    {2} cmp esi,eax
    {@F0} cmovb eax,esi
    {1*} add ecx,04h
    {2*} jnz @findcolmin
    { } lea ecx,[ebp-04h]
    { -} mov esi,eax
    { } lea ebx,[edi+edx]
    {@00**} test eax,eax { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@04} @seekcol0:
    {0} mov eax,[edi+ecx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ecx,04h
    {2*} jz @free0col
    {0} sub ebx,ebp
    {1} add eax,[ebx]
    {@11**} cmp eax,esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {0**} jnz @seekcol0
    @test0row:
    { **} test [edi+ecx*08h+__0STAR],ebp { JS/JNS can only fuse with TEST }
    { **} js @seekcol0
    { } mov [edi+edx*08h+__0STARROW],ecx
    {@1E} mov [edi+ecx*08h+__0STAR],edx
    {@22} jns @free0col { forced conditional jump for Sandy Bridge }
    { ----------------------------------------------------------------------------------------------- }
    {@24} { x12 } mov eax,00000000h; mov edx,00000000h; xor ecx,ecx
    {@30} { x5 } mov esi,00000000h
    @@5TH_STEP: { K10:2.2 Core2:2.2 - 2.7 uop/clk - 3050*2+3700 }
    {@35} movsx esi,word ptr [edi+__MINCOLROW+00h]
    { } sub ebx,ebp
    { } movsx eax,word ptr [edi+ebx*08h+__SIGN-(04h*08h)+__COLMARK]
    {@40} @5th_step: { 5 AGU + 11 EX uops on Kaveri }
    {0} movsx ecx,word ptr [edi+ebx*08h+__SIGN+__0COLON___ROWMARK] { 4 clk 6 ALU ops on Core 2 }
    {1} mov [edi+ebx*08h-(04h*08h)+__COLMARK],eax
    {2} and eax,edx
    {0} add [edi+ebx*08h+__COLMODIFIER],eax
    {@4F} and ecx,edx
    {2} movsx eax,word ptr [edi+ebx*08h+__SIGN-(04h*08h)+(04h*08h)+__COLMARK] { __MINCOLROW col }
    {0} add [edi+ebx*08h+__ROWMODIFIER],ecx
    {1*} add ebx,04h
    {2*} jnz @5th_step { clears EBX register }
    {@5F} mov ecx,[edi+__INITCOL]
    {1-} mov edx,esi
    {2} mov esi,[edi+esi*08h+__0STAR]
    {0**} test esi,esi
    {1**} jz @@4TH_STEP { long jump instruction }
    {@70} mov [edi+edx*08h+__0COLON___ROWMARK],eax { set row mark }
    {0} mov dword ptr [edi+esi*08h-(04h*08h)+__COLMARK],-1 { unmark column with -1 }
    {1} jmp @test2col
    { x2 } xor esi,esi
    {@80} { x2 } xor eax,eax
    {@82} @fast2forward:
    { *} add ebx,04h
    { *} jnz @continue
    {@87} @pass2col:
    { } mov [edi+ecx*08h-(04h*08h)+__COLMARK],ecx { re-mark column with its index != -1 }
    {@8B} @next2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP { clears ECX register }
    @test2col:
    {@90**} cmp [edi+ecx*08h-(04h*08h)+__COLMARK],ecx
    {0**} jbe @next2col
    @@2ND_STEP:
    { } sub ebx,ebp { ordered for Core2 }
    { } lea eax,[ecx+edi] { ordered for Core2 }
    {@9B} @continue:
    { } mov esi,[edi+ecx*08h+__COLMODIFIER]
    { } push esi
    {@A0} sal ecx,10h
    { } mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {@A7} @ZERO2col: { K10:3.0 Core2:2.5 - 2.9 uop/clk - 1500*2+5600 { 4 AGU + 11 EX uops on Kaveri }
    {0} sub esi,[esp+00h] { 4 clk 13 ALU ops on Core 2 }
    {1} add esi,[eax+ebp]
    {2} lea eax,[eax+ebp]
    {@B0} jo @over2flow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {1} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {2} jz @@3RD_STEP
    {0} cmp esi,edx
    {1} cmovb edx,esi
    {2} cmovb cx,bx
    {@C1} @over2flow:
    {0} mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ebx,04h
    {2*} jnz @ZERO2col { clears EBX register }
    @@3RD_STEP:
    {@CA} pop esi { add esp,04h } { enforces ESP tracking to AGU/load pipe on Bulldozer/Core }
    {1-} mov esi,ecx
    {2} sar ecx,10h
    {@D0} cmovnc esi,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],esi
    {2**} { x1 } cmp ebx,00h
    {0**} jz @pass2col
    {1} mov esi,[edi+ebx*08h+__0STAR]
    {@E0**} test esi,esi
    {0**} jz @4TH_STEP
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2} mov dword ptr [edi+esi*08h-(04h*08h)+__COLMARK],-1 { unmark column with -1 }
    {@F0**} cmp word ptr [edi+__MINCOLROW],bx { STORE FORWARDED }
    {1**} jz @re2start
    {2**} cmp esi,ecx { jb = jl for 2 negative numbers }
    {0**} jae @fast2forward
    {1-} xor ebx,ebx
    {2-} mov ecx,esi
    {0} jmp @@2ND_STEP
    {@00} @re2start:
    {0} mov ecx,[edi+__INITCOL]
    {1-} mov edx,ebx
    {2-} mov ebx,ebp
    {0} neg ebx
    {@09} @init2col:
    {0} movsx eax,word ptr [edi+ebx*08h+__SIGN-(04h*08h)+__COLMARK]
    {1} mov [edi+ebx*08h-(04h*08h)+__COLMARK],eax
    {2*} add ebx,04h
    {0*} jnz @init2col { clears EBX register }
    { } jmp @test2col { long jump instruction }
    { } { x4 } lea eax,[ebp+ebp+00h]
    {@20} { x2 } test edi,edi
    @@4TH_STEP:
    {@22-} mov ecx,eax
    @re4order:
    {@24-} mov ebx,edx
    @4TH_STEP:
    {@26} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {@30} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {2**} { x1 } cmp edx,00h
    {0**} jnz @re4order { clears EDX register }
    { } sub esi,ebp
    { } sub edx,ebp
    { } lea ecx,[esi-04h]
    @@1ST_STEP: { K10:2.8 Core2:2.9 - 3.2 uop/clk - 1500*2+6100 }
    {@40} mov eax,[edi+esi*08h+__0STARROW] { 4 AGU + 7 EX uops on Kaveri }
    {1} and ebx,eax { clears EBX at uncomplete calculation } { 3 clk 6 ALU ops on Core 2 }
    {2} not eax
    {0} mov [edi+esi*08h-(04h*08h)+__COLMARK],eax
    {1} mov eax,[edi+esi*08h+__FIXEDROW]
    {2} cmovs ecx,esi
    {0} mov [edi+esi*08h+__0COLON___ROWMARK],eax
    {1*} add esi,04h
    {2*} jnz @@1ST_STEP { clears ESI register [NOT USED] }
    { *} add ecx,04h { long jump instruction }
    { *} jnz @@2ND_STEP { ===>>> EBX: 00h EDX:negative = -EBP ECX:initcol (>= EBP) }
    { -} mov ebx,edi { work matrix unmodified } { [esp+__SAVE] }
    { } mov esi,[esp+04h+__MARKS]
    @@results:
    {@6A} mov eax,[edi+edx*08h+__0STAR] { 3 AGU + 8 EX uops on Kaveri }
    {1} add ebx,ebp
    {@70} add ecx,[ebx+eax]
    {0} add eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {0} add esi,01h
    {1*} add edx,04h
    {@80*} jnz @@results { clears EDX register ( DL=0 as head, DH=0 as length ) }

  • P.H.

    senior tag

    Több, mint 1 Kbyte-os (1124 karakter) Java utasítás: arg egész pozitív számot szöveggé konvertálja dest tömbbe i pozíciótól kezdődően, legfejlebb size karakter méretben; 0-k helyett space-ekkel felvezetve, ha a szám kevesebb karakterből áll, mint size.

    public static byte[] inttoSPACEstr(int arg, int size, int i, byte[] dest) {
    int x, j, nr, z;


    dest[(i=(i=(i=(i=(i=(i=(i=(
    i+=((dest[i]=(byte)((((z =(j=((nr=1+(int)(((x=(int)(((arg=(arg^(x=arg>>31))-x)*0x00000000A7C5AC47L)>>>32)>>>16)*0x00000000D1B71759L)>>>30))>>>15)))-1)&0xFFFFFFF0)+j+48)) | (10-1-size))>>>31)
    +(((dest[i]=(byte)((((z|=(j=((nr=(nr&0x00007FFF)*5)>>>14)))-1)&0xFFFFFFF0)+j+48)) | (10-2-size)) >>>31))
    +(((dest[i]=(byte)((((z|=(j=((nr=(nr&0x00003FFF)*5)>>>13)))-1)&0xFFFFFFF0)+j+48)) | (10-3-size)) >>>31))
    +(((dest[i]=(byte)((((z|=(j=((nr=(nr&0x00001FFF)*5)>>>12)))-1)&0xFFFFFFF0)+j+48)) | (10-4-size)) >>>31))
    +(((dest[i]=(byte)((((z|=(j=(( (nr&0x00000FFF)*5)>>>11)))-1)&0xFFFFFFF0)+j+48)) | (10-5-size)) >>>31))
    +(((dest[i]=(byte)((((z|=(j=((nr=1+((int)(((arg-x*100000)*0x00000000D1B71759L)>>>30)))>>>15)))-1)&0xFFFFFFF0)+j+48)) | (10-6-size)) >>>31))
    +(((dest[i]=(byte)((((z|=(j=((nr=(nr&0x00007FFF)*5)>>>14)))-1)&0xFFFFFFF0)+j+48)) | (10-7-size)) >>>31))
    +(((dest[i]=(byte)((((z|=(j=((nr=(nr&0x00003FFF)*5)>>>13)))-1)&0xFFFFFFF0)+j+48)) | (10-8-size)) >>>31))
    +(((dest[i]=(byte)((((z| (j=((nr=(nr&0x00001FFF)*5)>>>12)))-1)&0xFFFFFFF0)+j+48)) | (10-9-size)) >>>31)]
    =(byte)((((nr&0x00000FFF)*5)>>>11)+48);


    return dest; }

  • P.H.

    senior tag

    válasz P.H. #102 üzenetére

    Core2 (2.5 GHz): 59 sec alatt megoldja a feladatot
    K10 (2.9 GHz): Core2-nek tetsző ciklusverzióval 46 sec oldja meg a feladatot
    Prescott (2.26 GHz): 60 sec alatt 220000 mátrix

    {@04-} { x1 } movsx ebx,byte ptr es:[edx]
    {1-} xor eax,eax
    {2-} mov esi,ebp
    {0} and esi,-8
    @init:
    {@0F} mov [edi+esi*08h+(00h*08h)+__0STARROW],eax
    {1} mov [edi+esi*08h+(04h*08h)+__0STARROW],eax
    {2*} add esi,08h
    {0*} jnz @init { clears ESI register }
    { } add edx,01h
    { -} mov ecx,ebp
    @@ARGUMENT: { K10:2.6 Core2:2.9 - 3.3 uop/clk - 1640*2+6550 }
    {@20} cmp ebx,esi { 4 AGU + 9 EX uops on Kaveri }
    {1} lea eax,[ebp+ebx*04h+00h] { 3 clk 8 ALU ops on Core 2 }
    {2} movsx ebx,[edx]
    {0} lea edx,[edx+01h]
    {1} mov [edi+eax*08h+__0STARROW],ebp { __0COUNTER <- EBP }
    {2} cmovs eax,esi
    {0} mov [edi+ecx*08h+__FIXEDROW],eax
    {1*} add ecx,04h
    {2*} jnz @@ARGUMENT { clears ECX register }
    { -} { x2 } xor ecx,ecx
    { -} mov eax,edi
    { -} push ebp
    {@40-} lea edx,[ebp-04h]
    @@REDUCE_ROWS:
    {@43} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1} mov esi,[edi+edx*08h+(04h*08h)+__FIXEDROW]
    {2*} add edx,04h
    {0*} jz @@REDUCE_COLUMNS
    {@50} mov [edi+edx*08h+__0STAR],esi
    {2-} xor ecx,ecx
    {0} sub eax,ebp
    {1**} test esi,esi { JS/JNS can only fuse with TEST }
    {2**} js @@REDUCE_ROWS
    { -} mov ebx,ebp { EBX < 0 for even minimum }
    { } mov ecx,[eax+ebp]
    {@61} or ecx,[edi+ebp*08h+__0STARROW]
    { } and ebp,04h
    { } add ebp,ebx
    {@69} @findrowmin: { K10:2.8 Core2:2.2 - 2.6 uop/clk - 1100*2+5000 }
    {0} mov esi,[eax+ebp+00h] { 4 AGU + 8 EX uops on Kaveri }
    {1} or esi,[edi+ebp*08h+(00h*08h)+__0STARROW] { 3 clk 10 ALU ops on Core 2 }
    {2} add ebp,08h
    {@72} cmp esi,ebx
    {1} cmovb ebx,esi
    {2} mov esi,[eax+ebp-04h]
    {0} or esi,[edi+ebp*08h-(04h*08h)+__0STARROW]
    {1} cmp esi,ecx
    {@81} cmovb ecx,esi
    {0**} test ebp,ebp
    {1**} jnz @findrowmin
    { } mov ebp,[esp+00h]
    { } cmp ebx,ecx
    { } cmovb ecx,ebx
    {@90} neg ecx
    { } jle @@REDUCE_ROWS
    { -} nop
    @@ABNORMAL_EXIT:
    {@95} pop eax
    {1} or edx,-1
    {2} mov esi,[esp+__MARKS]
    {0} mov [esi+TRESULT.OPTIMUM],edx
    {@A0} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {2} jmp dword ptr [esp+_INVALIDRESULT]
    { } { x6 } test ebp,0FFFFFFFFh
    {@AD} @init0col:
    {0} mov [edi+__INITCOL],ecx
    {@B0-} mov esi,ebp
    {2} neg ebp
    {0} or ebx,-1
    {1*} sub ecx,04h
    {2*} jnz @@1ST_STEP { long jump instruction } { forced conditional jump for Sandy Bridge }
    {@C0} { x3 } cmp ebp,00h
    {@C3} @free0col:
    { -} mov ecx,edx
    {@C5} @setcolmod:
    { } mov [edi+edx*08h+__COLMODIFIER],esi
    @@REDUCE_COLUMNS: { no need to initialize -initcol in ECX }
    {0**} cmp edx,ebp
    {1**} jz @init0col
    {0} sub edx,04h
    {@D0-} xor esi,esi
    {1**} test [edi+edx*08h+__0STARROW],ebp
    {2**} js @setcolmod
    { } lea ebx,[edi+edx]
    { -} mov ecx,ebp
    { -} mov eax,ebp
    { } sub ebx,ebp
    {@E0} @findcolmin: { K10:3.0 Core2:_._ - _._ uop/clk - ____*2+____
    {0} mov esi,[ebx] { 3 AGU + 8 EX uops on Kaveri }
    {1} add esi,[edi+ecx*08h+__ROWMODIFIER] { 3 clk 9 ALU ops on Core 2 }
    {2} or esi,[edi+ecx*08h+__FIXEDROW]
    {0} jz @test0row
    {1} sub ebx,ebp
    {2} cmp esi,eax
    {@F0} cmovb eax,esi
    {1*} add ecx,04h
    {2*} jnz @findcolmin
    { } lea ecx,[ebp-04h]
    { -} mov esi,eax
    { } lea ebx,[edi+edx]
    {@00**} test eax,eax { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@04} @seekcol0:
    {0} mov eax,[edi+ecx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ecx,04h
    {2*} jz @free0col
    {0} sub ebx,ebp
    {1} add eax,[ebx]
    {@11**} cmp eax,esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {0**} jnz @seekcol0
    @test0row:
    { **} test [edi+ecx*08h+__0STAR],ebp
    { **} js @seekcol0
    { } mov [edi+edx*08h+__0STARROW],ecx
    {@1E} mov [edi+ecx*08h+__0STAR],edx
    {@22} jns @free0col { forced conditional jump for Sandy Bridge }
    { ----------------------------------------------------------------------------------------------- }
    {@24} { x12 } test ebp,0FFFFFFFFh; test edi,0FFFFFFFFh
    {@30} { x9 } mov ecx,00000000h; xor esi,esi; xor edi,edi
    @@5TH_STEP: { K10:2.6 Core2:_._ - _._ uop/clk - ____*2+____
    {@39} mov ecx,[edi+__MINCOLROW]
    { } sub ebx,ebp
    { } neg edx
    {@40} @DEC5_free_col: { 5 AGU + 11 EX uops on Kaveri }
    {0} mov eax,[edi+ebx*08h+__COLMARK] { 3 clk 8 ALU ops on Core 2 }
    {1} sar eax,1Fh
    {2} mov [edi+ebx*08h+__COLMARK],eax
    {0} and eax,edx
    {1} sub [edi+ebx*08h+__COLMODIFIER],eax
    {@51} mov eax,[edi+ebx*08h+__0COLON___ROWMARK]
    {0} sar eax,1Fh
    {1} and eax,edx
    {2} sub [edi+ebx*08h+__ROWMODIFIER],eax
    {0*} add ebx,04h
    {@61*} jnz @DEC5_free_col { clears EBX register [NOT USED] }
    {@63} movsx ebx,cx
    {1} sar ecx,10h
    {2} mov esi,[edi+ebx*08h+__0STAR]
    {0**} cmp esi,00h
    {@70**} jz @4TH_STEP { long jump instruction }
    {2} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {0} mov dword ptr [edi+esi*08h+__COLMARK],0FFFFFFFFh { unmark column with -1 }
    {1} mov esi,[edi+__INITCOL]
    {@85} @mark3row:
    { -} xor ebx,ebx
    { } lea ecx,[esi-04h]
    { } jmp @chk2col
    @pass2col:
    { } mov [edi+ecx*08h+__COLMARK],ecx { re-mark column with column index <> -1 }
    {@90} @chk2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP { clears ECX register }
    {2**} cmp [edi+ecx*08h+__COLMARK],ecx
    {0**} jbe @chk2col
    @@2ND_STEP:
    { } lea eax,[ecx+edi]
    { } sub ebx,ebp
    @continue:
    {@A0} { x1 } push dword ptr es:[edi+ecx*08h+__COLMODIFIER]
    { } sal ecx,10h
    { } mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {@AC} @ZERO2col: { K10:3.0 Core2:2.5 - 2.9 uop/clk - 1500*2+5600 { 4 AGU + 11 EX uops on Kaveri }
    {0} sub esi,[esp+00h] { 4 clk 13 ALU ops on Core 2 }
    {@AF} add esi,[eax+ebp]
    {C2D} lea eax,[eax+ebp]
    {2} jo @over2flow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {0} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {1} jz @@3RD_STEP
    {K10}// lea eax,[eax+ebp]
    {0} cmp esi,edx
    {@BF} cmovb edx,esi
    {@C2} cmovb cx,bx
    @over2flow:
    {0} mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ebx,04h
    {2*} jnz @ZERO2col { clears EBX register }
    @@3RD_STEP:
    {@CF} pop esi { add esp,04h } { enforces ESP handling to AGU/load pipe on Kaveri/Core }
    {@D0-} mov esi,ecx
    {2} sar ecx,10h
    {0} cmovnc esi,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],esi
    {2**} test ebx,ebx
    {0**} jz @pass2col
    {@E0} mov esi,[edi+ebx*08h+__0STAR]
    {2**} test esi,esi
    {0**} jz @4TH_STEP
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2} or dword ptr [edi+esi*08h+__COLMARK],-1 { unmark column with -1 }
    {@F1**} cmp word ptr [edi+__MINCOLROW],bx
    {1**} jz @re2start
    {2**} cmp esi,ecx { jb = jl for 2 negative numbers }
    {0**} jb @mark3row
    {1*} add ebx,04h
    {2*} jnz @continue
    {@00} jmp @pass2col
    {1} { x2 } xor eax,eax
    {@04} @re2start:
    {0} mov ecx,[edi+__INITCOL]
    {1-} mov ebx,ebp
    {2} neg ebx
    @initcol:
    {0} sar dword ptr [edi+ebx*08h+__COLMARK],1Fh
    {@10*} add ebx,04h
    {2*} jnz @initcol { clears EBX register }
    { } or edx,-1
    { *} sub ecx,04h
    { *} jnz @chk2col { long jump instruction }
    {@20} { x4 } lea eax,[ebp+ebp+00h]
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@24-} mov ebx,edx { 2 clk 2 ALU ops on Core 2 }
    @4TH_STEP:
    {@26} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {@30} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {2**} cmp edx,00h
    {0**} jnz @@4TH_STEP { clears EDX register }
    { } sub esi,ebp
    { } sub edx,ebp
    { } lea ecx,[esi-04h]
    @@1ST_STEP: { K10:2.8 Core2:2.9 - 3.2 uop/clk - 1500*2+6100 }
    {@40} mov eax,[edi+esi*08h+__0STARROW] { 4 AGU + 7 EX uops on Kaveri }
    {1} and ebx,eax { 3 clk 6 ALU ops on Core 2 }
    {2} not eax
    {0} mov [edi+esi*08h+__COLMARK],eax
    {1} mov eax,[edi+esi*08h+__FIXEDROW]
    {2} cmovs ecx,esi
    {0} mov [edi+esi*08h+__0COLON___ROWMARK],eax
    {1*} add esi,04h
    {2*} jnz @@1ST_STEP { clears ESI register }
    { } { x3 } mov ebx,00000000h
    {@60*} add ecx,04h { long jump instruction }
    { *} jnz @@2ND_STEP { ===>>> EBX: 00h EDX:negative = -EBP ECX:initcol (>= EBP) }
    { } { x1 } mov esi,ss:[esp+04h+__MARKS]
    { -} mov ebx,edi { work matrix unmodified } { [esp+__SAVE] }
    @@results:
    {@70} mov eax,[edi+edx*08h+__0STAR] { 3 AGU + 8 EX uops on Kaveri }
    {1} add ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} add eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@80} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results { clears EDX register ( DL=0 as head, DH=0 as length ) }

  • P.H.

    senior tag

    válasz P.H. #101 üzenetére

    Eheti 1000-mátrix-hetente rovat :)

    Core2 (2.5 GHz): 60 sec alatt 510000 mátrix

    {@04-} { x1 } movsx ebx,byte ptr es:[edx]
    {1-} xor eax,eax
    {2-} mov esi,ebp
    {0} and esi,-8
    @init:
    {@0F} mov [edi+esi*08h+(00h*08h)+__0STARROW],eax
    {1} mov [edi+esi*08h+(04h*08h)+__0STARROW],eax
    {2*} add esi,08h
    {0*} jnz @init { clears ESI register }
    { } add edx,01h
    { -} mov ecx,ebp
    @@ARGUMENT: { K10:2.6 Core2:2.9 - 3.3 uop/clk - 1640*2+6550 }
    {@20} cmp ebx,esi { 4 AGU + 9 EX uops on Kaveri }
    {1} lea eax,[ebp+ebx*04h+00h] { 3 clk 8 ALU ops on Core 2 }
    {2} movsx ebx,[edx]
    {0} lea edx,[edx+01h]
    {1} mov [edi+eax*08h+__0STARROW],ebp { __0COUNTER <- EBP }
    {2} cmovs eax,esi
    {0} mov [edi+ecx*08h+__FIXEDROW],eax
    {1*} add ecx,04h
    {2*} jnz @@ARGUMENT { clears ECX register }
    { } add esp,ebp
    { -} mov eax,edi
    { -} push ebp
    {@40-} lea edx,[ebp-04h]
    @@REDUCE_ROWS:
    {@43} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1} mov esi,[edi+edx*08h+(04h*08h)+__FIXEDROW]
    {2*} add edx,04h
    {0*} jz @@REDUCE_COLUMNS
    {@50} mov [edi+edx*08h+__0STAR],esi
    {2-} xor ecx,ecx
    {0} sub eax,ebp
    {1**} test esi,esi { JS/JNS can only fuse with TEST }
    {2**} js @@REDUCE_ROWS
    { -} mov ebx,ebp { EBX < 0 for even minimum }
    { } mov ecx,[eax+ebp]
    {@61} or ecx,[edi+ebp*08h+__0STARROW]
    { } and ebp,04h
    { } add ebp,ebx
    {@69} @findrowmin: { K10:2.8 Core2:2.2 - 2.6 uop/clk - 1100*2+5000 }
    {0} mov esi,[eax+ebp+00h] { 4 AGU + 8 EX uops on Kaveri }
    {1} or esi,[edi+ebp*08h+(00h*08h)+__0STARROW] { 3 clk 10 ALU ops on Core 2 }
    {2} add ebp,08h
    {@72} cmp esi,ebx
    {1} cmovb ebx,esi
    {2} mov esi,[eax+ebp-04h]
    {0} or esi,[edi+ebp*08h-(04h*08h)+__0STARROW]
    {1} cmp esi,ecx
    {@81} cmovb ecx,esi
    {0**} test ebp,ebp
    {1**} jnz @findrowmin
    { } mov ebp,[esp+00h]
    { } cmp ebx,ecx
    { } cmovb ecx,ebx
    {@90} neg ecx
    { } jle @@REDUCE_ROWS
    @@ABNORMAL_EXIT:
    {@94} pop eax
    {1} sub esp,ebp
    {2} mov edx,0FFFFFFFFh
    {0} mov esi,[esp+__MARKS]
    {@A0} mov [esi+TRESULT.OPTIMUM],edx
    {2} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {0} jmp dword ptr [esp+_INVALIDRESULT]
    { } { x6 } test ebp,0FFFFFFFFh
    {@90} @initcol:
    {0} neg dword ptr [esp+00h]
    {1-} mov esi,ebp
    {2} neg ebp
    {0} mov [edi+__INITCOL],ecx
    {1} or ebx,-1
    {2} jmp @@1ST_STEP { long jump instruction }
    {@A2} @free0col:
    { } lea ecx,[edx-04h]
    {@A5} @setcolmod:
    { } mov [edi+edx*08h+__COLMODIFIER],esi
    @@REDUCE_COLUMNS:
    {1**} jz @initcol
    {0} sub edx,04h
    {@B0-} xor esi,esi
    {1**} test [edi+edx*08h+__0STARROW],ebp
    {2**} js @setcolmod
    { } lea ebx,[edi+edx]
    { -} mov ecx,ebp
    { -} mov eax,ebp
    { } sub ebx,ebp
    {@C0} @findcolmin: { K10:3.0 Core2:_._ - _._ uop/clk - ____*2+____
    {0} mov esi,[ebx] { 3 AGU + 8 EX uops on Kaveri }
    {1} add esi,[edi+ecx*08h+__ROWMODIFIER] { 3 clk 9 ALU ops on Core 2 }
    {2} or esi,[edi+ecx*08h+__FIXEDROW]
    {0} jz @test0row
    {1} sub ebx,ebp
    {2} cmp esi,eax
    {@D0} cmovb eax,esi
    {1*} add ecx,04h
    {2*} jnz @findcolmin
    { } lea ecx,[ebp-04h]
    { -} mov esi,eax
    { } lea ebx,[edi+edx]
    {@E0**} test eax,eax { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@E4} @seekcol0:
    {0} mov eax,[edi+ecx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ecx,04h
    {2*} jz @free0col
    {0} sub ebx,ebp
    {1} add eax,[ebx]
    {@F1**} cmp eax,esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {0**} jnz @seekcol0
    @test0row:
    { **} test [edi+ecx*08h+__0STAR],ebp
    { **} js @seekcol0
    { } mov [edi+edx*08h+__0STARROW],ecx
    {@FE} mov [edi+ecx*08h+__0STAR],edx
    {@02} jns @free0col { forced conditional jump for Sandy Bridge }
    { ----------------------------------------------------------------------------------------------- }
    {@04} { x12 } mov eax,00000000h; mov edx,00000000h; xor ebp,ebp
    {@10} { x5 } mov ecx,00000000h
    @@5TH_STEP: { K10:2.6 Core2:2.4 - 2.8 uop/clk - 2000*2+5100
    {@15} mov eax,[edi+__INITCOL] { lea eax,[ebp+04h]; neg eax }
    {1} mov esi,[esp+__SIZE]
    {2} movsx ebx,word ptr [edi+__MINCOLROW]
    {@20} @DEC5_free_col: { 3 AGU + 6 EX uops on Kaveri }
    {0} add [edi+eax*08h+__COLMODIFIER],ecx { 2 clk 5 ALU ops on Core 2 }
    {1} mov ecx,[edi+eax*08h+(04h*08h)+__COLMARK]
    {2} sar ecx,1Fh
    {0} and ecx,edx
    {1*} add eax,04h
    {@30*} jnz @DEC5_free_col { clears EAX register [NOT USED] }
    { } mov eax,[esp+__SIZE+esi*04h]
    { } movsx ecx,word ptr [edi+__MINCOLROW+02h]
    { } jmp @INC5_marked_row
    { x4 } xor ebp,ebp; xor esi,esi
    {@40} @inc5row:
    {0} add [edi+eax*08h+__ROWMODIFIER],edx { 4 AGU + 4 EX uops on Kaveri }
    {1-} mov eax,ebp
    @INC5_marked_row:
    {2} mov ebp,[esp+esi*04h]
    {0*} sub esi,01h
    {1*} jge @inc5row { sets ESI to 0FFFFFFFFh }
    @@3RD_STEP:
    {@4E*} and esi,[edi+ebx*08h+__0STAR]
    {@52*} jz @4TH_STEP { long jump instruction }
    {@58} @re3start:
    { } mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    { } { x1 } mov ecx,es:[edi+__INITCOL] { lea ecx,es:[ebp-04h] }
    {@60-} mov edx,ebx
    {@62} @mark3row:
    { } mov [esp+__OFFS+eax*04h],ebx
    { -} xor ebx,ebx
    { } mov [edi+esi*08h+__COLMARK],esi { unmark column with negative }
    { } inc eax
    { } mov [esp+__SIZE],eax
    {@71} @chk2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP { clears ECX register }
    {2**} test [edi+ecx*08h+__COLMARK],ecx { STORE FORWARDED from @mark3row }
    {0**} jns @chk2col
    @@2ND_STEP:
    {12} push dword ptr [edi+ecx*08h+__COLMODIFIER]
    {@80} lea eax,[ecx+edi]
    { } sub ebx,ebp
    { } sal ecx,10h
    { } mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {@8C} @ZERO2col: { K10:3.0 Core2:2.5 - 2.9 uop/clk - 1500*2+5600 { 4 AGU + 11 EX uops on Kaveri }
    {0} sub esi,[esp+00h] { 4 clk 13 ALU ops on Core 2 }
    {@8F} add esi,[eax+ebp]
    {C2D} lea eax,[eax+ebp] { Core 2, Kaveri }
    {2} jo @over2flow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {0} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {1} jz @zero
    {K10}// lea eax,[eax+ebp] { K10, Sandy Bridge, Ivy Bridge }
    {0} cmp esi,edx
    {@9F} cmovb edx,esi
    {@A2} cmovb cx,bx
    @over2flow:
    {0} mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ebx,04h
    {2*} jnz @ZERO2col { clears EBX register }
    {@AF} @zero:
    {0} pop eax { add esp,04h } { forces ESP handling to AGU/memory pipe on Kaveri/Core }
    {@B0-} mov eax,ecx
    {2} sar ecx,10h
    {0} cmovnc eax,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],eax
    {2**} test ebx,ebx
    {0**} jz @chk2col
    {@C0*} add esi,[edi+ebx*08h+__0STAR] { zero found -> ESI=0 }
    {2*} jz @4TH_STEP
    {0} cmp ax,bx
    {1} { x1 } mov eax,ss:[esp+__SIZE]
    {2} jz @re3start
    {@D0} cmp esi,ecx
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2} cmovl ecx,esi
    {0*} sub ecx,04h { never clears ECX register }
    {1*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    { x2 } xor esi,esi
    {@E0} { x4 } lea eax,[ebp+ebp+00h]
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@E4-} mov ebx,edx { 2 clk 2 ALU ops on Core 2 }
    @4TH_STEP:
    {@E6} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {@F0} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {2**} cmp edx,00h
    {0**} jnz @@4TH_STEP { clears EDX register }
    { } sub esi,ebp
    { } sub edx,ebp
    { } lea ecx,[esi-04h] { mov ecx,[edi+__INITCOL] }
    @@1ST_STEP: { K10:2.8 Core2:2.9 - 3.2 uop/clk - 1500*2+6100 }
    {@00} mov eax,[edi+esi*08h+__0STARROW] { 4 AGU + 7 EX uops on Kaveri }
    {1} and ebx,eax { 3 clk 6 ALU ops on Core 2 }
    {2} not eax
    {0} mov [edi+esi*08h+__COLMARK],eax
    {1} mov eax,[edi+esi*08h+__FIXEDROW]
    {2} cmovs ecx,esi
    {0} mov [edi+esi*08h+__0COLON___ROWMARK],eax
    {1*} add esi,04h
    {2*} jnz @@1ST_STEP { clears ESI register }
    { } mov [esp+__SIZE],esi
    { -} xor ebx,ebx
    {@21*} add ecx,04h { long jump instruction }
    { *} jnz @@2ND_STEP { ===>>> EBX: 00h EDX:negative ECX:initcol (>= EBP) }
    { } mov esi,[esp+ebp+04h+__MARKS]
    { -} mov ebx,edi { work matrix unmodified } { [esp+__SAVE] }
    @@results:
    {@30} mov eax,[edi+edx*08h+__0STAR] { 3 AGU + 8 EX uops on Kaveri }
    {1} add ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} add eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@40} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results { clears EDX register ( DL=0 as head, DH=0 as length ) }
    {0} pop eax
    {1} add esp,ebp
    {2} neg ebp
    {0} or eax,-1
    {@50} lea ebx,[edi+ebp*04h]
    {1} sar ebp,02h
    {2} mov [esi+ebp+TRESULT.OPTIMUM],ecx
    {0} add esi,ebp
    {1-} xor ecx,ecx
    {2} jmp @onchain

  • P.H.

    senior tag

    Továbbra is egy szálas program.

    Core2 (2.5 GHz): 60 sec alatt 507000 mátrix
    Sandy Bridge (G1620 2.7 GHz): a K10-es ciklusverzióval 59 sec, a Core2-essel 60 sec

    Akkor is meg fogja oldani 2500 MHz-en bármely Core egy szálon ezt a feladatot; ha kell, fél évig mászok fel hetente 1000 mátrixot, de meg fogja.

    {@04-} { x1 } movsx ecx,byte ptr es:[edx]
    {1-} xor eax,eax
    {2-} mov esi,ebp
    {0} and esi,-8
    @init:
    {@0F} mov [edi+esi*08h+(00h*08h)+__0STARROW],eax
    {1} mov [edi+esi*08h+(04h*08h)+__0STARROW],eax
    {2*} add esi,08h
    {0*} jnz @init { clears ESI register }
    { } add edx,01h
    { -} mov ebx,ebp
    @@ARGUMENT: { K10:2.6 Core2:2.9 - 3.3 uop/clk - 1640*2+6550 }
    {@20} cmp ecx,esi { 4 AGU + 9 EX uops on Kaveri }
    {1} lea eax,[ebx+ecx*04h] { 3 clk 8 ALU ops on Core 2 }
    {2} movsx ecx,[edx]
    {0} lea edx,[edx+01h] { db $8D,$52,$00 }
    {1} mov [edi+eax*08h+__0STARROW],ebx { __0COUNTER <- EBP }
    {2} cmovs eax,esi
    {0} mov [edi+ebp*08h+__FIXEDROW],eax
    {1*} add ebp,04h
    {2*} jnz @@ARGUMENT { clears EBP register }
    { -} mov eax,edi
    { -} mov ebp,ebx
    { -} xor ecx,ecx
    {@40} add esp,ebx
    { } lea edx,[ebx-04h]
    @@REDUCE_ROWS:
    {@45} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1} mov esi,[edi+edx*08h+(04h*08h)+__FIXEDROW]
    {2*} add edx,04h
    {0*} jz @@REDUCE_COLUMNS
    {1} mov [edi+edx*08h+__0STAR],esi
    {2-} xor ecx,ecx
    {0} sub eax,ebp
    {1**} test esi,esi
    {2**} js @@REDUCE_ROWS
    {0-} mov ecx,ebp
    {@60} @findrowmin: { 2 AGU + 5 EX uops on Kaveri }
    {0} mov esi,[eax+ebx] { 2 clk 6 ALU ops on Core 2 }
    {1} or esi,[edi+ebx*08h+__0STARROW]
    {2} cmp esi,ecx
    {0} cmovb ecx,esi
    {1*} add ebx,04h
    {2*} jnz @findrowmin
    {@70-} mov ebx,ebp
    { } neg ecx
    { } jle @@REDUCE_ROWS
    @@ABNORMAL_EXIT:
    {@76} or edx,0FFFFFFFFh
    {1} sub esp,ebp
    {@7E} mov esi,[esp+__MARKS]
    {0} mov [esi+TRESULT.OPTIMUM],edx
    {1} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {2} jmp dword ptr [esp+_INVALIDRESULT]
    { x4 } xor eax,eax; xor edx,edx
    {@90} @initcol:
    {0} mov [edi+__INITCOL],ecx
    {1-} mov esi,ebp
    {2} neg ebp
    {0} push ebp
    {1} or ebx,-1
    {2} jmp @@1ST_STEP { long jump instruction }
    {@A0} { x2 } xor eax,eax
    {@A2} @free0col:
    { } lea ecx,[edx-04h]
    {@A5} @setcolmod:
    { } mov [edi+edx*08h+__COLMODIFIER],esi
    @@REDUCE_COLUMNS: { no need to initialize -initcol in ECX }
    {0**} cmp edx,ebp
    {1**} jz @initcol
    {0} sub edx,04h
    {@B0-} xor esi,esi
    {1**} test [edi+edx*08h+__0STARROW],ebp
    {2**} js @setcolmod
    { } lea ebx,[edi+edx]
    { -} mov ecx,ebp
    { -} mov eax,ebp
    { } sub ebx,ebp
    {@C0} @findcolmin:
    {0} mov esi,[ebx] { 3 AGU + 8 EX uops on Kaveri }
    {1} add esi,[edi+ecx*08h+__ROWMODIFIER] { 3 clk 9 ALU ops on Core 2 }
    {2} or esi,[edi+ecx*08h+__FIXEDROW]
    {0} jz @test0row
    {1} sub ebx,ebp
    {2} cmp esi,eax
    {@D0} cmovb eax,esi
    {1*} add ecx,04h
    {2*} jnz @findcolmin
    { } lea ecx,[ebp-04h]
    { -} mov esi,eax
    { } lea ebx,[edi+edx]
    {@E0**} test eax,eax { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@E4} @seekcol0:
    {0} mov eax,[edi+ecx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ecx,04h
    {2*} jz @free0col
    {0} sub ebx,ebp
    {1} add eax,[ebx]
    {@F1**} cmp eax,esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {0**} jnz @seekcol0
    @test0row:
    { **} test [edi+ecx*08h+__0STAR],ebp
    { **} js @seekcol0
    { } mov [edi+edx*08h+__0STARROW],ecx
    {@FE} mov [edi+ecx*08h+__0STAR],edx
    {@02} jns @free0col { forced conditional jump for Sandy Bridge }
    { ----------------------------------------------------------------------------------------------- }
    {@04} { x12 } mov eax,00000000h; mov edx,00000000h; xor ecx,ecx
    {@10} { x2 } xor ebp,ebp
    @@5TH_STEP: { K10:2.5 Core2:2.4 - 2.8 uop/clk - 1900*2+4800
    {@12} mov eax,[edi+__INITCOL] { lea ebx,[ebp-04h] }
    {1} mov esi,[esp+__SIZE]
    {2} add eax,04h
    {0} movsx ebx,word ptr [edi+__MINCOLROW]
    {@20} @DEC5_free_col: { 3 AGU + 6 EX uops on Kaveri }
    {0} mov ebp,[edi+eax*08h+__COLMARK] { 2 clk 5 ALU ops on Core 2 }
    {1} sar ebp,1Fh
    {2} and ebp,edx
    {0} add [edi+eax*08h+__COLMODIFIER],ebp
    {1*} add eax,04h
    {@30*} jnz @DEC5_free_col { clears EAX register }
    { } mov eax,[esp+__SIZE+esi*04h]
    { } movsx ecx,word ptr [edi+__MINCOLROW+02h]
    { } jmp @INC5_marked_row
    { x4 } xor ebp,ebp; xor esi,esi
    {@40} @inc5row:
    {0} add [edi+eax*08h+__ROWMODIFIER],edx { 4 AGU + 4 EX uops on Kaveri }
    {1-} mov eax,ebp
    @INC5_marked_row:
    {2} mov ebp,[esp+esi*04h]
    {0*} sub esi,01h
    {1*} jge @inc5row { sets ESI to 0FFFFFFFFh }
    @@3RD_STEP:
    {@4E*} and esi,[edi+ebx*08h+__0STAR]
    {@52*} jz @4TH_STEP { long jump instruction }
    {@58} @re3start:
    { } mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    { } { x1 } mov ecx,es:[edi+__INITCOL] { lea ecx,es:[ebp-04h] }
    {@60-} mov edx,ebx
    {@62} @mark3row:
    { } mov [esp+__OFFS+eax*04h],ebx
    { -} xor ebx,ebx
    { } mov [edi+esi*08h+__COLMARK],esi { unmark column with negative }
    { } add dword ptr [esp+__SIZE],01h
    {@71} @chk2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*08h+__COLMARK],ecx { STORE FORWARDED from @mark3row }
    {0**} jns @chk2col
    @@2ND_STEP:
    {12} push dword ptr [edi+ecx*08h+__COLMODIFIER]
    {@80} lea eax,[ecx+edi]
    { } sub ebx,ebp
    { } sal ecx,10h
    { } mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {@8C} @ZERO2col: { K10:3.0 Core2:2.5 - 2.9 uop/clk - 1500*2+5600 { 4 AGU + 11 EX uops on Kaveri }
    {0} sub esi,[esp+00h] { 4 clk 13 ALU ops on Core 2 }
    {@8F} add esi,[eax+ebp]
    {C2D} lea eax,[eax+ebp]
    {2} jo @over2flow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {0} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {1} jz @zero
    {K10}// lea eax,[eax+ebp]
    {0} cmp esi,edx
    {@9F} cmovb edx,esi
    {@A2} cmovb cx,bx
    @over2flow:
    {0} mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ebx,04h
    {2*} jnz @ZERO2col
    {@AF} @zero:
    {0} pop eax { add esp,04h } { forces ESP handling to AGU/memory pipe on Kaveri/Core }
    {@B0-} mov eax,ecx
    {2} sar ecx,10h
    {0} cmovnc eax,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],eax
    {2**} test ebx,ebx
    {0**} jz @chk2col
    {@C0*} add esi,[edi+ebx*08h+__0STAR] { zero found -> ESI=0 }
    {2*} jz @4TH_STEP
    {0} mov eax,[esp+__SIZE]
    {1**} cmp word ptr [edi+__MINCOLROW],bx { STORE FORWARDED }
    {2**} jz @re3start
    {@D0} cmp esi,ecx
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2} cmovl ecx,esi
    {0*} sub ecx,04h { never clears ECX register }
    {1*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    { x2 } xor esi,esi
    {@E0} { x4 } lea eax,[ebp+ebp+00h]
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@E4-} mov ebx,edx
    @4TH_STEP:
    {@E6} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {@F0} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {2**} cmp edx,00h
    {0**} jnz @@4TH_STEP
    { } sub esi,ebp
    { } sub edx,ebp
    { } lea ecx,[esi-04h] { mov ecx,[edi+__INITCOL] }
    @@1ST_STEP: { K10:2.8 Core2:2.9 - 3.2 uop/clk - 1500*2+6100 }
    {@00} mov eax,[edi+esi*08h+__0STARROW] { 4 AGU + 7 EX uops on Kaveri }
    {1} and ebx,eax { 2 clk 6 ALU ops on Core 2 }
    {2} not eax
    {0} mov [edi+esi*08h+__COLMARK],eax
    {1} mov eax,[edi+esi*08h+__FIXEDROW]
    {2} cmovs ecx,esi
    {0} mov [edi+esi*08h+__0COLON___ROWMARK],eax
    {1*} add esi,04h
    {2*} jnz @@1ST_STEP { clears ESI register }
    { } mov [esp+__SIZE],esi
    { -} xor ebx,ebx
    {@21*} add ecx,04h { long jump instruction }
    { *} jnz @@2ND_STEP { ===>>> EBX: 00h EDX:negative ECX:initcol (>= EBP) }
    { } mov esi,[esp+ebp+04h+__MARKS]
    { -} mov ebx,edi { work matrix unmodified } { [esp+__SAVE] }
    @@results:

  • P.H.

    senior tag

    válasz P.H. #99 üzenetére

    Nem ez a gond; bár a szimuláció a végrehajtásra jó, a Core-ok utasításdekódolása teljesen másképp működik, mint az AMD-knél a fixen egymás után következő 3 (K7/K8/K10) vagy 4 (Bulldozer-family) utasítás mint egy egység.

    Az említett 12 utasításos (14 uop, ebből 13 ALU-érintett) ciklusmag 2.5 IPC-vel (2.9 uop/clk) fut (2.5 GHz mellett 1500 fused + 5600 non-fused uop = 3,44 művelet/órajel; tekintve, hogy tárolás nincs benne, azaz 4 pipe-ot mozgat (p2 mint load és a p015 3 ALU), ez nagyon közel van az elméleti maximumhoz; ennél több nehezen hozható ki belőle).

    Nem is kellene említem, hogy K10-en a K10-utasítássorrendű ciklus természetesen 3.0 IPC-vel megy.

    Bár még programot egyelőre nehéz írni/átrendezni rá, kezd kézzelfoghatóvá válni, hogy mit és hogyan dekódol a Core2 (és miért kellett a garantált 4 uop/clock a későbbi Core-verziókba). Pl. ezt a ciklusmagot 3 órajel alatt dekódolja a Core 2 (IPC 2.6, 3.0 uop/cycle), pedig ránézésre ráhúzható a 4-1-1-1 + 4-1-1-1 minta:

    mov eax,[edi+esi*08h+__0STARROW]
    mov [edi+esi*08h+__COLMARK],eax
    and ebx,eax
    mov eax,[edi+esi*08h+__FIXEDROW]
    cmovs ecx,esi
    mov [edi+esi*08h+__0COLON___ROWMARK],eax
    add esi,04h
    jnz @@1ST_STEP

    Érdekesebb, hogy ezt is 3 órajel alatt dekódolja (IPC 2.3, 2.9 uop/cycle), pedig 2-1-1 + 2-1-1 a mintája:

    add [edi+ebx*08h+__COLMODIFIER],ebp
    mov ebp,[edi+ebx*08h+(04h*08h)+__COLMARK]
    xor ebp,edx
    cmovs ebp,ecx
    add ebx,04h
    jnz @DEC5_free_col

    A cmovcc, a load-op-store mindenképpen a 0. dekóderre kell kerüljön, illetve csak egymás utáni utasításokat tud dekódolni a Core2.

  • P.H.

    senior tag

    válasz P.H. #98 üzenetére

    Core2-n továbbra is 506000 mátrix oldódik meg 60 sec alatt. Meg is van a magyarázat, pipeline szimuláció szerint, a fő ciklusra, 5 db lefutás (tárolás nincs benne, azaz 4 pipe dolgozik csak):

    sub esi,[esp+00h] add esi,[eax+ebp] lea eax,[eax+ebp] jo @over2flow
    or esi,[...+__0COLON___ROWMARK] jz @zero cmp esi,edx
    cmovb edx,esi
    cmovb cx,bx mov esi,[...+__ROWMODIFIER] add ebx,04h jnz @ZERO2col


    clk -- ALO 0 -- | -- ALU 1 -- | -- ALU 5 -- | -- LOAD --
    00 | lea eax,[eax+ebp] | | ld x,esp+00h
    01 | | | ld y,eax+ebp
    02 | | | ld z,rowmark
    03 sub esi,x | add ebx,04h | | mov esi,rowmodifier
    04 add esi,y | lea eax,[eax+ebp] | jnz @zeroincol | ld x,esp+00h
    05 or esi,z | | jo overflow | ld y,eax+ebp
    06 cmp esi,edx | | jz zero | ld z,rowmark
    07 cmovb cx,bx | cmovb edx,esi | sub esi,x | mov esi,rowmodifier
    08 cmovb cx,bx | cmovb edx,esi | add esi,y | ld x,esp+00h
    09 or esi,z | add ebx,04h +2 | jz @zero | ld y,eax+ebp
    10 cmp esi,edx | cmovb edx,esi | jo @overflow | ld z,rowmark
    11 cmovb cx,bx | cmovb edx,esi | jnz @zeroincol +4 | mov esi,rowmodifier
    12 sub esi,x +1 | lea eax,[eax+ebp] +1 | | ld x,esp+00h
    13 add esi,x +1 | add ebx,04h +2 | | ld y,eax+ebp
    14 or esi,z +1 | | jo overflow +1 | ld z,rowmark
    15 cmp esi,edx | sub esi,x | jz @zero +1 | mov esi,rowmodifier
    16 cmovb cx,bx | cmovb esi,edx | jnz @zeroincol +4 | ld x,esp+00h
    17 cmovb cx,bx | cmovb esi,edx | add esi,y |
    18 or esi,z | lea eax,[eax+ebp] +2 | jo overflow |
    19 cmp esi,edx | add ebx,04h +4 | jz @zero | ld y,eax+ebp
    20 cmovb cx,bx | cmovb esi,edx | jnz @zeroincol | ld z,rowmark
    21 cmovb cx,bx | cmovb esi,edx | sub esi,x +2 | mov esi,rowmodifier
    22 add esi,y | lea eax,[eax+ebp] +2 | |
    23 or esi,z | add ebx,04h | jo overflow |
    24 cmp edx,esi | | jz @zero |
    25 cmovb cx,bx | cmovb esi,edx | jnz @zeroincol |
    26 cmovb cx,bx | cmovb esi,edx | |

    27 órajel alatt indul el az 5 ciklus 60 utasítása, ez 2,22 IPC; pontosan annyi, amennyi a programon mérhető (a szimuláció 3 clock/load-dal történt). A "+x" jelölés azt jelenti, hogy az adott uop hány órajellel később indul el ahhoz képest , hogy a paraméterei rendelkezésre állnak, mivel van öregebb lefuttatni való uop, ami akadályozza. Nem csoda a 2,2 IPC és a "röcögés", mert főleg az add ebx,04h és kisebb mértékben a lea eax,[eax+ebp] az érintett, amelyek épp a következő ciklusmag lefutását késleltetik (a jcc utasítások ilyen szempontből lényegtelenek, mivel a decode fázisban "kezeli le" őket a branch prediction).

    Ha az X*X méretű munkamátrix végére egy plusz sor kerülne, amely csupa nullát tartalmaz, akkor az add ebx,04h + jnz @zeroincol párosnak nem kellene lezárónak lennie a ciklusban, a felső jz @zero kiléptetné, így az add ebx,04h bárhol elhelyezhető lenne a ciklusban, ezzel az add ebx,04h "öregebb" lenne, így nagyobb IPC érhető el.
    Meglátjuk.

  • P.H.

    senior tag

    Egy újabb lépcsőfok, még több shortcut-tal és mellékhatással.

    K10 (2.9 GHz): Core2-nek tetsző ciklusverzióval 48 sec, K10-essel 47 sec alatt oldja meg a feladatot
    Core2 (2.5 GHz): 60 sec alatt 506000 mátrix? vagy több
    Ivy Bridge (3.8 GHz): 42 sec alatt végez a teljes feladattal (a K10-es ciklusverzió a gyorsabb rajta 1%-kal, de azonos másodperc-eredményt ad)

    Egyre jobban körvonalazódik, hogy - akármilyen hajmeresztő, - átszámolás szerint azonos órajel mellett a Merom/Penryn (Core 2) gyorsabb ebben a programban, mint a Sandy/Ivy Bridge, kb 8%-kal. Egyetlen tényező indokolja ezt, a Core2 loop predictor-a: ez a számolt/for ciklusokat 64 lefutásig jól becsli (a program legfeljebb 60x60-as mátrixokat kezel, ennek megfelelőek a számolt ciklusai is), de ilyen csak a Core 2-kben van; se a későbbi Core-okban, se az AMD CPU-iban nincs.

    {@04-} xor eax,eax
    {1-} mov esi,ebp
    {2} { x1 } movsx ecx,byte ptr es:[edx]
    {0} and esi,-8
    @init:
    {@0F} mov [edi+esi*08h+(00h*08h)+__0STARROW],eax
    {1} mov [edi+esi*08h+(04h*08h)+__0STARROW],eax
    {2*} add esi,08h
    {0*} jnz @init { clears ESI register }
    { } add edx,01h
    { -} mov ebx,ebp
    @@ARGUMENT:
    {@20} cmp ecx,esi { 5 AGU + 10 EX uops on Kaveri }
    {1} lea eax,[ebx+ecx*04h] { 3 clk 8 ALU ops on Core 2 }
    {2} movsx ecx,[edx]
    {0} mov [edi+eax*08h+__0STARROW],ebx { __0COUNTER <- EBP }
    {1} cmovs eax,esi
    {2} inc edx
    {0} mov [edi+ebp*08h+__FIXEDROW],eax
    {1} mov [edi+ebp*08h+__0STAR],eax
    {2*} add ebp,04h
    {0*} jnz @@ARGUMENT { clears EBP register }
    { -} mov eax,edi
    { -} mov ebp,ebx
    {@40} { x1 } lea edx,es:[ebx-04h]
    { } { x1 } and ecx,00h
    { } add esp,ebx
    @@REDUCE_ROWS:
    {@49} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1*} add edx,04h
    {@50*} jz @@REDUCE_COLUMNS
    {0-} xor ecx,ecx
    {1} sub eax,ebp
    {2**} test [edi+edx*08h+__0STAR],ebp
    {0**} js @@REDUCE_ROWS
    { -} mov ebx,ebp
    { -} mov ecx,ebp
    {@60} @findrowmin: { 2 AGU + 5 EX uops on Kaveri }
    {0} mov esi,[eax+ebx] { 2 clk 6 ALU ops on Core 2 }
    {1} or esi,[edi+ebx*08h+__0STARROW]
    {2} cmp esi,ecx
    {0} cmovb ecx,esi
    {1*} add ebx,04h
    {2*} jnz @findrowmin
    {@70} neg ecx
    {1} jle @@REDUCE_ROWS
    @@ABNORMAL_EXIT:
    {@74} or edx,-1
    {1} sub esp,ebp
    {2-} { x3 } cmp edi,00h
    {0} mov esi,[esp+__MARKS]
    {@80} { x6 } test ebp,0FFFFFFFFh
    {2} mov [esi+TRESULT.OPTIMUM],edx
    {0} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {1} jmp dword ptr [esp+_INVALIDRESULT]
    {@90} @initcol:
    {0} mov [edi+__INITCOL],ecx
    {1-} mov esi,ebp
    {2} neg ebp
    {0} push ebp
    {1} or ebx,-1
    {2} jmp @@1ST_STEP { long jump instruction }
    {@A0} { x2 } xor eax,eax
    {@A2} @free0col:
    { } lea ecx,[edx-04h]
    {@A5} @setcolmod:
    { } mov [edi+edx*08h+__COLMODIFIER],esi
    @@REDUCE_COLUMNS: { no need to initialize -initcol in ECX }
    {0**} cmp edx,ebp
    {1**} jz @initcol
    {0} sub edx,04h
    {@B0-} xor esi,esi
    {1**} test [edi+edx*08h+__0STARROW],ebp
    {2**} js @setcolmod
    { } lea ebx,[edi+edx]
    { -} mov ecx,ebp
    { -} mov eax,ebp
    { } sub ebx,ebp
    {@C0} @findcolmin:
    {0} mov esi,[ebx] { 3 AGU + 8 EX uops on Kaveri }
    {1} add esi,[edi+ecx*08h+__ROWMODIFIER] { 3 clk 9 ALU ops on Core 2 }
    {2} or esi,[edi+ecx*08h+__FIXEDROW]
    {0} jz @test0row
    {1} sub ebx,ebp
    {2} cmp esi,eax
    {@D0} cmovb eax,esi
    {1*} add ecx,04h
    {2*} jnz @findcolmin
    { } lea ecx,[ebp-04h]
    { -} mov esi,eax
    { } lea ebx,[edi+edx]
    {@E0**} test eax,eax { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@E4} @seekcol0:
    {0*} add ecx,04h
    {1*} jz @free0col
    {2} sub ebx,ebp
    {0} mov eax,[ebx]
    {@ED} add eax,[edi+ecx*08h+__ROWMODIFIER]
    {@F1**} cmp eax,esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    { **} jnz @seekcol0
    @test0row:
    { **} test [edi+ecx*08h+__0STAR],ebp
    { **} js @seekcol0
    { } mov [edi+edx*08h+__0STARROW],ecx
    {@FE} mov [edi+ecx*08h+__0STAR],edx
    {@02} jns @free0col { forced conditional jump for Sandy Bridge }

    { --------------------------------------------------------------------------------------------- }

    {@04} { x12 } mov eax,00000000h; mov edx,00000000h; xor ecx,ecx
    {@10} { x3 } cmp ebp,00h
    @@5TH_STEP:
    {@13} mov ebx,[edi+__INITCOL] { lea ebx,[ebp-04h] }
    {1} mov esi,[esp+__SIZE]
    {2-} xor ebp,ebp
    {0} mov eax,[esp+__SIZE+esi*04h]
    {@20} @DEC5_free_col: { 3 AGU + 6 EX uops on Kaveri }
    {0} add [edi+ebx*08h+__COLMODIFIER],ebp { 2 clk 6 ALU ops on Core 2 }
    {1} mov ebp,[edi+ebx*08h+(04h*08h)+__COLMARK]
    {2} xor ebp,edx { EDX > 0 EBP <= 0 }
    {0} cmovs ebp,ecx
    {1*} add ebx,04h
    {@30*} jnz @DEC5_free_col { clears EBX register }
    { } mov ecx,[edi+__MINCOLROW]
    { } movsx ebx,cx
    { } sar ecx,10h
    { } jmp @INC5_marked_row
    { x3 } xor ebp,ebp; nop
    {@40} @inc5row:
    {0} add [edi+eax*08h+__ROWMODIFIER],edx { 4 AGU + 4 EX uops on Kaveri }
    {1-} mov eax,ebp
    @INC5_marked_row:
    {2} mov ebp,[esp+esi*04h]
    {0*} sub esi,01h
    {1*} jge @inc5row { sets ESI to 0FFFFFFFFh }
    @@3RD_STEP:
    {@4E*} and esi,[edi+ebx*08h+__0STAR]
    {@52*} jz @4TH_STEP { long jump instruction }
    {@58} @re3start:
    { } mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    { } { x1 } mov ecx,es:[edi+__INITCOL] { lea ecx,es:[ebp-04h] }
    {@60-} mov edx,ebx
    {@62} @mark3row:
    { } mov [esp+__OFFS+eax*04h],ebx
    { -} xor ebx,ebx
    { } add dword ptr [esp+__SIZE],01h
    { } mov [edi+esi*08h+__COLMARK],ebx { unmark column with ZERO }
    {@71} @chk2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*08h+__COLMARK],ecx { STORE FORWARDED from @mark3row }
    {0**} js @chk2col
    @@2ND_STEP:
    {12} push dword ptr [edi+ecx*08h+__COLMODIFIER]
    {@80} lea eax,[ecx+edi]
    { } sub ebx,ebp
    { } sal ecx,10h
    { } mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {@8C} @ZERO2col: { 4 AGU + 11 EX uops on Kaveri }
    {0} sub esi,[esp+00h] { 4 clk 13 ALU ops on Core 2 }
    {@8F} add esi,[eax+ebp]
    {C2D} lea eax,[eax+ebp]
    {2} jo @over2flow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {0} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {1} jz @zero
    {K10}// lea eax,[eax+ebp]
    {0} cmp esi,edx
    {@9F} cmovb edx,esi
    {@A2} cmovb cx,bx
    @over2flow:
    {0} mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ebx,04h
    {2*} jnz @ZERO2col
    {@AF} @zero:
    {0} pop eax { add esp,04h } { enforce ESP handling from to AGU/memory pipe on P4/Kaveri/Core }
    {@B0-} mov eax,ecx
    {2} sar ecx,10h
    {0} cmovnc eax,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],eax
    {2**} test ebx,ebx
    {0**} jz @chk2col
    {@C0*} add esi,[edi+ebx*08h+__0STAR] { zero found -> ESI=0 }
    {2*} jz @4TH_STEP
    {0} mov eax,[esp+__SIZE]
    {1**} cmp word ptr [edi+__MINCOLROW],bx { STORE FORWARDED }
    {2**} jz @re3start
    {@D0} cmp esi,ecx
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2} cmovl ecx,esi
    {0*} sub ecx,04h { never clears ECX register }
    {1*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    { x2 } xor esi,esi
    {@E0} { x4 } lea eax,[ebp+ebp+00h]
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@E4-} mov ebx,edx
    @4TH_STEP:
    {@E6} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {@F0} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {2**} cmp edx,00h
    {0**} jnz @@4TH_STEP
    { } sub esi,ebp
    { } sub edx,ebp
    { } lea ecx,[esi-04h] { mov ecx,[edi+__INITCOL] }
    @@1ST_STEP: { 4 AGU + 6 EX uops on Kaveri }
    {@00} mov eax,[edi+esi*08h+__0STARROW]
    {1} mov [edi+esi*08h+__COLMARK],eax
    {2} and ebx,eax
    {0} mov eax,[edi+esi*08h+__FIXEDROW]
    {1} cmovs ecx,esi
    {@10} mov [edi+esi*08h+__0COLON___ROWMARK],eax
    {0*} add esi,04h
    {1*} jnz @@1ST_STEP { clears ESI register }
    { } { x1 } mov ss:[esp+__SIZE],esi
    { -} xor ebx,ebx
    {@20*} add ecx,04h { long jump instruction }
    { *} jnz @@2ND_STEP { ===>>> EBX: 00h EDX:negative ECX:initcol (>= EBP) }
    { } mov esi,[esp+ebp+04h+__MARKS]
    { -} mov ebx,edi { work matrix unmodified }
    { } pop eax
    @@results:
    {@30} mov eax,[edi+edx*08h+__0STAR] { 3 AGU + 8 EX uops on Kaveri }
    {1} add ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} add eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@40} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results { clears EDX register ( DL=0 as head, DH=0 as length ) }

  • P.H.

    senior tag

    A "simítások" célja - ha nem lenne egyértelmű - az IPC növelése; ez jórészt sikerült is. Ezen szakaszban az algoritmikus megoldások már tisztázottak, a lényeg, a minél kevesebb utasítás + minél több mellékhatás = minél kevesebb órajel alatt tegye meg ugyanazt a CPU. És itt jönnek ki leginkább a microarch. különbségek és főleg a gyengeségek. Azaz az utasítássorrend.

    Szem előtt mindig azt tartom, hogy a kód legyen mindenen jó, ne legyen egy kiszemelt microarch, amin jól fut, a többi rovására, de a lehető legkevesebb kompromisszummal.

    Ivy Bridge (3.8 GHz): 43 sec alatt végez a teljes feladattal
    P4 Northwood (2.4 GHz): 60 sec alatt 225000 mátrix
    Kaveri (3.8 GHz): 54 sec alatt végez a teljes feladattal
    Core2 (2.5 GHz): 60 sec alatt 463000 mátrix
    K10 (2.9 GHz): 48 sec alatt oldja meg a teljes feladatot

    Mint látható, Ivy Bridge-en és a Northwood-on gyorsabb lett a program, a Kaveri-n nem változott a lefutás sebessége (a fő korlátozó tényező még mindig a 2 db EX);

    Core2-n lassabb lett, K10-en viszont "fénysebességre" kapcsolt, folyamatos 2.6 IPC-vel fut le a korábbi 2.4-gyel szemben. Az ok is megvan: az utasítássorrend. A program "mindent vivő", fő meghatározó ciklusa:

    @ZERO2col:
    sub esi,[esp+00h]
    add esi,[eax+ebp]
    {C2} lea eax,[eax+ebp]
    jo @over2flow
    or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    jz @zero
    {K10} lea eax,[eax+ebp]
    cmp esi,edx
    cmovb edx,esi
    cmovb cx,bx
    @over2flow:
    mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    add ebx,04h
    jnz @ZERO2col

    A ciklus Core2 CPU-kon 13 ALU műveletet jelent (a cmovcc-k duplázása miatt), K10-en 11-et; a dekódolás sebessége mindkettőn 4 clock/ciklus.
    A lea eax,[eax+ebp] utasítás felső elhelyezése esetén a Core2-n 2.2 IPC (= 2.6 uop/clock) mérhető és 60 sec alatt 492000 mátrixot számol ki, viszont a K10 visszaesik 2.5 IPC-re és 50 sec alatt végez a feladattal. Az említett utasítás alsó elhelyezésével a fent írt eredmények jönnek ki.

    K10 esetén nem nagy talány, hogy az utasítássorrend adja, hogy mely utasítás mely pipeline-ra kerülhet, és ezek akadályozhatják egymást, viszont Core2 esetén annál inkább, mivel a lea utasítást csakis az 1. ALU tudja végrehajtani (ahogy az ugrásokat csak az 5.). Nem kizárt, hogy a ciklus első 4 utasításával a Core2 ROB-read korlátozásába (3 reg/clock, ebből az egyik kötelezően index-regiszter) sikerült belefutni.
    Bár a Sandy/Ivy Bridge is a Core2-éhez hasonló pipe-elrendezéssel rendelkezik, ott nem akadályozó tényező ez, mivel egyrészt a cikluszáró add+jnz egyetlen belső művelet (macro-fusion), másrészt ROB-read korlátja nem létezik.

    {@04-} xor eax,eax
    {1-} mov esi,ebp
    {2} { x1 } movsx ecx,byte ptr es:[edx]
    {0} and esi,-8
    @init:
    {@0F} mov [edi+esi*08h+(00h*08h)+__0STARROW],eax
    {1} mov [edi+esi*08h+(04h*08h)+__0STARROW],eax
    {2*} add esi,08h
    {0*} jnz @init { clears ESI register }
    { } add edx,01h
    { -} mov ebx,ebp
    @@ARGUMENT:
    {@20} cmp ecx,esi { 5 AGU + 10 EX uops on Kaveri }
    {1} lea eax,[ebx+ecx*04h]
    {2} movsx ecx,[edx]
    {0} mov [edi+eax*08h+__0STARROW],ebx { __0COUNTER <- EBP }
    {1} cmovs eax,esi
    {2} inc edx
    {0} mov [edi+ebp*08h+__FIXEDROW],eax
    {1} mov [edi+ebp*08h+__0STAR],eax
    {2*} add ebp,04h
    {0*} jnz @@ARGUMENT { clears EBP register }
    { -} mov eax,edi
    { -} mov ebp,ebx
    {@40} { x1 } lea edx,es:[ebx-04h]
    { } { x1 } and ecx,00h
    { } add esp,ebx
    @@REDUCE_ROWS:
    {@49} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1*} add edx,04h
    {@50*} jz @@REDUCE_COLUMNS
    {0-} xor ecx,ecx
    {1} sub eax,ebp
    {2**} test [edi+edx*08h+__0STAR],ebp
    {0**} js @@REDUCE_ROWS
    { -} mov ebx,ebp
    { -} mov ecx,ebp
    {@60} @findrowmin: { 2 AGU + 5 EX uops on Kaveri }
    {0} mov esi,[eax+ebx]
    {1} or esi,[edi+ebx*08h+__0STARROW]
    {2} cmp esi,ecx
    {0} cmovb ecx,esi
    {1*} add ebx,04h
    {2*} jnz @findrowmin
    {@70-} neg ecx
    {1} jle @@REDUCE_ROWS
    @@ABNORMAL_EXIT:
    {@74} or edx,-1
    {1} sub esp,ebp
    {2-} { x3 } cmp edi,00h
    {0} mov esi,[esp+__MARKS]
    {@80} { x6 } test ebp,0FFFFFFFFh
    {2} mov [esi+TRESULT.OPTIMUM],edx
    {0} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {1} jmp dword ptr [esp+_INVALIDRESULT]
    {@90} @initcol:
    {0} { x1 } mov es:[edi+__INITCOL],ecx
    {1-} mov eax,ebp
    {2} neg ebp
    {0} push ebp
    {1-} xor ebx,ebx
    {2} jmp @@1ST_STEP { long jump instruction }
    {@A0} { x2 } xor eax,eax
    {@A2} @free0col:
    { } lea ecx,[edx-04h]
    {@A5} @setcolmod:
    { } mov [edi+edx*08h+__COLMODIFIER],esi
    @@REDUCE_COLUMNS: { no need to initialize -initcol in ECX }
    {0**} cmp edx,ebp
    {1**} jz @initcol
    {0} sub edx,04h
    {@B0-} xor esi,esi
    {1**} test [edi+edx*08h+__0STARROW],ebp
    {2**} js @setcolmod
    { } lea ebx,[edi+edx]
    { -} mov ecx,ebp
    { -} mov esi,ebp
    { } sub ebx,ebp
    {@C0} @findcolmin:
    {0} mov eax,[ebx] { 3 AGU + 7 EX uops on Kaveri }
    {1} add eax,[edi+ecx*08h+__ROWMODIFIER]
    {2} or eax,[edi+ecx*08h+__FIXEDROW]
    {0} sub ebx,ebp
    {1} cmp eax,esi
    {2} cmovb esi,eax
    {0*} add ecx,04h
    {1*} jnz @findcolmin
    { } lea ecx,[ebp-04h]
    { } lea ebx,[edi+edx]
    { **} test esi,esi { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@E0} @findcol0:
    {0*} add ecx,04h
    {1*} jz @free0col
    {2} sub ebx,ebp
    {0} mov eax,[ebx]
    {1} add eax,[edi+ecx*08h+__ROWMODIFIER]
    {2**} cmp eax,esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {@EF**} jnz @findcol0
    { **} test [edi+ecx*08h+__0STAR],ebp
    { **} js @findcol0
    { } mov [edi+edx*08h+__0STARROW],ecx
    { } mov [edi+ecx*08h+__0STAR],edx
    { } jmp @free0col
    { --------------------------------------------------------------------------------------------- }
    {@00} { x16 } test ebp,0FFFFFFFFh; cmp edx,00h; cmp ecx,00h; xor eax,eax; xor edi,edi
    {@10} { x3 } cmp ebp,00h
    @@5TH_STEP:
    {@13} mov ebx,[edi+__INITCOL] { lea ebx,[ebp-04h] }
    {1} mov esi,[esp+__SIZE]
    {2-} xor ebp,ebp
    {0} mov eax,[esp+__SIZE+esi*04h]
    {@20} @DEC5_free_col: { 4 AGU + 6 EX uops on Kaveri }
    {0} add [edi+ebx*08h+__COLMODIFIER],ebp
    {1-} mov ebp,ecx
    {2} test [edi+ebx*08h+(04h*08h)+__COLMARK],ebx
    {0} cmovns ebp,edx
    {1*} add ebx,04h
    {@30*} jnz @DEC5_free_col { clears EBX register }
    { } mov ecx,[edi+__MINCOLROW]
    { } movsx ebx,cx
    { } sar ecx,10h
    { } jmp @INC5_marked_row
    { x3 } xor ebp,ebp; nop
    {@40} @inc5row:
    {0} add [edi+eax*08h+__ROWMODIFIER],edx
    {1-} mov eax,ebp
    @INC5_marked_row: { 4 AGU + 4 EX uops on Kaveri }
    {2} mov ebp,[esp+esi*04h]
    {0*} sub esi,01h
    {1*} jge @inc5row { sets ESI to 0FFFFFFFFh }
    @@3RD_STEP:
    {@4E*} and esi,[edi+ebx*08h+__0STAR]
    {@52*} jz @4TH_STEP { long jump instruction }
    {@58} @re3start:
    { } mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    { } { x1 } mov ecx,es:[edi+__INITCOL] { lea ecx,[ebp-04h] }
    {@60-} mov edx,esi
    {@62} @mark3row:
    { } mov [esp+__OFFS+eax*04h],ebx
    { } mov [edi+esi*08h+__COLMARK],eax { clear _COLMARK sign = store positive value to _COLMARK }
    { } inc eax { add eax,01h }
    { -} xor ebx,ebx
    @@2ND_STEP:
    {@6D} mov [esp+__SIZE],eax
    @chk2col:
    {@71*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*08h+__COLMARK],ecx { STORE FORWARDED from @mark3row }
    {0**} js @chk2col
    {12} push dword ptr [edi+ecx*08h+__COLMODIFIER]
    {@80} sub ebx,ebp
    { } lea eax,[ecx+edi]
    { } mov esi,[edi+ebx*08h+__ROWMODIFIER]
    { } sal ecx,10h
    {@8C} @ZERO2col: { 4 AGU + 11 EX uops on Kaveri }
    {0} sub esi,[esp+00h]
    {@8F} add esi,[eax+ebp]
    {0} jo @over2flow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {1} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {2} jz @zero
    {K10} lea eax,[eax+ebp]
    {0} cmp esi,edx
    {@9F} cmovb edx,esi
    {@A2} cmovb cx,bx
    @over2flow:
    {0} mov esi,[edi+ebx*08h+(04h*08h)+__ROWMODIFIER]
    {1*} add ebx,04h
    {2*} jnz @ZERO2col
    {@AF} @zero:
    {0} pop eax
    {@B0-} mov eax,ecx
    {2} sar ecx,10h
    {0} cmovnc eax,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],eax
    {2**} test ebx,ebx
    {0**} jz @chk2col
    {@C0*} add esi,[edi+ebx*08h+__0STAR] { zero found -> ESI=0 }
    {2*} jz @4TH_STEP
    {0} mov eax,[esp+__SIZE]
    {1**} cmp word ptr [edi+__MINCOLROW],bx { STORE FORWARDED }
    {2**} jz @re3start
    {@D0} cmp esi,ecx
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2} cmovl ecx,esi
    {0*} sub ecx,04h { never clears ECX register }
    {1*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    { x2 } xor esi,esi
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@E0-} mov ebx,edx
    @4TH_STEP:
    {@E2} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {1} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {@F0**} cmp edx,00h
    {0**} jnz @@4TH_STEP
    { -} mov eax,esi
    { } mov ecx,[edi+__INITCOL] { lea ecx,[ebp-04h] }
    { } sub edx,ebp
    { } sub eax,ebp
    { -} mov ebx,esi
    @@1ST_STEP: { 4 AGU + 6 EX uops on Kaveri }
    {@00} mov esi,[edi+eax*08h+__0STARROW]
    {1} mov [edi+eax*08h+__COLMARK],esi
    {2} and edx,esi
    {0} mov esi,[edi+eax*08h+__FIXEDROW]
    {1} cmovs ecx,eax
    {@10} mov [edi+eax*08h+__0COLON___ROWMARK],esi
    {0*} add eax,04h
    {1*} jnz @@1ST_STEP { clears EAX register }
    { } xor edx,ecx { long jump instruction }
    { } js @@2ND_STEP { ===>>> EBX: 00h EAX:00h EDX:negative ECX:initcol (>= EBP-4) }
    {@21} pop esi
    { } neg ebp
    { -} xor ecx,ecx
    { -} mov edx,ebp
    { } sub esp,ebp
    { -} mov ebx,edi
    { } mov esi,[esp+__MARKS]
    @@results:
    {@30} mov eax,[edi+edx*08h+__0STAR] { 3 AGU + 8 EX uops on Kaveri }
    {1} sub ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@40} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results

  • P.H.

    senior tag

    válasz P.H. #95 üzenetére

    Simitgatva:

    K10 (2.9 GHz): 53 sec alatt oldja meg a teljes feladatot
    Ivy Bridge (3.8 GHz): 45 sec alatt végez a teljes feladattal
    Core2 (2.5 GHz): 60 sec alatt 479000 mátrix
    P4 Northwood (2.4 GHz): 60 sec alatt 221000 mátrix

    Core-családhoz kis adalék:

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Instructions per cycle (IPC)
    Counter 2 : Retired fused uops
    Counter 3 : Retired non-fused uops

    T(ms) c0(M/s) c1(i/c) c2(M/s) c3(M/s)
    50 2500.0 2.2 1323.7 4871.0
    100 2500.0 2.1 1312.8 4842.1
    150 2500.0 2.1 1312.8 4843.9
    200 2500.0 2.1 1305.8 4808.1
    250 2500.0 2.2 1322.9 4882.0
    300 2500.0 2.2 1324.7 4874.4
    350 2500.1 2.1 1301.2 4800.0
    400 2499.9 2.1 1317.3 4851.5
    450 2500.0 2.1 1317.9 4858.3
    500 2500.0 2.1 1316.3 4849.7

    Ez a 2.5 GHz-es Core2 mérése:
    - ami nem látszik, 2.1 IPC mellett 2.5 uop/cycle (cmovcc...)
    - ami látszik: stabilan 4800 feletti non-fused és 1300 feletti fused uop/cycle (utóbbi 2 végrehajtót dolgoztat), azaz 4800+1300*2 = 7400, a branch misprediction-ok mellett is minden órajelben 3 feldolgozó dolgozik a 6-ból.

    {@08} { x1 } and eax,00h
    {1-} mov esi,ebp
    {2} movsx ecx,byte ptr [edx]
    @init:
    {@10} mov [edi+esi*08h+__0STARROW],eax
    {1} mov [edi+esi*08h+__COLMODIFIER],eax
    {2*} add esi,04h
    {0*} jnz @init { clears ESI register }
    inc edx
    { x1 } lea ebx,[ebp+00h]
    @@ARGUMENT:
    {@20} cmp ecx,esi { 5 AGU + 10 EX uops on Kaveri }
    {1} lea eax,[ebx+ecx*04h]
    {2} movsx ecx,[edx]
    {0} mov [edi+eax*08h+__0STARROW],ebx { __0COUNTER <- EBP }
    {1} cmovs eax,esi
    {2} inc edx
    {0} mov [edi+ebp*08h+__FIXEDROW],eax
    {1} mov [edi+ebp*08h+__0STAR],eax
    {2*} add ebp,04h
    {0*} jnz @@ARGUMENT { clears EBP register }
    { -} mov edx,ebx
    { -} mov eax,edi
    {@40*} add ebp,ebx
    { *} jnz @chk0row { forced conditional jump for Sandy Bridge }
    { x5 } mov ecx,00000000h
    @@REDUCE_ROWS:
    {@49} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {1*} add edx,04h
    {@50*} jz @@REDUCE_COLUMNS
    @chk0row:
    {0-} xor ecx,ecx
    {1} sub eax,ebp
    {2**} test [edi+edx*08h+__0STAR],ebp
    {0**} js @@REDUCE_ROWS
    { -} mov ebx,ebp
    { } not ecx
    {@60} @findrowmin: { 2 AGU + 5 EX uops on Kaveri }
    {0} mov esi,[eax+ebx]
    {1} or esi,[edi+ebx*08h+__0STARROW]
    {2} cmp esi,ecx
    {0} cmovb ecx,esi
    {1*} add ebx,04h
    {2*} jnz @findrowmin
    {@70-} neg ecx
    {1} jle @@REDUCE_ROWS
    @@ABNORMAL_EXIT:
    {@74} { x2 } mov edx,0FFFFFFFFh
    {1} mov esi,[esp+__MARKS]
    {2-} { x3 } cmp edi,00h
    {@80} { x6 } test ebp,0FFFFFFFFh
    {1} mov [esi+TRESULT.OPTIMUM],edx
    {2} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {0} jmp dword ptr [esp+_INVALIDRESULT]
    {@90} @initcol:
    {0} mov [edi+ebp*08h+__INITCOL],ecx
    {1} add esp,ebp
    {2-} mov eax,ebp
    {0} push ebp
    {1} jmp @@1ST_STEP { long jump instruction }
    { x2 } xor edx,edx
    {@A0} { x6 } test ebp,0FFFFFFFFh
    {@A6} @setcolmod:
    { } mov [edi+edx*08h+__COLMODIFIER],ecx
    @@REDUCE_COLUMNS:
    {@AA} lea ecx,[edx-04h] { negative for minimum }
    {@AD} @chk0col:
    {0} sub edx,04h
    {@B0**} cmp edx,ebp
    {2**} jb @initcol { EDX always negative } { jb = jl for 2 negative numbers }
    {0**} test [edi+edx*08h+__0STARROW],ebp
    {1**} js @chk0col
    { } lea ebx,[edi+edx]
    { -} mov esi,ebp
    { } sub ebx,ebp
    {@C0} @findcolmin:
    {0} mov eax,[ebx] { 3 AGU + 7 EX uops on Kaveri }
    {1} add eax,[edi+esi*08h+__ROWMODIFIER]
    {2} or eax,[edi+esi*08h+__FIXEDROW]
    {0} sub ebx,ebp
    {1} cmp eax,ecx
    {2} cmovb ecx,eax
    {0*} add esi,04h
    {1*} jnz @findcolmin
    { } lea esi,[ebp-04h]
    { } lea ebx,[edi+edx]
    { **} test ecx,ecx { JS/JNS can only fuse with TEST }
    { **} js @@ABNORMAL_EXIT
    {@E0} @subcol:
    {0*} add esi,04h
    {1*} jz @setcolmod
    {2} sub ebx,ebp
    {0} mov eax,[ebx]
    {1} add eax,[edi+esi*08h+__ROWMODIFIER]
    {2**} cmp eax,ecx
    {@EF**} jnz @subcol
    { **} test [edi+esi*08h+__0STAR],ebp
    { **} js @subcol
    { } mov [edi+edx*08h+__0STARROW],esi
    { } mov [edi+esi*08h+__0STAR],edx
    { } jmp @setcolmod
    { --------------------------------------------------------------------------------------------- }
    {@00} { x16 } ...
    @@5TH_STEP:
    {@10} mov ebx,[edi+ebp*08h+__INITCOL]
    {1-} xor eax,eax
    {2} mov esi,[esp+__SIZE]
    {0-} xor ebp,ebp
    {1} mov ecx,[edi+__MINCOLROW]
    {2-} { x1 } nop
    {@20} @DEC5_free_col: { 4 AGU + 6 EX uops on Kaveri }
    {0} add [edi+ebx*08h+__COLMODIFIER],ebp
    {1-} mov ebp,eax
    {2} test [edi+ebx*08h+04h*08h+__COLMARK],ebx
    {0} cmovns ebp,edx
    {1*} add ebx,04h
    {@30*} jnz @DEC5_free_col { clears EBX register }
    { } mov eax,[esp+__SIZE+esi*04h]
    { } movsx ebx,cx
    { } sar ecx,10h
    { } jmp @INC5_marked_row
    { x2 } nop; nop
    {@40} @inc5row:
    {0} add [edi+eax*08h+__ROWMODIFIER],edx
    {1-} mov eax,ebp
    @INC5_marked_row: { 4 AGU + 4 EX uops on Kaveri }
    {2} mov ebp,[esp+esi*04h]
    {0*} sub esi,01h
    {1*} jge @inc5row { sets ESI to 0FFFFFFFFh }
    @@3RD_STEP:
    {@4E*} and esi,[edi+ebx*08h+__0STAR]
    {@52*} jz @4TH_STEP { long jump instruction }
    {0} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {@5C} @re3start:
    {0} mov ecx,[edi+ebp*08h+__INITCOL] { lea ecx,[ebp-04h] }
    {@60-} mov edx,ebp
    {@62} @mark3row:
    {0} mov [esp+__OFFS+eax*04h],ebx
    {1} mov [edi+esi*08h+__COLMARK],eax { clear __COLMARK sign = store positive value to __COLMARK}
    {2} add eax,01h
    @@2ND_STEP:
    {@6D} mov [esp+__SIZE],eax
    @chk2col:
    {@71*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*08h+__COLMARK],ecx { STORE FORWARDED from @mark3row }
    {0**} js @chk2col
    {12} push dword ptr [edi+ecx*08h+__COLMODIFIER]
    {@80-} mov ebx,ebp
    {0-} mov eax,ecx
    {1} sal ecx,10h
    {2} sub eax,ebp
    {@89} @ZERO2col: { 4 AGU + 11 EX uops on Kaveri }
    {0} mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {1} sub esi,[esp+00h]
    {@90} add esi,[edi+eax]
    {0} jo @overflow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {1} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {2} jz @zero
    {0} sub eax,ebp
    {1} cmp esi,edx
    {@9F} cmovb edx,esi
    {@A2} cmovb cx,bx
    @over2flow:
    {1*} add ebx,04h
    {2*} jnz @ZERO2col
    {@AB} @zero:
    {0} add esp,04h
    {1-} mov eax,ecx
    {@B0} sar ecx,10h
    {0} cmovnc eax,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],eax
    {2**} test ebx,ebx
    {0**} jz @chk2col
    {@BE*} add esi,[edi+ebx*08h+__0STAR] { zero found -> ESI=0 }
    {@C2*} jz @4TH_STEP
    {0} mov eax,[esp+__SIZE]
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2**} cmp word [edi+__MINCOLROW],bx { STORE FORWARDED }
    {@D0**} jz @re3start
    {1} cmp esi,ecx
    {2} cmovl ecx,esi
    {0*} sub ecx,04h { never clears ECX register }
    {1*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    @overflow:
    sub eax,ebp
    jmp @over2flow
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@E0-} mov ebx,edx
    @4TH_STEP:
    {@E2} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {1} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {@F0**} cmp edx,00h
    {0**} jnz @@4TH_STEP
    { } mov ecx,[edi+ebp*08h+__INITCOL] { lea ecx,[ebp-04h] }
    { -} mov eax,ebp
    { } { x2 } mov edx,0FFFFFFFFh
    @@1ST_STEP: { 4 AGU + 6 EX uops on Kaveri }
    {@00} mov ebx,[edi+eax*08h+__0STARROW]
    {1} mov [edi+eax*08h+__COLMARK],ebx
    {2} and edx,ebx
    {0} mov ebx,[edi+eax*08h+__FIXEDROW]
    {1} cmovs ecx,eax
    {@10} mov [edi+eax*08h+__0COLON___ROWMARK],ebx
    {0*} add eax,04h
    {1*} jnz @@1ST_STEP { clears EAX register }
    { } xor edx,ebp { long jump instruction }
    { } js @@2ND_STEP { ===>>> EAX:00h EDX:negative ECX:initcol (>= EBP-4) }
    {@21} lea eax,[ebp-04h]
    {1-} mov edx,ebp
    {2-} xor ecx,ecx
    {0} sub esp,eax
    {1-} mov ebx,edi { work matrix unmodified } { [esp+__SAVE] }
    {2} mov esi,[esp+__MARKS]
    @@results:
    {@30} mov eax,[edi+edx*08h+__0STAR]
    {1} sub ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@40} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results

  • P.H.

    senior tag

    Innen már csak apróbb simítások maradnak egy szálon, tényleg jöhet a többszálas megvalósítás.

    - a kód negyede eltűnt, felesleges, mivel:
    - a write-through L1D-vel ellátott microarch-ok kedvéért a program mindent fejben számol, magába a mátrixba semmit sem ír vissza; n*n méretű mátrix esetén két db n méretű vektor az írt terület
    - a ciklusok utasítássorrendjében kiemelkedő fontosságú, hogy a ciklusszámláló és a pointer-aritmetika (a következő cikluslefutáshoz) ne legyen akadályozva a ciklustörzs számításai által; a.k.a. a lehető leghamarabb megtörténjenek.

    K10 (2.9 GHz): 55 sec alatt oldja meg a teljes feladatot
    Kaveri (3.8 GHz): 54 sec alatt végez a teljes feladattal
    Core2 (2.5 GHz): 60 sec alatt 472000 mátrix
    P4 Northwood (2.4 GHz): 60 sec alatt 218000 mátrix (megvan az 1.0 IPC)

    {0-} xor eax,eax
    {1-} mov esi,ebp
    {2-} mov ebx,ebp
    {0} add ebp,ebp
    {1} movsx ecx,byte ptr [edx]
    @mark0:
    {0} mov [edi+esi*08h+__0STARROW],eax
    {1} mov [edi+esi*08h+__COLMODIFIER],eax
    {2*} add esi,04h
    {1*} jnz @mark0 { clears ESI register }
    { -} { x5 } mov eax,00000000h
    { } add esp,ebp
    { -} mov ebp,ebx
    @@ARGUMENT:
    {@20} cmp ecx,esi
    {1} lea eax,[ebx+ecx*04h]
    {2} movsx ecx,[edx+01h]
    {0} mov [edi+eax*08h+__0STARROW],ebx
    {1} cmovs eax,esi
    {2} inc edx
    {@30} mov [edi+ebp*08h+__FIXEDROW],eax
    {1} mov [edi+ebp*08h+__0STAR],eax
    {2*} add ebp,04h
    {0*} jnz @@ARGUMENT
    {0} { x1 } nop
    {1-} mov ebp,ebx
    {@40-} mov edx,ebx
    {0-} mov eax,edi
    {1} jz @chk0row { forced conditional jump for Sandy Bridge }
    { x1 } nop
    @@REDUCE_ROWS:
    {@47} neg ecx
    {1} mov [edi+edx*08h+__ROWMODIFIER],ecx
    {2*} add edx,04h
    {@50*} jz @@REDUCE_COLUMNS
    @chk0row:
    {0-} xor ecx,ecx
    {1} sub eax,ebp
    {2**} test [edi+edx*08h+__0STAR],ebp
    {0**} js @@REDUCE_ROWS
    {1} or ecx,-1
    {2-} { x1 } nop
    {@60} @findrowmin:
    {0} mov esi,[eax+ebp]
    {1} or esi,[edi+ebp*08h+__0STARROW]
    {2} cmp ecx,esi
    {0} cmova ecx,esi
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {@70-} mov ebp,ebx
    {1**} test ecx,ecx { JS/JNS can only fuse with TEST }
    {2**} jns @@REDUCE_ROWS
    push ebx
    { x3 } cmp edi,00h
    @@ABNORMAL_EXIT:
    {@7A} pop eax
    {1} sub esp,ebp
    {2} or edx,-1
    {@80} sub esp,ebp
    {1} mov esi,[esp+__MARKS]
    {0} mov [esi+TRESULT.OPTIMUM],edx
    {1} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {2} jmp dword ptr [esp+_INVALIDRESULT]
    {@90} @initcol:
    {0} push ebp
    {1-} mov eax,ebp
    {2} mov [edi+ebp*08h+__INITCOL],ecx
    {0} jmp @@1ST_STEP
    {@9C} { x4 } lea eax,[ebp+ebp+00h]
    {@A0} { x1 } nop
    {@A1} @setcolmod:
    { } pop eax
    { } mov [edi+edx*08h+__COLMODIFIER],ecx
    @@REDUCE_COLUMNS:
    {@A6} lea ecx,[edx-04h] { negative for minimum }
    {@A9} @chk0col:
    {0} sub edx,04h
    {1**} cmp edx,ebp
    {2**} jb @initcol { EDX always negative } { jb = jl for 2 negative numbers }
    {@B0**} test [edi+edx*08h+__0STARROW],ebp
    {1**} js @chk0col
    { -} mov ebx,eax
    { } mov esi,0FFFFFFFCh { -4 }
    { } push eax
    { } { x3 } cmp edi,00h
    {@C0} @findcolmin:
    {0} mov eax,[ebx+edx]
    {1} add eax,[edi+esi*08h+__ROWMODIFIER]
    {2} or eax,[edi+esi*08h+__FIXEDROW]
    {0} cmp ecx,eax
    {1} cmova ecx,eax
    {@D0} sub esi,04h
    {0} add ebx,ebp
    {1**} cmp esi,ebp
    {2**} jge @findcolmin
    {0} { x3 } cmp esi,00h
    {1**} test ecx,ecx { JS/JNS can only fuse with TEST }
    {2**} js @@ABNORMAL_EXIT
    {@E0} @subcol:
    {0*} add esi,04h
    {1*} jz @setcolmod
    {2} sub ebx,ebp
    {1} mov eax,[ebx+edx]
    {0} add eax,[edi+esi*08h+__ROWMODIFIER]
    {2**} cmp eax,ecx { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {@F0**} jnz @subcol
    {1**} test [edi+esi*08h+__0STAR],ebp
    {2**} js @subcol
    {0} mov [edi+edx*08h+__0STARROW],esi
    {1} { x1 } mov es:[edi+esi*08h+__0STAR],edx
    {@00} jns @setcolmod { forced conditional jump for Sandy Bridge }
    { ----------------------------------------------------------------------------------------------}
    {@02} @DEC5_free_col: { 3 AGU + 6 EX uops on Kaveri }
    {0} mov ebp,[edi+esi*08h+__COLMARK]
    {1} mov ecx,[edi+esi*08h+__COLMODIFIER]
    {2} cmp ebp,00h
    {0} lea ebp,[ecx+edx]
    {@10} cmovs ebp,ecx
    {2} mov [edi+esi*08h+__COLMODIFIER],ebp
    {0*} add esi,04h
    {1*} jnz @DEC5_free_col { clears ESI register }
    { x1 } mov ecx,[edi+esi+__MINCOLROW]
    @INC5_marked_row: { 4 AGU + 5 EX uops on Kaveri }
    {@20} mov ebp,[esp+ebx*08h]
    {1*} sub ebx,01h
    {2*} jnge @@3RD_STEP
    {0} add [edi+eax*08h+__ROWMODIFIER],edx
    {1-} mov eax,ebp
    {2} jmp @INC5_marked_row
    @@5TH_STEP:
    {@30} mov esi,[edi+ebp*08h+__INITCOL]
    {1-} mov ebx,eax
    {2} mov eax,[esp+__SIZE+eax*08h]
    {0*} add esi,04h
    {1*} jnz @DEC5_free_col { forced conditional jump for Sandy Bridge }
    { x1 } nop
    {@40} { x6 } test ebp,0FFFFFFFFh
    @@3RD_STEP:
    {@46} movsx ebx,cx
    {1} sar ecx,10h
    {2*} add esi,[edi+ebx*08h+__0STAR]
    {@50*} jz @4TH_STEP { long jump instruction }
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {@5A} @re3start:
    {0} mov ecx,[edi+ebp*08h+__INITCOL]
    {1-} mov edx,ebp
    {@60} @mark3row:
    {0} mov [edi+esi*08h+__COLMARK],eax
    {1} mov [esp+__OFFS+eax*08h],ebx
    {2} { x2 } db $2D,$FF,$FF,$FF,$FF { add eax,01h }
    @@2ND_STEP:
    {@6D} mov [esp+__SIZE],eax
    @chk2col:
    {@71*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*08h+__COLMARK],ecx { STORE FORWARDED from @mark3row }
    {0**} js @chk2col
    {12} push dword ptr [edi+ecx*08h+__COLMODIFIER]
    {@80-} mov ebx,ebp
    {0-} mov eax,ecx
    {1} sal ecx,10h
    {2} sub eax,ebp
    {@89} @ZERO2col: { 4 AGU + 11 EX uops on Kaveri }
    {0} mov esi,[edi+ebx*08h+__ROWMODIFIER]
    {1} sub esi,[esp+00h]
    {@90} add esi,[edi+eax]
    {0} jo @overflow { overflow: (-x)+(-y)=(+z) or (+x)+(+y)=(-z) }
    {1} or esi,[edi+ebx*08h+__0COLON___ROWMARK]
    {2} jz @zero
    {0} sub eax,ebp
    {1} cmp esi,edx
    {@9F} cmovb edx,esi
    {@A2} cmovb cx,bx
    @over2flow:
    {1*} add ebx,04h
    {2*} jnz @ZERO2col
    {@AB} @zero:
    {0} add esp,04h
    {1-} mov eax,ecx
    {@B0} sar ecx,10h
    {0} cmovnc eax,[edi+__MINCOLROW]
    {1} mov [edi+__MINCOLROW],eax
    {2} mov eax,[esp+__SIZE]
    {0**} test ebx,ebx
    {@C0**} jz @chk2col
    {2*} add esi,[edi+ebx*08h+__0STAR] { zero found -> ESI=0 }
    {0*} jz @4TH_STEP
    {1} mov [edi+ebx*08h+__0COLON___ROWMARK],ecx { set row mark }
    {2**} cmp word [edi+__MINCOLROW],bx { STORE FORWARDED }
    {@D0**} jz @re3start
    {1} cmp esi,ecx
    {2} cmovl ecx,esi
    {0*} sub ecx,04h { never clears ECX register }
    {1*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    @overflow:
    sub eax,ebp
    jmp @over2flow
    @@4TH_STEP: { 5 AGU + 3 EX uops on Kaveri }
    {@E0-} mov ebx,edx
    @4TH_STEP:
    {@E2} mov edx,[edi+ecx*08h+__0STARROW]
    {2} mov [edi+ebx*08h+__0STAR],ecx
    {0} mov [edi+ecx*08h+__0STARROW],ebx
    {1} mov ecx,[edi+edx*08h+__0COLON___ROWMARK]
    {@F0**} cmp edx,00h
    {0**} jnz @@4TH_STEP
    { } mov ecx,[edi+ebp*08h+__INITCOL]
    { -} mov eax,ebp
    { } { x3 } mov edx,0FFFFFFFFh
    @@1ST_STEP: { 4 AGU + 6 EX uops on Kaveri }
    {@00} mov ebx,[edi+eax*08h+__0STARROW]
    {1} mov [edi+eax*08h+__COLMARK],ebx
    {2} and edx,ebx
    {0} mov ebx,[edi+eax*08h+__FIXEDROW]
    {1} cmovs ecx,eax
    {@10} mov [edi+eax*08h+__0COLON___ROWMARK],ebx
    {0*} add eax,04h
    {1*} jnz @@1ST_STEP { clears EAX register }
    { } xor edx,-1
    { } js @@2ND_STEP { ===>>> EAX:00h EDX:negative ECX:initcol (>= EBP-4) }
    {@22} lea eax,[ebp+ebp-04h]
    {1-} mov edx,ebp
    {2-} xor ecx,ecx
    {0} sub esp,eax
    {1-} mov ebx,edi { work matrix unmodified }
    {2} mov esi,[esp+__MARKS]
    @@results:
    {@32} mov eax,[edi+edx*08h+__0STAR]
    {1} sub ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} sub eax,ebp
    {1} shr eax,02h
    {@40} mov [esi],al
    {0} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results

  • P.H.

    senior tag

    válasz P.H. #93 üzenetére

    Kaveri (3.8 GHz): 60 sec alatt 448000 mátrix

  • P.H.

    senior tag

    Újabb, még gyorsabb változat.

    Core2 (2.5 GHz): 60 sec alatt 370000 mátrix
    K10 (2.9 GHz): 60 sec alatt 483000 mátrix
    Ivy Bridge (3.8 GHz): immár 50 sec alatt oldja meg a feladatot (60 sec alatt kb. 600000 mátrixot oldana meg)

    {0-} xor eax,eax
    {1-} mov esi,ebp
    {2} { x1 } lea ebx,[ebp+ebp+00h]
    {0} and esi,-8
    {1} movsx ecx,byte ptr [edx]
    {2} add esp,ebx
    {@F0} @mark0:
    {0} mov [edi+esi*04h+00h+__0STARROW_COLMARK],eax { __0STARROW = -1 means FIXEDCOL }
    {1} mov [edi+esi*04h+10h+__0STARROW_COLMARK],eax { __0STARROW = -1 means FIXEDCOL }
    {2*} add esi,08h
    {0*} jnz @mark0
    { -} mov ebx,ebp
    { } not eax
    @@ARGUMENT: { initialize __0COUNTER variable to -1 }
    {@00} sub edx,eax
    {1} cmp ecx,esi
    {2} lea ecx,[ebx+ecx*04h]
    {0} mov [edi+ecx*04h+__0STARROW_COLMARK],eax { __0STARROW = -1 means FIXEDCOL }
    {1} cmovs ecx,esi
    {2} mov [edi+ebp*04h+__FIXEDROW],ecx
    {0} mov [edi+ebp*04h+__0STAR],ecx
    {1} movsx ecx,byte ptr [edx]
    {2*} add ebp,04h
    {0*} jnz @@ARGUMENT
    {0} push ebx
    {1-} mov ebp,ebx
    {@20-} mov edx,ebx
    {0-} mov eax,edi
    {1} jmp @chk0row
    @@ABNORMAL_LEAVE:
    {0} mov [esi+TRESULT.OPTIMUM],edx
    {1} mov ebx,[esi+TRESULT.NEXTIVALUE]
    {2} jmp dword ptr [esp+_INVALIDRESULT]
    @@REDUCE_ROWS:
    {0*} add edx,04h
    {1*} jz @@REDUCE_COLUMNS
    @chk0row:
    {2} sub eax,ebp
    {0**} test [edi+edx*04h+__0STAR],ebp
    {1**} js @@REDUCE_ROWS
    {2} or ecx,-1
    {@40} @findrowmin:
    {0} mov esi,[eax+ebp]
    {1} or esi,[edi+ebp*04h+__0STARROW_COLMARK]
    {2} cmp ecx,esi
    {0} cmova ecx,esi
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {@50-} mov ebp,ebx
    {1**} { x4 } test ecx,0FFFFFFFFh { JS/JNS can only fuse with TEST }
    {2**} js @@ABNORMAL_EXIT
    {0} sar ebx,03h
    {1} jc @oddrow
    {2} { x1 } nop
    @subrow:
    {@60} sub [eax+ebx*08h+00h],ecx { max. data value = 00FFFFFFh -> marked elements stay negative }
    @oddrow:
    {1} sub [eax+ebx*08h+04h],ecx { max. data value = 00FFFFFFh -> marked elements stay negative }
    {2*} add ebx,01h
    {0*} jnz @subrow
    { -} mov ebx,ebp
    { } jz @@REDUCE_ROWS { forced conditional jump for Sandy Bridge }
    @@ABNORMAL_EXIT:
    {@70} pop esi
    {1} sub esp,ebp
    {2} or edx,-1
    {0} sub esp,ebp
    {1} mov esi,[esp+__MARKS]
    {2} jmp @@ABNORMAL_LEAVE
    { } { x2 } xor ecx,ecx
    {@80} { x12 } mov eax,00000000h; mov edx,00000000h; xor ecx,ecx
    {@6C} @initcol:
    {0} mov [edi+ebp*04h+__INITCOL],ecx
    {@70-} mov ebx,ebp
    {2} or esi,-1
    {0} jnz @@1ST_STEP { forced conditional jump for Sandy Bridge }
    { x1 } nop
    {@7C} @0counter:
    { } sub [edi+ebp*04h+__0COUNTER],ebx
    @@REDUCE_COLUMNS:
    lea ecx,[edx-04h]
    {@83} @chk0col:
    {0} sub edx,04h
    {1**} cmp edx,ebp
    {2**} jb @initcol { EDX always negative } { jb = jl for 2 negative numbers }
    {0**} test [edi+edx*04h+__0STARROW_COLMARK],ebp
    {1**} js @chk0col
    { -} { x1 } nop
    {@90-} xor ecx,ecx
    { -} mov esi,ebp
    {@94} @findcolmin:
    {0} mov ebx,[eax+edx]
    {1} or ebx,[edi+ecx*04h-10h+__FIXEDROW]
    {2} sub ecx,04h
    {0} cmp esi,ebx
    {@A0} cmova esi,ebx
    {2} add eax,ebp
    {0**} cmp ecx,ebp
    {1**} jnz @findcolmin
    {0} sub ecx,04h
    {1**} test esi,esi { JS/JNS can only fuse with TEST }
    {2**} js @@ABNORMAL_EXIT
    {@B0-} or ebx,-1
    {@B3} @subcol:
    {0*} add ecx,04h
    {1*} jz @0counter
    {2} sub eax,ebp
    {0} sub [eax+edx],esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {1} jnz @subcol
    { } { x1 } nop
    {@C0**} cmp [edi+ecx*04h+__0STAR],ebx
    {1**} jle @subcol
    {2} mov [edi+edx*04h+__0STARROW_COLMARK],ecx
    {0} mov [edi+ecx*04h+__0STAR],edx
    {1} xor ebx,-1 { clears CF }
    {@D0} jnc @subcol
    { x1 } nop
    @@3RD_STEP:
    {0} movsx edx,cx
    {1} lea eax,[ebp-04h]
    {2} sar ecx,10h
    {0} mov esi,[edi+edx*04h+__0STAR]
    {@00} sub eax,edx
    {2**} { x4 } test esi,0FFFFFFFFh
    {0**} jz @@4TH_STEP
    {1} sar eax,02h
    {2} mov [edi+edx*04h+__0COLON___ROWMARK],ecx
    {0} imul eax,ebp
    {1} add eax,edi
    @re3start:
    {@FA-} mov ecx,[edi+ebp*04h+__INITCOL] { lea ecx,[ebp-04h] }
    {1} mov edx,ebp
    {@00} @mark3row:
    {0} and dword ptr [edi+esi*04h+__0STARROW_COLMARK],00FFFFFFh { clear __0STARROW_COLMARK sign }
    {1} mov [esp+__OFFS+ebx*08h],eax
    {2} add ebx,01h
    {0-} { x2 } xor esi,esi
    @@2ND_STEP:
    {@10} mov [esp+__SIZE],ebx
    @chk2col:
    {@14*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*04h+__0STARROW_COLMARK],ecx
    {0**} js @chk2col
    {0-} mov ebx,ebp
    {@20} lea eax,[ecx+edi]
    {1} sal ecx,10h
    {2} sub eax,ebp
    {@28} @zeroincol: { IPC: 3.0 } { 2 AGU + 8 EX uops on Kaveri }
    {0} mov esi,[edi+ebx*04h+__0COLON___ROWMARK]
    {1} or esi,[eax]
    {2} jz @zero
    {@30} cmp esi,edx
    {1} cmovb edx,esi
    {2} cmovb cx,bx
    {0} sub eax,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    {@40} @zero:
    {0-} mov esi,ecx
    {1} sar ecx,10h
    {2} cmovnc esi,[edi+00h] { matrix[0,0] }
    {0} mov [edi+00h],esi { matrix[0,0] }
    {1**} test ebx,ebx
    {2**} jz @chk2col
    {@4E} mov esi,[edi+ebx*04h+__0STAR]
    {1**} test esi,esi
    {2**} jz @4TH_STEP
    {0} mov [edi+ebx*04h+__0COLON___ROWMARK],ecx { set row mark }
    {1} sub eax,ecx
    {@60} mov ebx,[esp+__SIZE]
    {0**} { x1 } db $66,$39,$5F,$00 { cmp word [edi+00h],bx { matrix[0,0] } { STORE FORWARDED }
    {1**} jz @re3start
    {2} cmp esi,ecx
    {0} cmovl ecx,esi
    {1*} sub ecx,04h { never clears ECX register }
    {2*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    @@5TH_STEP:
    { STACK: [2N:offs]...[6:offs] [4:offs] [2:size] [0:EBP]
    [2N+1:colN] ... [5:col2] [3:col1] [1:col0] }
    {0} mov eax,[esp+__SIZE]
    {1} mov esi,[edi+ebp*04h+__INITCOL] { lea esi,[ebp-04h] }
    {01} push dword ptr [edi+00h]
    {1} jmp @INC5_marked_row
    {@80} @row5parity: { IPC: 2.3 }
    {0} mov ecx,ebp
    {1} sar ecx,03h
    {2} jc @odd5row
    @inc5row: { 4 AGU + 8 EX uops on Kaveri }
    {0} add [ebx+ecx*08h+00h],edx
    {1} jc @restore_
    @odd5row:
    {2} add [ebx+ecx*08h+04h],edx
    {0} jc @restore__
    @even5row:
    {@90*} add ecx,01h
    {2*} jnz @inc5row
    @INC5_marked_row:
    {0} mov ebx,[esp+__SIZE+eax*08h+__PUSHED]
    {1*} dec eax { sub eax,01h }
    {2*} jge @row5parity
    {0-} mov ecx,ebp
    {@A0*} add ebp,ebp
    {2*} jnz @CHK5col { forced conditional jump for Sandy Bridge }
    @restore_:
    {@A4} sub [ebx+ecx*08h+00h],edx
    jc @odd5row { forced conditional jump for Sandy Bridge }
    @restore__:
    {@A9} sub [ebx+ecx*08h+04h],edx
    jc @even5row { forced conditional jump for Sandy Bridge }
    @CHK5col:
    {@AF*} add esi,04h
    {1*} jz @zero5item { clears ESI register }
    {2**} test [edi+esi*04h+__0STARROW_COLMARK],esi { __0STARROW = -1 means FIXEDCOL [NOT USED] }
    {0**} js @CHK5col
    {1} add esi,edi
    {2-} mov eax,ecx
    @DEC5_free_col: { IPC: 2.3 }
    {0} imul eax,eax
    {@C0} add ecx,esi
    {2} sar eax,02h
    {@C5} @dec5row: { 4 AGU + 8 EX uops on Kaveri }
    {0} sub [esi+eax],edx
    {1} jo @recover_
    @dec5_1:
    {2} sub [ecx+eax],edx
    {0} jo @recover__
    {1*} add eax,ebp
    {@D1*} jg @dec5row
    {0} sub ecx,esi
    {1} sub esi,edi
    {2**} cmp eax,ebp
    {0**} jc @CHK5col
    {1} add [esi+edi],edx
    {2} jmp @CHK5col
    {@E0} @recover_:
    mov dword ptr [esi+eax],0FF000000h { leave OF }
    jo @dec5_1
    @recover__:
    {@E9} add [ecx+eax],edx
    {1*} add eax,ebp
    {2*} jg @dec5row
    {@F0} sub ecx,esi
    {1*} sub esi,edi { never clears ESI register }
    {2*} jnz @CHK5col { forced conditional jump for Sandy Bridge }
    @zero5item:
    {@F4} pop ecx
    {1} sar ebp,01h
    {2-} xor esi,esi
    {0} jmp @@3RD_STEP
    @@4TH_STEP: { 5 AGU + 4 EX uops on Kaveri }
    {@E0-} mov ebx,edx
    @4TH_STEP:
    {@E2} movsx edx,word ptr [edi+ecx*04h+__0STARROW_COLMARK]
    {2} mov [edi+ebx*04h+__0STAR],ecx
    {0} mov [edi+ecx*04h+__0STARROW_COLMARK],ebx
    {1} mov ecx,[edi+edx*04h+__0COLON___ROWMARK]
    {2**} test edx,edx
    {0**} jnz @@4TH_STEP
    { } dec esi
    { } mov ecx,[edi+ebp*04h+__INITCOL] { lea ecx,[ebp-04h] }
    { -} mov ebx,ebp
    { } add [edi+ebp*04h+__0COUNTER],esi
    @@1ST_STEP: { IPC: 3.0 } { 4 AGU + 5 EX uops on Kaveri }
    {@00} movsx eax,word ptr [edi+ebx*04h+__0STARROW_COLMARK]
    {1} mov [edi+ebx*04h+__0STARROW_COLMARK],eax
    {2} add ebx,04h
    {0} mov eax,[edi+ebx*04h-10h+__FIXEDROW]
    {1} mov [edi+ebx*04h-10h+__0COLON___ROWMARK],eax
    {2} jnz @@1ST_STEP { clears EBX register }
    { -} mov edx,ebp
    { **} cmp [edi+ebp*04h+__0COUNTER],esi {= -1 }
    { **} jnz @@2ND_STEP { ===>>> EBX:00h EDX:negative ECX:initcol (>= EBP-4) }
    {@20} lea eax,[ebp+ebp-04h]
    {1-} xor ecx,ecx
    {0} sub esp,eax
    {1} mov ebx,[esp+__SAVE]
    {2} mov esi,[esp+__MARKS]
    @@results:
    {@30} mov eax,[edi+edx*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@40} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results

  • P.H.

    senior tag

    A géphez legközelebb levő ASM-től látszatra a lehető legtávolabb áll a Java, de a látszat csal: mivel a Java is gépen - csak virtuális gépen - alapul, virtuális architektúrával, arra is lehet optimalizálni; sőt, eléggé jól (meghálálja).
    Csak úgy említem: HSA...
    Viszont meglehetősen nehéz egy ósdi, regiszter nélküli, stack-rendszerű (~x87, csak itt a regiszterek kizárólag az aktuális műveletekhez szükséges értékeket tudják tárolni (azaz minden művelet pop is egyben) és nincs "FXCH").

    Az alábbi kód kitömörít, olyasmi fajtát, amifélét felhasználók vagy programok elég gyakran szoktak kitömöríteni.
    Egy szálas algoritmus, egy Samsung Galaxy SIII egy 1.4 GHz-es magján kb. fele olyan gyors, mint a W****r ugyanerre a file-ra egy 2.26 GHz-es Prescott-on.

    A fő cél az volt, hogy a lefordított Java bytecode minél kevesebb utasításból álljon, ezen ok miatt több utasítás is egy sorba került a Java bytecode LINENUMBER "utasítása" miatt (val'szeg egy számlálót állít be annak érdekében, hogy hiba/exception esetén meg tudja mondani, hanyadik sorban történt a hiba).

    Ezen fő cél elérése nem öncélú, mivel a lefutás is egyre gyorsult. Így a leggyorsabb, kb. fél év ráfordított szabadidő elteltével:

    for(--pos;;)
    if ((type&0x00000001) == 0) {
    if (bpos < 3) { s+=((data[++pos]&bFF)<<bpos); bpos+=b8; }
    if ((type=s&((1<<3)-1)) >= 3<<1) { return invalid_encoding; }
    bpos-=3; s>>=3;
    if (type >= 2<<1) {
    for (;;) if (bpos < 5+5+4 +3) { s+=((data[++pos]&bFF)<<bpos); bpos+=b8; } else break;
    HLIT=257+(movelen=(s&((1<<5)-1))); HDIST=(s>>5+0)&((1<<5)-1); clen=4+((s>>5+5)&((1<<4)-1)); bpos-=(5+5+4); s>>=(5+5+4);
    cMAXBITS=maxLENVALUE; i=maxLENVALUE; do { count[--i]=0; } while (i > 0); // a ciklus után i=0
    j=maxLENGTHCODE-1; do { clens[j]=0; } while (--j >= 0); // a ciklus után j=-1
    for (;;)
    if (--clen >= 0) {
    count[clens[zigzag[++j]]=(s&((1<<3)-1))]++; s>>=3;
    if ((bpos-=3) < 3) { s+=(data[++pos]&bFF)<<bpos; bpos+=b8; } }
    else { break; }
    for (;count[++i] == 0;); for (;count[--cMAXBITS] == 0;); j=cMAXBITS-(cMINBITS=(--i)); lookupsize=0; symbol=0; clen=0;
    do { dmin[++i]=symbol-lookupsize; dmax[i]=(symbol=(symbol+(clen=count[i])))<<(--j); symbol<<=1; count[i]=(lookupsize+=clen); } while (j > 0);
    for (dmax[i+1]=(1<<16)-1, count[0]=maxLENGTHCODE, i=maxLENGTHCODE; (lookup032[--count[clens[--i]]]=i) > 0;);

    aMAXBITS=alphabetMAXencodeLENGTH; i=alphabetMAXencodeLENGTH; do { count[--i]=0; } while (i > 0); // a ciklus után i=0;
    j=HLIT-1; do { clens[j]=0; } while (--j >= 0); // a ciklus után j=-1;
    for (crepMAXBITS=cMAXBITS+repMAXBITS, dMAX8=b8-cMAXBITS;;)
    if (++j < HLIT) {
    for (;;) if (bpos < crepMAXBITS) { s+=((data[++pos]&bFF)<<bpos); bpos+=b8; } else break;
    for (symbol=t[s&bFF]>>dMAX8, clen=cMINBITS; (symbol >= dmax[++clen]);); bpos-=clen; s>>=clen;
    if ((symbol=lookup032[(symbol>>(cMAXBITS-clen))-dmin[clen]]) <= 15) { ++count[clens[j]=symbol]; }
    else if (symbol == 17) { j+=(03-1)+(s&((1<<3)-1)); bpos-=3; s>>=3; }
    else if (symbol == 18) { j+=(11-1)+(s&((1<<7)-1)); bpos-=7; s>>=7; }
    else {
    count[clen=clens[--j]]+=(i=3+(s&((1<<2)-1))); bpos-=2; s>>=2;
    do { clens[++j]=clen; } while (--i > 0); } }
    else { break; }
    for (;count[++i] == 0;); for (;count[--aMAXBITS] == 0;); j=aMAXBITS-(aMINBITS=(--i)); lookupsize=0; symbol=0; clen=0;
    do { amin[++i]=symbol-lookupsize; amax[i]=(symbol=(symbol+(clen=count[i])))<<(--j); symbol<<=1; count[i]=(lookupsize+=clen); } while (j > 0);
    for (amax[i+1]=(1<<16)-1, count[0]=maxALPHA;;) if (movelen > 0) { lookup288[--count[clens[--HLIT]]]=lengthdata[--movelen]; } else break;
    for (;(lookup288[--count[clens[--HLIT]]]=HLIT) > 0;);

    dMAXBITS=alphabetMAXencodeLENGTH; i=alphabetMAXencodeLENGTH; do { count[--i]=0; } while (i > 0); // a ciklus után i=0;
    j=HDIST; ++HDIST; do { clens[j]=0; } while (--j >= 0); // a ciklus után j=-1;
    for (;;)
    if (++j < HDIST) {
    for (;;) if (bpos < crepMAXBITS) { s+=((data[++pos]&bFF)<<bpos); bpos+=b8; } else break;
    for (symbol=t[s&bFF]>>dMAX8, clen=cMINBITS; (symbol >= dmax[++clen]);); bpos-=clen; s>>=clen;
    if ((symbol=lookup032[(symbol>>(cMAXBITS-clen))-dmin[clen]]) <= 15) { ++count[clens[j]=symbol]; }
    else if (symbol == 17) { j+=(03-1)+(s&((1<<3)-1)); bpos-=3; s>>=3; }
    else if (symbol == 18) { j+=(11-1)+(s&((1<<7)-1)); bpos-=7; s>>=7; }
    else {
    count[clen=clens[--j]]+=(i=3+(s&((1<<2)-1))); bpos-=2; s>>=2;
    do { clens[++j]=clen; } while (--i > 0); } }
    else { break; }
    for (; count[++i] == 0;); for (;count[--dMAXBITS] == 0;); j=dMAXBITS-(dMINBITS=(--i)); lookupsize=0; symbol=0; clen=0;
    do { dmin[++i]=symbol-lookupsize; dmax[i]=(symbol=(symbol+(clen=count[i])))<<(--j); symbol<<=1; count[i]=(lookupsize+=clen); } while (j > 0);
    dmax[i+1]=(1<<16)-1; count[0]=maxDISTANCE; do lookup032[--count[clens[--HDIST]]]=distancedata[HDIST]; while (HDIST > 0);
    for (alenMAXBITS=aMAXBITS+lenMAXBITS, aMAXhi=b8-(aMAX8=aMAXBITS-b8), dMAXhi=b8-(dMAX8=dMAXBITS-b8);;) {
    for(;;) if (bpos < alenMAXBITS) { s+=(bFF&data[++pos])<<bpos; bpos+=b8; } else break;
    symbol=(aMAX8 > 0) ? (t[bFF&s]<<aMAX8)+(t[bFF&(s>>b8)]>>aMAXhi) : t[bFF&s]>>(-aMAX8);
    for (clen=aMINBITS; (amax[++clen] <= symbol);); s>>=clen; bpos-=clen;
    if ((symbol=lookup288[(symbol>>(aMAXBITS-clen))-amin[clen]]) <= 255) { dest[++dpos]=(byte)(symbol); continue; }
    if ((movelen=(symbol>>16)) > 0) {
    if ((symbol=(byte)symbol) > 0) { movelen+=s&((-1)>>>(32-symbol)); bpos-=symbol; s>>=symbol; }
    for (;;) if (bpos < dMAXBITS) { s+=(bFF&data[++pos])<<bpos; bpos+=b8; } else break;
    symbol=(dMAX8 > 0) ? (t[bFF&s]<<dMAX8)+(t[bFF&(s>>b8)]>>dMAXhi) : t[bFF&s]>>(-dMAX8);
    for (clen=dMINBITS; (dmax[++clen] <= symbol);); bpos-=clen; s>>=clen;
    i=dpos-(char)(clen=lookup032[(symbol>>(dMAXBITS-clen))-dmin[clen]]);
    if ((clen>>=16) > 0) {
    for (;;) if (bpos < clen) { s+=(bFF&data[++pos])<<bpos; bpos+=b8; } else break;
    i-=s&((-1)>>>(32-clen)); bpos-=clen; s>>=clen; }
    do { dest[++dpos]=dest[++i]; } while (--movelen > 0); }
    else { break; } } }

    else if (type >= 1<<1) {
    for (;;) {
    for (;;) if (bpos < (ZFIX_aMAXBITS+lenMAXBITS+ZFIX_dBITS)) { s+=((data[++pos]&bFF)<<bpos); bpos+=b8; } else break;
    symbol=(t[s&bFF]<<(ZFIX_aMAXBITS-b8))+(t[(s>>b8)&bFF]>>(b8-(ZFIX_aMAXBITS-b8)));
    for (clen=ZFIX_aMINBITS-1; (amaxFIX[++clen] <= symbol);); bpos-=clen; s>>=clen;
    if ((symbol=lookupFIX[(symbol>>(ZFIX_aMAXBITS-clen))-aminFIX[clen]]) <= 255) { dest[++dpos]=(byte)(symbol); continue; }
    if ((movelen=(symbol>>16)) > 0) {
    if ((symbol=(byte)symbol) > 0) { movelen+=s&((-1)>>>(32-symbol)); bpos-=symbol; s>>=symbol; }
    i=dpos-(char)(clen=distancedata[t[s&bFF]>>(b8-ZFIX_dBITS)]); s>>=ZFIX_dBITS; bpos-=ZFIX_dBITS;
    if ((clen>>=16) > 0) {
    for (;;) if (bpos < clen) { s+=((data[++pos]&bFF)<<bpos); bpos+=b8; } else break;
    i-=s&((-1)>>>(32-clen)); bpos-=clen; s>>=clen; }
    do { dest[++dpos]=dest[++i]; } while (--movelen > 0); }
    else { break; } } }

    else {
    pos-=(bpos>>3);
    if ((clen=(bFF&data[++pos])|((bFF&data[++pos])<<8)) == ((~(((bFF&data[++pos])<<16)|(data[++pos]<<24)))>>16)) {
    System.arraycopy(data,pos+1,dest,dpos+1,clen); pos+=clen; dpos+=clen; bpos=0; s=0; } }
    } else break;

  • P.H.

    senior tag

    Titkon, álmomban reméltem, hogy eljön ez a pillanat, de nem volt valós alapja. De(!) eljött.

    Core2 (2.5 GHz): 60 sec alatt 344000 mátrix
    K10 (2.9 GHz): 60 sec alatt 450000 mátrix
    Ivy Bridge (3.8 GHz): nem mérhető, 53 sec alatt megoldja a feladatot (a teljes lefutást 510000 mátrix kiszámolása jelenti); ez több, mint 13%-os gyorsulás a legutóbbi programhoz képest; számításaim szerint 60 sec alatt kb. 570000 mátrixot oldana meg a 3770K.
    Nem kérdés, új tesztfeladatot kell keresni, most jöhet a többszálú algoritmus újraelkészítése.

    A store-to-load forwarding kulcskérdéssé vált, az @@5TH_STEP két egymást követő ciklusa részben azonos elemeken dolgozik, mindkettő load-op-store műveletekkel.

    Ez a program nagyon meghálálja, ha órajelenként két jcc feltételes ugrás kerülhet végrehajtásra; erre a K8/K10-en kívül egyedül a Haswell képes. El se merem képzelni, ott mit mutatna...

    A Pentium 4-eken természetesen lassult így a program a write-through L1D miatt; a 3.8 GHz-es Kaveri-n (ugyancsak write-through L1D) legutóbb 425000 mátrix volt az eredmény 60 sec alatt, tehát hozta a 2.9 GHz-es K10 sebességét 31%-kal nagyobb órajelen, 2 EX végrehajtóval; azt, hogy az ez a kód mit tud, még nem tiszta, de első látásra gyorsabb nem lett.

    Mint látható, számos utasítás mellékhatása erőteljesen ki van használva (egy ciklus nulláz egy regisztert, shift utasítás CF-be teszi az utolsó kitolt bitet, jmp helyett feltételes ugrás egy sosem létrejövő értékre, ...) az utasításszám csökkentése végett. Ez most így K10-en 2.2 IPC.

    {0-} xor eax,eax
    {1-} mov esi,ebp
    {2} { x1 } lea ebx,[ebp+ebp+00h]
    {0} and esi,-8
    {1} movsx ecx,byte ptr [edx]
    {2} add esp,ebx
    {@F0} @mark0:
    {0} mov [edi+esi*04h+00h+__0STARROW_COLMARK],eax { __0STARROW = -1 means FIXEDCOL }
    {1} mov [edi+esi*04h+10h+__0STARROW_COLMARK],eax { __0STARROW = -1 means FIXEDCOL }
    {2*} add esi,08h
    {0*} jnz @mark0
    { -} mov ebx,ebp
    { } not eax
    @@ARGUMENT: { initialize __0COUNTER variable to -1 }
    {@00} sub edx,eax
    {1} cmp ecx,esi
    {2} lea ecx,[ebx+ecx*04h]
    {0} mov [edi+ecx*04h+__0STARROW_COLMARK],eax { __0STARROW = -1 means FIXEDCOL }
    {1} cmovs ecx,esi
    {2} mov [edi+ebp*04h+__FIXEDROW],ecx
    {0} mov [edi+ebp*04h+__0STAR],ecx
    {1} movsx ecx,byte ptr [edx]
    {2*} add ebp,04h
    {0*} jnz @@ARGUMENT
    { } push ebx
    { -} mov ebp,ebx
    {@20-} mov edx,ebx
    { -} mov eax,edi
    { } jmp @chk0row
    {@26} @subrow:
    {0} sub [eax+ebx],ecx { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {1*} add ebx,04h
    {2*} jnz @subrow
    {0-} mov ebx,ebp
    @@REDUCE_ROWS:
    {@30*} add edx,04h
    {1*} jz @@REDUCE_COLUMNS
    @chk0row:
    {2} sub eax,ebp
    {0**} test [edi+edx*04h+__0STAR],ebp
    {1**} js @@REDUCE_ROWS
    {2} or ecx,-1
    {@40} @findrowmin:
    {0} mov esi,[eax+ebp]
    {1} or esi,[edi+ebp*04h+__0STARROW_COLMARK]
    {2} cmp ecx,esi
    {0} cmova ecx,esi
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {@50-} mov ebp,ebx
    {1**} test ecx,ecx { JS/JNS can only fuse with TEST }
    {2**} jns @subrow
    @@ABNORMAL_EXIT:
    {@56} pop esi
    sub esp,ebp
    or edx,-1
    sub esp,ebp
    mov esi,[esp+__MARKS]
    mov [esi+TRESULT.OPTIMUM],edx
    mov ebx,[esi+TRESULT.NEXTIVALUE]
    jmp dword ptr [esp+_INVALIDRESULT]
    {@6C} @initcol:
    {0} mov [edi+ebp*04h+__INITCOL],ecx
    {@70} or esi,-1
    {2-} mov ebx,ebp
    {0} jmp @@1ST_STEP
    { x2 } xor eax,eax
    {@7C} @0counter:
    { } sub [edi+ebp*04h+__0COUNTER],ebx
    @@REDUCE_COLUMNS:
    {@80} lea ecx,[edx-04h]
    {@83} @chk0col:
    {0} sub edx,04h
    {1**} cmp edx,ebp
    {2**} jb @initcol { EDX and EBP always negative } { jb = jl for 2 negative numbers }
    {0**} test [edi+edx*04h+__0STARROW_COLMARK],ebp
    {1**} js @chk0col
    { -} { x1 } nop
    {@90-} xor ecx,ecx
    { -} mov esi,ebp
    {@94} @findcolmin:
    {0} mov ebx,[eax+edx]
    {1} or ebx,[edi+ecx*04h-10h+__FIXEDROW]
    {2} sub ecx,04h
    {0} cmp esi,ebx
    {@A0} cmova esi,ebx
    {2} add eax,ebp
    {0**} cmp ecx,ebp
    {1**} jnz @findcolmin
    {0} sub ecx,04h
    {1**} test esi,esi { JS/JNS can only fuse with TEST }
    {2**} js @@ABNORMAL_EXIT
    {@B0-} or ebx,-1
    {@B3} @subcol:
    {0*} add ecx,04h
    {1*} jz @0counter
    {2} sub eax,ebp
    {0} sub [eax+edx],esi { maximum data value = 00FFFFFFh -> marked elements stay negative }
    {1} jnz @subcol
    { } { x1 } nop
    {@C0**} cmp [edi+ecx*04h+__0STAR],ebx
    {1**} jle @subcol
    {2} mov [edi+edx*04h+__0STARROW_COLMARK],ecx
    {0} mov [edi+ecx*04h+__0STAR],edx
    {1} xor ebx,-1
    {@D0} jmp @subcol
    { x14 } lea edi,[ebp+ebp+00h]; mov eax,00000000h; mov edx,00000000h
    {@E0} { x9 } lea edi,[ebp+ebp+00h]; mov ecx,00000000h


    @@3RD_STEP:
    {@E9} lea eax,[ebp-04h]
    {1} sub eax,edx
    {2} mov [edi+edx*04h+__0COLON___ROWMARK],ecx
    {0} imul eax,ebp
    {1} sar eax,02h
    {2} add eax,edi
    @re3start:
    {@FA-} mov edx,ebp
    {1} mov ecx,[edi+ebp*04h+__INITCOL]
    {@00} @mark3row:
    {0} and dword ptr [edi+esi*04h+__0STARROW_COLMARK],00FFFFFFh
    {1} mov [esp+__OFFS+ebx*08h],eax
    {2} add ebx,01h
    {0-} { x2 } xor esi,esi
    @@2ND_STEP:
    {@10} mov [esp+__SIZE],ebx
    @chk2col:
    {@14*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*04h+__0STARROW_COLMARK],ebp
    {0**} js @chk2col
    {0-} mov ebx,ebp
    {@20} lea eax,[ecx+edi]
    {1} sal ecx,10h
    {2} sub eax,ebp
    {@28} @zeroincol: { 2 AGU + 8 EX uops on Kaveri }
    {0} mov esi,[edi+ebx*04h+__0COLON___ROWMARK]
    {1} or esi,[eax]
    {2} jz @zero
    {@30} cmp esi,edx
    {1} cmovb edx,esi
    {2} cmovb cx,bx
    {0} sub eax,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    {@40} @zero:
    {0-} mov esi,ecx
    {1} sar ecx,10h
    {2} cmovnc esi,[edi+00h] { matrix[0,0] }
    {0} mov [edi+00h],esi { matrix[0,0] }
    {1**} test ebx,ebx
    {2**} jz @chk2col
    {@4E} mov esi,[edi+ebx*04h+__0STAR]
    {1**} test esi,esi
    {2**} jz @4TH_STEP
    {0} mov [edi+ebx*04h+__0COLON___ROWMARK],ecx
    {1} sub eax,ecx
    {@60} mov ebx,[esp+__SIZE]
    {0**} { x1 } db $66,$39,$5F,$00 { cmp word [edi+00h],bx { matrix[0,0] } { STORE FORWARDED }
    {1**} jz @re3start
    {2} cmp esi,ecx
    {0} cmovl ecx,esi
    {1*} sub ecx,04h
    {2*} jnz @mark3row { forced conditional jump for Sandy Bridge }
    @@5TH_STEP:
    { STACK: [2N:offs]...[6:offs] [4:offs] [2:size] [0:EBP]
    [2N+1:colN] ... [5:col2] [3:col1] [1:col0]
    {@74} mov esi,[edi+ebp*04h+__INITCOL]
    {1} mov ebx,[esp+__SIZE]
    {01} push dword ptr [edi+00h]
    {1} jmp @chk5col
    {@80} @recover:
    {0} sub [esi+ecx],edx
    {1-} mov ecx,ebp
    {2} jmp @INC5_column
    {@87} @inc5col: { 4 AGU + 5 EX uops on Kaveri }
    {0} add [esi+ecx],edx
    {1} jc @recover
    {2-} mov ecx,ebp
    @INC5_column:
    {@8E} mov ebp,[esp+ebx*08h+__PUSHED]
    {@92*} sub ebx,01h
    {1*} jge @inc5col
    { } cmp eax,00h
    { -} mov ebx,ecx
    { -} mov eax,ebp
    { } jns @DEC5_free_col
    @CHK5col:
    {@A0} mov eax,[edi+esi*04h+04h*04h+__0STARROW_COLMARK]
    {1*} add esi,04h
    {2*} jz @zero5item { clears ESI register }
    {0**} db $3D,$FF,$FF,$FF,$FF { cmp eax,-1 } { __0STARROW = -1 means FIXEDCOL }
    {1**} jz @chk5col
    {@B0} mov ecx,[esp+__SIZE+ebx*08h+__PUSHED]
    {0} jmp @INC5_column
    @DEC5_free_col:
    {@B6} imul eax,ebp
    {1-} mov ecx,ebp
    {2} add esi,edi
    {0} sar eax,02h
    {@C0} add eax,esi
    {2} add ecx,ecx
    {@C4} @dec5row: { 4 AGU + 8 EX uops on Kaveri }
    {0} sub [eax],edx
    {1} jo @recover_
    @dec5_1:
    {2} sub [eax+ebp],edx
    {0} jo @recover__
    @dec5_2:
    {1} add eax,ecx
    {2**} cmp eax,esi
    {@D1**} ja @dec5row
    { } jz @basestate
    { } sub eax,ebp
    { } add [eax],edx
    @basestate:
    { *} sub esi,edi
    { *} jnz @chk5col { forced conditional jump for Sandy Bridge }
    { } { x3 } cmp edi,00h
    {@E0} @recover_:
    add [eax],edx
    jmp @dec5_1
    @recover__:
    add [eax+ebp],edx
    jmp @dec5_2
    { x6 } mov eax,00000000h; nop
    @zero5item:
    {@EF} pop ecx
    {@F0} movsx edx,cx
    {2} sar ecx,10h
    {0*} add esi,[edi+edx*04h+__0STAR]
    {1*} jnz @@3RD_STEP
    @@4TH_STEP: { 5 AGU + 4 EX uops on Kaveri }
    {@E0-} mov ebx,edx
    @4TH_STEP:
    {@E2} movsx edx,word ptr [edi+ecx*04h+__0STARROW_COLMARK]
    {2} mov [edi+ebx*04h+__0STAR],ecx
    {0} mov [edi+ecx*04h+__0STARROW_COLMARK],ebx
    {1} mov ecx,[edi+edx*04h+__0COLON___ROWMARK]
    {2**} test edx,edx
    {0**} jnz @@4TH_STEP
    { } dec esi
    { } mov ecx,[edi+ebp*04h+__INITCOL]
    { -} mov ebx,ebp
    { } add [edi+ebp*04h+__0COUNTER],esi
    @@1ST_STEP: { 4 AGU + 5 EX uops on Kaveri }
    {@00} movsx eax,word ptr [edi+ebx*04h+__0STARROW_COLMARK]
    {1} mov [edi+ebx*04h+__0STARROW_COLMARK],eax
    {2} add ebx,04h
    {0} mov eax,[edi+ebx*04h-10h+__FIXEDROW]
    {1} mov [edi+ebx*04h-10h+__0COLON___ROWMARK],eax
    {2} jnz @@1ST_STEP { clears EBX register }
    { -} mov edx,ebp
    { **} cmp [edi+ebp*04h+__0COUNTER],esi {= -1 }
    { **} jnz @@2ND_STEP { ===>>> EBX:00h EDX:negative ECX:initcol (>= EBP-4) }


    {@20} lea eax,[ebp+ebp-04h]
    {1-} xor ecx,ecx
    {0} sub esp,eax
    {1} mov ebx,[esp+__SAVE]
    {2} mov esi,[esp+__MARKS]
    @@results:
    {@30} mov eax,[edi+edx*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add ecx,[ebx+eax]
    {0} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@40} add esi,01h
    {1*} add edx,04h
    {2*} jnz @@results

  • P.H.

    senior tag

    Mint a zipzár, az alábbi kód úgy zárt össze a K10 és a Core2 fogaskerekeivel.

    Core2 (2.5 GHz): 60 sec alatt 290000 -> 308000 mátrix
    K10 (2.9 GHz): 60 sec alatt 390000 -> 428000 mátrix
    Ivy Bridge (3.8 GHz): 60 sec alatt 480000 -> 497000 mátrix

    A tesztfeladat teljes lefutásához ~565000 mátrix megoldására van szükség; már nincs messze, hogy valamelyiken 60 sec alatt meglegyen.
    Sikerült újra elérni a K10-en a lefutás alatti folyamatos 2.3-2.4 IPC-t, illetve Core2-n a 2.2 IPC-t (ami a ciklusonkénti legalább 1 cmovcc miatt ~2.5-2.6 fused uop/clock); illetve a Core2 miatt eliminálásra került az összes load-op-store művelet a ciklusokból, meg is hálálta.

    A K10-ben rengeteg potenciál van (3 ALU, 2 L1D-olvasás/clock, cmovcc=1 uop, 3 clock L1D-latency), csak nagyon nehéz eltalálni a megfelelő decode miatti utasításelrendezést (a K8-on 2 db 16 byte-os instruction buffer volt az L1C után, a K10-ben viszont egyetlen 32 byte-os buffer van), illetve azt, hogy a "számítási" utasítások ne ütközzenek a 3 ALU-ban a statikus leosztás miatt (itt főleg a sok movsx reg,mem okoz gondot).
    A Core2 attól szenved, hogy a cmovcc utasítások nemcsak hogy 2 végrehajtót igényelnek, de az utasításdekódolást is befolyásolják, mert ezen utasítások csak az első dekóderbe mehetnek, a 4-1-1-1 minta szerint, ezért a legtöbb 8 utasításos ciklus is csak 3 órajel alatt dekódolható.
    A Bulldozer-alapú CPU-k is szenvednek a K10-hez képest, ott viszont az a gond, hogy magonként csak 2 számítási végrehajtó (EX0 és EX1) van a két AGU mellett (míg K7-ben, K8-ban, K10-ben, Core2-Ivy Bridge-ben 3, Haswell-ben 4), ebbe kell beletuszkolni a 8 utasításos ciklusok 7-8 számítási uop-ját, ezért ezek lefutása nem tud kevesebb lenni, mint 4 órajel; ehhez viszont kevés a ~4 GHz órajel, 1.5x akkora frekvencia kellene, mint a K10-nél (vagy legalább egy igazi AGLU).
    Az Ivy Bridge kiegyensúlyozottan teljesít, az uop-cache miatt a dekódolás nem szűk keresztmetszet és a kódban elég sok macro-op fusion is van, de azért a folyamatos, garantált 4 uop/clock kicsit sovány a Core 2 4-1-1-1 mintájából kinyerhető 7 uop/clock-hoz képest. Mindenesetre itt a legkisebb a nyereség, mi azt mutatja, hogy alapvetően itt volt a legnagyobb a hatékonyság.

    {0-} mov ecx,esp
    {1-} xor ebx,ebx
    {2} add esp,ebp
    {0-} mov esi,ebp
    {1} or eax,-1
    {2} add esp,ebp
    {@F1} @mark0:
    {0} mov [edi+esi*04h+__0STARROW],ebx
    {1} mov [ecx+esi*02h],eax
    {2*} add esi,04h
    {0*} jnz @mark0
    mov eax,ebp
    { x1 } nop
    @@ARGUMENT:
    {@00} movsx ecx,byte ptr [edx]
    {1} mov [esp+ecx*08h],ebx
    {2} cmp ecx,ebx
    {0} lea ecx,[eax+ecx*04h]
    {1} mov [edi+ecx*04h+__0STARROW],ebp
    {@0F} cmovs ecx,ebx
    {0} mov [edi+ebp*04h+__COLROWMARK],ecx
    {1} inc edx
    {2} mov [edi+ebp*04h+__0STAR],ecx
    {0*} add ebp,04h
    {1*} jnz @@ARGUMENT
    {0 } push eax
    {@20-} mov ebp,eax
    {2-} mov edx,eax
    {0-} mov eax,edi
    {1} jmp @chk0row
    {@28} @subrow:
    {0} sub [eax+esi],ecx
    {1*} add esi,04h
    {2*} jnz @subrow
    @@REDUCE_ROWS:
    {0*} add edx,04h
    {1*} jz @@REDUCE_COLUMNS
    @chk0row:
    {2} sub eax,ebp
    {0**} cmp [edi+edx*04h+__0STAR],esi
    {1**} jnz @@REDUCE_ROWS
    {2} or ecx,-1
    {@40-} mov esi,ebp
    {@42} @findrowmin:
    {0} mov ebx,[eax+ebp]
    {1} or ebx,[edi+ebp*04h+__0STARROW]
    {2} cmp ecx,ebx
    {0} cmova ecx,ebx
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {0-} mov ebp,esi
    {1} test ecx,0FFFFFFFFh { JS/JNS can only fuse with TEST }
    {2} jns @subrow
    @@ABNORMAL_EXIT:
    {@5D} pop esi
    sub esp,ebp
    {@60} or edx,-1
    sub esp,ebp
    mov esi,[esp+__MARKS]
    mov [esi+TRESULT.OPTIMUM],edx
    mov ebx,[esi+TRESULT.NEXTIVALUE]
    jmp dword ptr [esp+_INVALIDRESULT]
    {@83} @initcol:
    mov [esp+00h*08h+__FIXCOL],ecx
    jmp @@1ST_STEP
    { x2 } xor ecx,ecx
    @@REDUCE_COLUMNS:
    mov esi,ebp
    {@90} lea ecx,[edx-04h]
    @chk0col:
    {0} sub edx,04h
    {1**} cmp edx,ebp
    {2**} jb @initcol
    {0**} test [edi+edx*04h+__0STARROW],ebp
    {1**} js @chk0col
    {@A0} { x1 } xor ecx,ecx; nop
    @findcolmin:
    {0} { x1 } db $8B,$5C,$02,$00 { mov ebx,[eax+edx+00h] }
    {1} or ebx,[edi+ecx*04h-10h+__COLROWMARK]
    {2} sub ecx,04h
    {0} cmp esi,ebx
    {@B0} cmova esi,ebx
    {2} add eax,ebp
    {0**} cmp ecx,ebp
    {1**} jnz @findcolmin
    {0-} xor ebx,ebx
    {1} sub ecx,04h
    {2} test esi,0FFFFFFFFh { JS/JNS can only fuse with TEST }
    {0} js @@ABNORMAL_EXIT
    {@C6} @subcol:
    {0*} add ecx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax+edx],esi
    {@D0} jnz @subcol
    {0**} cmp ebx,[edi+ecx*04h+__0STAR]
    {1**} jnz @subcol
    {2} mov [edi+edx*04h+__0STARROW],ecx
    {0} mov [edi+ecx*04h+__0STAR],edx
    {@E0} not ebx
    {2} jmp @subcol
    { x2 } cmp edi,edi

    @3RD_STEP_rowaddr:
    {0} lea eax,[ebp-04h]
    {1} sub eax,ebx
    {2} mov [edi+ebx*04h+__COLON],ecx
    {0} imul eax,ebp
    {@F2} sar eax,02h
    {2} add eax,edi
    @@3RD_STEP:
    {@F7-} mov edx,ebp
    {1} mov ecx,[esp+00h*08h+__FIXCOL]
    {@FD} @mark2row:
    {0} mov byte ptr [edi+esi*04h+__COLMARK],000h
    {@02} mov esi,[esp+__SIZE]
    {2} mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    {0} mov [esp+__OFFS+esi*08h],eax
    {1} add esi,01h
    {@11-} { x1 } nop
    @@2ND_STEP:
    {@12} mov [esp+__SIZE],esi
    @chk2col:
    {@16*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*04h+__COLROWMARK],ebp
    {0**} js @chk2col
    {@20} lea eax,[ecx+edi]
    {1} sal ecx,10h
    {2-} mov ebx,ebp
    {0} sub eax,ebp
    {@2A} @zeroincol:
    {0} movsx esi,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or esi,[eax]
    {@30} jz @zero
    {0} cmp esi,edx
    {1} cmovb edx,esi
    {2} cmovb cx,bx
    {0} sub eax,ebp
    {1*} add ebx,04h
    {@40*} jnz @zeroincol
    {@42} @zero:
    {0-} mov esi,ecx
    {1} sar ecx,10h
    {2} cmovnc esi,[edi+00h]
    {0} mov [edi+00h],esi
    {1**} test ebx,ebx
    {2**} jz @chk2col
    {@50} mov esi,[edi+ebx*04h+__0STAR]
    {1**} test esi,esi
    {2**} jz @@4TH_STEP
    {0} mov [edi+ebx*04h+__COLON],ecx
    {@60} sub eax,ecx
    {2**} { x1 } db $66,$39,$5F,$00 { cmp word [edi+00h],bx
    {0**} jz @@3RD_STEP
    {1} cmp esi,ecx
    {2} cmovl ecx,esi
    {0*} sub ecx,04h
    {@70*} jnz @mark2row
    @@5TH_STEP:
    {0} mov esi,[esp+00h*08h+__FIXCOL]
    {1} mov ebx,[esp+__SIZE]
    {2} push dword ptr [edi+00h]
    {0} jmp @chk5col
    { x2 } xor eax,eax
    {@80} @inc5mark:
    {0} mov eax,[esi+ebx]
    {1} add eax,edx
    {2} cmovc eax,[esi+ebx]
    {0} mov [esi+ebx],eax
    {1-} mov ebx,ebp
    @inc5_marked_col:
    {2} mov ebp,[esp+ecx*08h+__PUSHED]
    {@92*} sub ecx,01h
    {1*} jnc @inc5mark
    {@97} @chk5col:
    {0} lea eax,[esi+04h]
    {1-} mov esi,eax
    {2**} test eax,eax
    {0**} jz @zero5item
    {@A0} mov ecx,[edi+eax*04h+__COLROWMARK]
    {2} sub eax,ebp
    {0**} test [esp+eax*02h+__FIXCOL+__PUSHED],esi
    {1**} jns @chk5col
    {2} cmp ecx,00h
    {0-} mov ecx,ebx
    {@B0} mov ebx,[esp+__SIZE+ebx*08h+__PUSHED]
    {2} js @inc5_marked_col
    {0} movsx ebx,byte ptr [edi+ebp*04h+__ROWMARK]
    {1} add eax,edi
    {2-} mov ecx,ebp
    {0} neg edx
    {@C0} @dec5free:
    {0} or ebx,[eax]
    {1} lea ebx,[ebx+edx]
    {2} cmovs ebx,[eax]
    {0} mov [eax],ebx
    {1} movsx ebx,byte ptr [edi+ecx*04h+04h*04h+__ROWMARK]
    {2} sub eax,ebp
    {@D1*} add ecx,04h
    {1*} jnz @dec5free
    {0} neg edx
    {1} mov ebx,[esp+__SIZE+__PUSHED]
    {2} jmp @chk5col
    { x1 } nop
    {@DF} @zero5item:
    {0} pop ecx
    {@E0} movsx ebx,cx
    {2} sar ecx,10h
    {0*} add esi,[edi+ebx*04h+__0STAR]
    {1*} jnz @3RD_STEP_rowaddr
    @@4TH_STEP:
    {0} mov [edi+ebx*04h+__0STAR],ecx
    {1-} mov edx,ebx
    {2} mov ebx,[edi+ecx*04h+__0STARROW]
    {0} mov [edi+ecx*04h+__0STARROW],edx
    {@FE} mov ecx,[edi+ebx*04h+__COLON]
    {@02**} test ebx,ebx
    {0**} jnz @@4TH_STEP
    mov ecx,[esp+00h*08h+__FIXCOL]
    mov esi,ebp
    @@1ST_STEP:
    {@0C} mov ebx,[edi+esi*04h+__0STARROW]
    {1} and edx,ebx
    {2} movsx bx,byte ptr [edi+esi*04h+__FIXEDROW]
    {1} mov [edi+esi*04h+__COLROWMARK],ebx
    {0*} add esi,04h
    {2*} jnz @@1ST_STEP
    {@20-} xor edx,ebp
    {1} { x5 } mov edx,0FFFFFFFFh
    {2} js @@2ND_STEP

    {0} lea eax,[ebp-04h]
    {1-} xor edx,edx
    {2-} mov ecx,ebp
    {0} sub esp,eax
    {1} sub esp,ebp
    {2} mov ebx,[esp+__SAVE]
    {0} mov esi,[esp+__MARKS]
    @@results:
    {@40} mov eax,[edi+ecx*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add edx,[ebx+eax]
    {0} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {@50} add esi,01h
    {1*} add ecx,04h
    {2*} jnz @@results

  • P.H.

    senior tag

    Tovább zajlik az ötletcunami, az egy héttel ezelőtti verzió óta ennyivel gyorsult (már 60x60-as mátrixokon tesztelem, kisebben okafogyottá válik; 60 másodpercnyi számítási ideje van):

    Core2 (2.5 GHz): +9% (60 sec alatt 266000 -> 290000 mátrix)
    K10 (2.9 GHz): +8% (60 sec alatt 360000 -> 390000 mátrix)
    Ivy Bridge (3.8 GHz): +6% (60 sec alatt 450000 -> 480000 mátrix)

    (a * jelölés a lehetséges macro-fusion min. Sandy Bridge-n, a ** jelölés a lehetséges macro-fusion Core2-n ill. Bulldozeren, a - jelölésű utasítások nem igényelnek végrehajtót min. Sandy Bridge-en)

    xor ebx,ebx
    mov esi,ebp
    mov ecx,ebp
    and esi,-8
    add esp,ebp
    mov eax,edi
    {@F1} @mark0:
    {0} mov [edi+esi*04h+00h+__0STARROW],ebx
    {1} mov [edi+esi*04h+10h+__0STARROW],ebx
    {2*} add esi,08h
    {0*} jnz @mark0
    push edi
    @@ARGUMENT:
    { EDX: ARGUMENT memory address
    {@00} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {@10} mov [edi+ecx*04h+__COLROWMARK],esi
    {0} inc edx
    {1} mov [edi+ecx*04h+__0STAR],esi
    {2*} add ecx,04h
    {0*} jnz @@ARGUMENT
    mov edx,ebp
    {@20} jmp @freerow
    {@25} @subrow:
    {0} sub [eax+ecx],esi
    {1*} add ecx,04h
    {2*} jnz @subrow
    @@REDUCE_ROWS:
    {0*} add edx,04h
    {1*} jz @@REDUCE_COLUMNS
    @freerow:
    {2} sub eax,ebp
    {0**} cmp [edi+edx*04h+__0STAR],ecx
    {1**} jnz @@REDUCE_ROWS
    {2} or esi,-1
    {@40-} mov ecx,ebp
    {@42} @findrowmin:
    {0} mov ebx,[eax+ebp]
    {1} or ebx,[edi+ebp*04h+__0STARROW]
    {2} cmp esi,ebx
    {0} cmova esi,ebx
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {0-} mov ebp,ecx
    {1**} cmp esi,00h
    {2**} jns @subrow
    @@ABNORMAL_EXIT:
    {@5A} pop esi
    mov edx,0FFFFFFFFh
    {@60} sub esp,ebp
    mov esi,[esp+__MARKS]
    mov [esi+TRESULT.OPTIMUM],edx
    mov ebx,[esi+TRESULT.NEXTIVALUE]
    jmp dword ptr [esp+_INVALIDRESULT]
    @@REDUCE_COLUMNS:
    {0} sub edx,04h
    {1} sub eax,04h
    {2**} cmp edx,ebp
    {0**} jb @@1ST_STEP
    {1**} cmp [edi+edx*04h+__0STARROW],ecx
    {2**} jnz @@REDUCE_COLUMNS
    {@A0-} mov esi,ebp
    {@A2} @findcolmin:
    {0} mov ebx,[eax]
    {1} or ebx,[edi+ecx*04h-10h+__COLROWMARK]
    {2} sub ecx,04h
    {0} cmp esi,ebx
    {1} cmova esi,ebx
    {@B0} add eax,ebp
    {0**} cmp ecx,ebp
    {1**} jnz @findcolmin
    {0-} xor ebx,ebx
    {1} sub ecx,04h
    {2**} cmp esi,00h
    {0**} js @@ABNORMAL_EXIT
    {@C0} @subcol:
    {0*} add ecx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    {0**} cmp ebx,[edi+ecx*04h+__0STAR]
    {@CF**} jnz @subcol
    {@D1} mov [edi+edx*04h+__0STARROW],ecx
    not ebx
    mov [edi+ecx*04h+__0STAR],edx
    jmp @subcol

    @@3RD_STEP:
    {@E0} mov [edi+ebx*04h+__COLON],ecx
    {1-} mov edx,ebp
    {2} lea ecx,[ebp-04h]
    {@E9} @mark2row:
    {0} mov byte ptr [edi+ebx*04h+__ROWMARK],80h
    {1-} xor ebx,ebx
    {2} mov [edi+esi*04h+__COLMARK],bl
    @@2ND_STEP:
    {@F3*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*04h+__COLROWMARK],ebp
    {0**} js @@2ND_STEP
    {0} push ecx
    {1-} mov ebx,ebp
    {@00} sub ecx,ebp
    {@02} @zeroincol:
    {0} movsx esi,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or esi,[edi+ecx]
    {2} jz @zero
    {0} cmp esi,edx
    {1} cmovb edx,esi
    {@10} cmovb eax,ebx { >= EBP }
    {0} sub ecx,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    {@1A} @zero:
    {0} pop esi
    {1-} mov ecx,esi
    {2} shl esi,10h
    {@20} cmp eax,ebp
    {1} mov si,ax { ESI < EBP }
    {2} cmovge eax,esi
    {0**} test ebx,ebx
    {1**} jz @@2ND_STEP
    {2} mov esi,[edi+ebx*04h+__0STAR]
    {@30**} test esi,esi
    {1**} jz @@4TH_STEP
    {2**} cmp ax,bx
    {0**} jz @@3RD_STEP
    {1} cmp esi,ecx
    {2} mov [edi+ebx*04h+__COLON],ecx
    {0} cmovl ecx,esi
    {1} sub ecx,04h
    {2} jmp @mark2row
    @@5TH_STEP:
    {0} mov [edi+00h*04h+__COLROWMARK],eax
    {1-} mov ecx,edi
    {2-} mov esi,ebp
    {@66} @markedrows:
    {0} sub ecx,ebp
    {1-} xor eax,eax
    {2} cmp [edi+esi*04h+__ROWMARK],ax
    {0} setg al
    {1} mov [esp+__OFFS+ebx*04h],ecx
    {2} add ebx,eax
    {0*} add esi,04h
    {1*} jnz @markedrows
    {0} mov [esp+__SIZE],ebx
    {@80} lea esi,[ebp-04h]
    {2} jmp @check5column
    {@8A} @inc5mark:
    {0-} xor ecx,ecx
    {1} test [esi+ebx],ebp
    {2} cmovns ecx,edx
    {@92} add [esi+ebx],ecx
    {1-} mov ebx,edi
    @inc5_marked_col:
    {2} mov edi,[esp+eax*04h]
    {0*} sub eax,01h
    {1*} jns @inc5mark
    {@A0} @check5column:
    {0-} mov eax,ebx
    {1} mov ecx,[edi+esi*04h+10h+__COLROWMARK]
    {2} mov ebx,[esp+__SIZE+ebx*04h]
    {0*} { x3 } db $81,$C6,$04,$00,$00,$00 { add esi,00000004h }
    {@B0*} jz @zero5item
    {2**} { x4 } test ecx,80000000h
    {0**} js @inc5_marked_col
    {@BA} @dec5_free_col:
    {0-} mov ecx,edi
    {1-} mov ebx,ebp
    {2} sub ecx,ebp
    {@C0} @dec5free:
    {0} movsx eax,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or eax,[esi+ecx]
    {2} mov eax,00000000h
    {0} cmovns eax,edx
    {1} sub [esi+ecx],eax
    {@D2} sub ecx,ebp
    {0*} add ebx,04h
    {1*} jnz @dec5free
    {0} mov ebx,[esp+__SIZE]
    {1} jmp @check5column
    {@E0} @zero5item:
    {0} movsx ebx,cx
    {1} sar ecx,10h
    {2*} add esi,[edi+ebx*04h+__0STAR]
    {0*} jnz @@3RD_STEP
    @@4TH_STEP:
    {0} mov [edi+ebx*04h+__0STAR],ecx
    {1-} mov edx,ebx
    {2} mov ebx,[edi+ecx*04h+__0STARROW]
    {0} mov [edi+ecx*04h+__0STARROW],edx
    {1} mov ecx,[edi+ebx*04h+__COLON]
    {2**} test ebx,ebx
    {0**} jnz @@4TH_STEP
    @@1ST_STEP:
    { EDX: negative
    {@07-} mov ebx,ebp
    {@09} @restructure:
    {0} mov esi,[edi+ebx*04h+__0STARROW]
    {1} and edx,esi
    {2} add ebx,04h
    {0} movsx si,byte ptr [edi+ebx*04h-10h+__FIXEDROW]
    {1} mov [edi+ebx*04h-10h+__COLROWMARK],esi
    {2} jnz @restructure { clears EBX register }
    {0} xor edx,ebp
    {@20} lea ecx,[ebp-04h]
    {2} js @@2ND_STEP

    {0} sub esp,ecx
    {1-} xor edx,edx
    {2-} mov ecx,ebp
    {0} mov ebx,[esp+__SAVE]
    {1} mov esi,[esp+__MARKS]
    @@results:
    {@37} mov eax,[edi+ecx*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add edx,[ebx+eax]
    {@40} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {0} add esi,01h
    {1*} add ecx,04h
    {2*} jnz @@results

    A legutolsó mért eredmény 25x25-ös mátrixra 71000/sec, a fenti kód most 105000 mátrix/sec az azonos tesztadatra (+47,8%).

  • P.H.

    senior tag

    válasz P.H. #83 üzenetére

    A gulács megszá'tta a lélkömet, oszt' ezör fontosabb dolgom volt eddig, mint hajlítani ezen a programon.

    De "új év, új szemlélet", hülyébbek meg nem lettünk, szóval ugyan kisebb IPC, de okosabb megközelítés.

    Van benne egy csomó NOP is, az arra fogékonyak kedvéért.

    Sebességnövekedés:
    Pentium 4: +6%
    K10: +20,5%
    Core2 +32,4%

    xor ebx,ebx
    mov esi,ebp
    mov ecx,ebp
    and esi,-8
    add esp,ebp
    mov eax,edi
    {@F1} @mark0:
    {0} mov [edi+esi*04h+00h+__0STARROW],ebx
    {1} mov [edi+esi*04h+10h+__0STARROW],ebx
    {2*} add esi,08h
    {0*} jnz @mark0
    { x2 } nop; nop
    @@ARGUMENT:
    {@00} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {@10} mov [edi+ecx*04h+__COLROWMARK],esi
    {0} inc edx
    {1} mov [edi+ecx*04h+__0STAR],esi
    {2*} add ecx,04h
    {0*} jnz @@ARGUMENT
    { x1 } nop
    mov edx,ebp
    {@20} jmp @freerow
    { x3 } add eax,00h
    {@25} @subrow:
    {0} sub [eax+ecx],esi
    {1*} add ecx,04h
    {2*} jnz @subrow
    { x3 } add ebx,00h
    @@REDUCE_ROWS:
    {0*} add edx,04h
    {1*} jz @@REDUCE_COLUMNS
    @freerow:
    {2} sub eax,ebp
    {0**} cmp [edi+edx*04h+__0STAR],ecx
    {1**} jnz @@REDUCE_ROWS
    {2} or esi,-1
    {@40-} mov ecx,ebp
    @findrowmin:
    {@42} mov ebx,[eax+ebp]
    {1} or ebx,[edi+ebp*04h+__0STARROW]
    {2} cmp esi,ebx
    {0} cmova esi,ebx
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {0-} mov ebp,ecx
    {1**} cmp esi,00h
    {2**} jns @subrow
    @@ABNORMAL_EXIT:
    {@5A} sub esp,ebp
    mov esi,[esp+__MARKS]
    or edx,-1
    {@60} mov [esi+TRESULT.OPTIMUM],edx
    mov ebx,[esi+TRESULT.NEXTIVALUE]
    jmp dword ptr [esp+_INVALIDRESULT]
    { x3 } add ebp,00h
    @@REDUCE_COLUMNS:
    {0} sub edx,04h
    {1} sub eax,04h
    {2**} cmp edx,ebp
    {0**} jb @@1ST_STEP
    {1**} cmp [edi+edx*04h+__0STARROW],ecx
    {2**} jnz @@REDUCE_COLUMNS
    {@80-} mov esi,ebp
    {@82} @findcolmin:
    {0} mov ebx,[eax]
    {1} or ebx,[edi+ecx*04h-10h+__COLROWMARK]
    {2} sub ecx,04h
    {0} cmp esi,ebx
    {1} cmova esi,ebx
    {@90} add eax,ebp
    {0**} cmp ecx,ebp
    {1**} jnz @findcolmin
    {0-} xor ebx,ebx
    {1} sub ecx,04h
    {2**} cmp esi,00h
    {0**} js @@ABNORMAL_EXIT
    {@A0} @subcol:
    {0*} add ecx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    {0**} cmp ebx,[edi+ecx*04h+__0STAR]
    {@AF**} jnz @subcol
    {@B1} mov [edi+edx*04h+__0STARROW],ecx
    not ebx
    mov [edi+ecx*04h+__0STAR],edx
    jmp @subcol


    @@3RD_STEP:
    {@C0} mov [edi+ebx*04h+__COLON],ecx
    @re2start:
    {@C4-} mov edx,ebp
    lea ecx,[ebp-04h]
    @mark2row:
    {@C9} mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    {?-} xor ebx,ebx
    mov [edi+esi*04h+__COLMARK],bl
    @@2ND_STEP:
    {@D3} add ecx,04h
    {1*} jz @@5TH_STEP
    {2**} test [edi+ecx*04h+__COLROWMARK],ebp
    {0**} js @@2ND_STEP
    push ecx
    mov ebx,ebp
    {@E0} sub ecx,ebp
    {@E2} @zeroincol:
    {0} movsx esi,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or esi,[edi+ecx]
    {2} jz @zero
    {0} cmp esi,edx
    {1} cmovb edx,esi
    {@F0} cmovb eax,ebx { >= EBP }
    {0} sub ecx,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    {@FA} @zero:
    {0} pop esi
    {1-} mov ecx,esi
    {2} shl esi,10h
    {@00} cmp eax,ebp
    {1} mov si,ax { ESI < EBP }
    {2} cmovge eax,esi
    {0**} test ebx,ebx
    {1**} jz @@2ND_STEP
    {2} mov esi,[edi+ebx*04h+__0STAR]
    {@10**} test esi,esi
    {1**} jz @@4TH_STEP
    {2} cmp esi,ecx
    {0} mov [edi+ebx*04h+__COLON],ecx
    {1} cmovl ecx,esi
    {2**} cmp ax,bx
    {@20**} jz @re2start
    {1} sub ecx,04h
    {2} jmp @mark2row
    @@5TH_STEP:
    {0} mov [edi+00h*04h+__COLROWMARK],eax { matrix[0,
    {1-} mov esi,ebp
    {2F} @markedrows:
    {0} sub ecx,ebp
    {@31} movsx eax,byte ptr [edi+esi*04h+__ROWMARK]
    {2} mov [esp+ebx*04h+04h],ecx
    {0} sub ebx,eax
    {1*} add esi,04h
    {2*} jnz @markedrows
    {@40} mov [esp+00h],ebx
    {1} lea esi,[edi+ebp-04h]
    {2} jmp @chk5col
    @increase:
    {@49-} xor ecx,ecx
    {1} test [esi+ebx],ebp
    {2} cmovns ecx,edx
    {0} add [esi+ebx],ecx
    {1} mov ebx,[esp+eax*04h]
    @increase_marked_col:
    {2*} sub eax,01h
    {0*} jns @increase
    {1-2} { x4 } xor eax,eax; xor ecx,ecx
    @chk5col:
    {@60} sub esi,edi
    {1-} mov eax,ebx
    {2} mov ecx,[edi+esi*04h+04h*04h+__COLROWMARK]
    {0} mov ebx,[esp+ebx*04h]
    {1*} add esi,04h
    {2*} jz @zero5item
    {@70} add esi,edi
    {1} sar ecx,1Fh
    {2} js @increase_marked_col
    @decrease_free_col: { IPC: 2.6 }
    {@77} sub ecx,ebp
    {1} { x5 } mov eax,00000000h
    {2-} mov ebx,ebp
    @decrease:
    {@80} movsx eax,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or eax,[esi+ecx]
    {2} mov eax,00000000h
    {0} cmovns eax,edx
    {1} sub [esi+ecx],eax
    {2} sub ecx,ebp
    {0*} add ebx,04h
    {1*} jnz @decrease
    {0} mov ebx,[esp+00h]
    {1} jmp @chk5col
    @zero5item:
    {@9E} mov edx,ebp
    {@A0} movsx ebx,cx
    sar ecx,10h
    add esi,[edi+ebx*04h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    {0} mov [edi+ebx*04h+__0STAR],ecx
    {1-} mov edx,ebx
    {2} mov ebx,[edi+ecx*04h+__0STARROW]
    {0} mov [edi+ecx*04h+__0STARROW],edx
    {1} mov ecx,[edi+ebx*04h+__COLON]
    {2**} test ebx,ebx
    {0**} jnz @@4TH_STEP
    @@1ST_STEP:
    {@86-} mov ebx,ebp
    @restructure:
    {@88} mov esi,[edi+ebx*04h+__0STARROW]
    {1} and edx,esi
    {2} movsx si,byte ptr [edi+ebx*04h+__FIXEDROW]
    {0} mov [edi+ebx*04h+__COLROWMARK],esi
    {1*} add ebx,04h
    {2*} jnz @restructure
    xor edx,ebp
    {9E} lea ecx,[ebp-04h]
    js @@2ND_STEP


    xor edx,edx
    sub esp,ebp
    mov ecx,ebp
    mov ebx,[esp+__SAVE]
    mov esi,[esp+__MARKS]
    @@results:
    {@B5} mov eax,[edi+ecx*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add edx,[ebx+eax]
    {0} sub eax,ebp
    {@C0} shr eax,02h
    {2} mov [esi],al
    {1} add esi,01h
    {2*} add ecx,04h
    {0*} jnz @@results

  • P.H.

    senior tag

    {@50} { x1 } nop
    @ENTRY:
    {@51} mov ebp,[esi-08h+_PRIO]
    movd edi,mm4
    mov ecx,[esi-08h+_DIST]
    or eax,-1
    mov edi,[edi+ebp*04h]
    {@60} movq mm1,[esi+ebx*08h]
    sub ebx,eax
    jg @finish
    movd mm2,[esi-08h+_DIST]
    jz @descriptor
    {@6E} prefetchnta [edi]
    {@71} jmp @down
    @movedown:
    {0}mov ebp,[esi+eax*08h+_PRIO]
    {1}mov [esi+ecx*08h+_DIST],edx
    {2}mov [esi+ecx*08h+_PRIO],ebp
    @down:
    {0}mov [esi+ebp*04h+_CONN],ecx
    {@80}{1}mov ecx,eax
    {2}add eax,eax
    {0}cmp eax,ebx
    {1}jb @INSERTDOWN
    {2}mov edx,[esi+eax*08h-00h+_DIST]
    {0}cmp [esi+eax*08h-08h+_DIST],edx
    {@90}{1}cmovb edx,[esi+eax*08h-08h+_DIST]
    {2}sbb eax,00h
    {0}cmp edx,[esi+ebx*08h-08h+_DIST]
    {1}jb @movedown
    {2}{ x2 } xor eax,eax
    @INSERTDOWN:
    {@A0} movd ebp,mm1
    movq [esi+ecx*08h],mm1
    @descriptor:
    movzx edx,word ptr [edi+HEADER.RCSIZE]
    lea edx,ds:[edi+HEADERSIZE+edx-RECORDSIZE]
    {@B0} add edi,HEADERSIZE
    mov [esi+__COUNTER],edx
    mov [esi+ebp*04h+_CONN],ecx
    jmp @nxrecord
    { x6 } mov eax,00000000h; nop
    @INSERTUP:
    {@C0} mov [esi+ebp*08h+_PRIO],ecx
    mov [esi+ebp*08h+_DIST],edx
    movd ebx,mm0
    mov [esi+ecx*04h+_CONN],ebp
    @CONNECTS:
    cmp edi,[esi+__COUNTER]
    {@CF} jae @entry
    {@D1} add edi,TMAPRECORDSIZE
    @nxrecord:
    {@D4} mov ecx,ds:[edi+RECORD.LINKED]
    mov eax,[esi+ecx*04h+_CONN]
    cmp eax,01h
    jge @connects
    {@E0} movzx edx,word ptr [edi+RECORD.FIELD0]
    movd ebp,mm2
    lea edx,ds:[ebp+edx]
    sbb ebp,ebp
    xor edx,ebp
    {@EF} cmp edx,[esi+eax*08h+_DIST]
    {@F3} jge @connects
    add ebx,ebp
    xor edx,ebp
    and ebp,ebx
    add eax,ebp
    movd mm0,ebx
    @moveup:
    {@00}{0}mov ebp,eax
    {1}sar eax,01h
    {2}adc eax,00h
    {0}cmp edx,[esi+eax*08h+_DIST]
    {1}jae @INSERTUP
    {2}mov ebx,[esi+eax*08h+_PRIO]
    {@10}{0}movq mm1,[esi+eax*08h]
    {1}movq [esi+ebp*08h],mm1
    {2}mov [esi+ebx*04h+_CONN],ebp
    {0}jmp @moveup

  • P.H.

    senior tag

    válasz P.H. #84 üzenetére

    A vonalakhoz tartozó koordináták kiszámolása (a gráf sajátosságai szerint) és a látható pontok összegyűjtése:

    push eax
    or ebp,-1
    mov edx,00000001h
    xorps xmm2,xmm2
    {@4F} mov ebx,[source]
    cvtsi2ss xmm1,edx
    movlps xmm2,[eax+TMAP.NX]
    xorps xmm3,xmm3
    {@60} mov esi,[destination]
    divss xmm1,[eax+TMAP.ZOOM]
    xorps xmm0,xmm0
    mov edi,[ebx+04h]
    {@70} cvtpi2ps xmm3,[eax+TMAP.BITMAP+TBITMAPFILE.XSIZE]
    shufps xmm1,xmm1,10100000b
    jmp @storecoor
    { x6 } add eax,00h; add edx,00h
    { x1 } nop
    @SSEcoor:
    {@81}{0}movlps xmm0,[edi+HEADER.X]
    {1}movzx eax,byte ptr [edi+HEADER.FIELD0]
    {2}movaps xmm5,xmm1
    {0}movzx ebx,word ptr [edi+HEADER.SIZE]
    {@90}{1}mulps xmm5,xmm0
    {2}movaps xmm4,xmm3
    {0}subps xmm5,xmm2
    {1}add eax,eax
    {2}sub ebx,01h
    {0}movlhps xmm4,xmm5
    {@A1}{1}movsx ebp,al
    {2}or ebp,ebx
    {0}cvtps2pi mm0,xmm5
    {1}sar ebp,1Fh
    {2}cmp byte ptr [edi+HEADER.FIELD1],01h
    {@B0}{0}subps xmm4,xmm5
    {1}mov [esi],edi
    {2}movmskps edx,xmm4
    {0}sbb ebp,edx
    {1}movq [edi+HEADER.XCOOR],mm0
    {2}sar ebp,1Fh
    {@C0}{0}rcr al,01h
    {1}mov [edi+HEADER.FIELD0],al
    {2}lea edi,[edi+ebx+HEADERSIZE+01h]
    @storecoor:
    {0}lea esi,[esi+ebp*04h+04h]
    {1}sub ecx,01h
    {@D0}{2}jnle @SSEcoor
    pop eax
    xor ecx,ecx
    emms
    mov [esi],ecx

  • P.H.

    senior tag

    válasz P.H. #39 üzenetére

    SSE1 line algoritmus azonos stílusú vonalak láncolt listájára, a #39-hez képest megtáltosítva; align/cím- és Northwood + Merom + K10 portelemzéssel.

    Intel processzorokon Core2 óta a MOVD reg,mmreg (2 órajel) gyorsabb, mint az L1D-olvasás (3-4 órajeé), a Sandy Bridge óra pedig kvázi +regiszterkészletként használhatóak az MMX és XMM regiszterek (1 órajel a MOVD oda-vissza). K10-en sem lassabb a MOVD reg,mmreg, mint az L1D-hozzáférés.

    {@31} lea edi,[esi+TBITMAPFILE.IDATA+_ADDER] // p01 d (1) alu p0 1 (1) p012 1 (1) ALU
    xorps xmm1,xmm1 // p1 2 (1) mmxalu p015 1 (1) p34 2 (1) FA/M
    mov eax,[esi+TBITMAPFILE.IDATA+_DX] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    {@40} cvtpi2ps xmm3,[edi-_ADDER+_TOPLEFT0] // p1+2 10 (4) mmx+load p1+2 (1) p34+5 7 (2) FPU+MEM
    pcmpeqd xmm4,xmm4 // p1 2 (1) mmxalu p01 1 (1) p34 2 (1) FA/M
    cvtpi2ps xmm2,[edi-_ADDER+_RIGHT] // p1+2 10 (4) mmx+load p1+2 (1) p34+5 7 (2) FPU+MEM
    pcmpeqd xmm7,xmm7 // p1 2 (1) mmxalu p01 1 (1) p34 2 (1) FA/M
    {@50} mov ecx,[edi-_ADDER+_PEN] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    pslld xmm4,25 // p1 2 (1) mmxshf p0 1 (1) p34 3 (1) FA/M
    mov esi,[esi+TBITMAPFILE.BITS] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    pslld xmm7,1Fh // p1 2 (1) mmxshf p0 1 (1) p34 3 (1) FA/M
    {@60} movd mm2,[edi-_ADDER+_COLOR] // p2 8 (1) mmxalu p2 2 (1) p345 4 (1) FANY
    shl eax,10h // p1 4 (1) mmxshf p05 1 (1) p012 1 (1) ALU
    movlhps xmm3,xmm2 // p1 2 (1) mmxshf p0 1 (1) p34 3 (1) FA/M
    add eax,01h // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    sub edi,ecx // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    {@6F} psrld xmm4,02h // p1 2 (1) mmxshf p0 1 (1) p34 3 (1) FA/M
    movd mm0,eax // p1 2 (2) mmxalu p05 2 (1) p012 6 (2) ALU
    jmp @1stline // p1 0 (1) branch p5 1 (1) p012 2 (1) ALU
    { x7 } mov eax,00000000h; mov edx,ecx //
    @reorder: //
    {@80} shufps xmm0,xmm0,11011000b // p1 4 (1) mmxshf p1 3 (3) p34 3 (1) FA/M
    @setpixels: //
    {@84} cvtps2pi mm1,xmm5 // p0+1 7 (3) fp-mmx p1 3 (1) p5 4 (1) FMISC
    movaps xmm2,xmm3 // p0 6 (1) mov p015 1 (1) p345 2 (1) FANY
    mov ebx,ecx // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    pshufw mm1,mm1,11011000b // p1 2 (1) mmxshf p5 1 (1) p34 2 (1) FA/M
    {@90} cmpltps xmm2,xmm5 // p1 4 (1) fpadd p1 3 (1) p3 (1) FADD
    addps xmm5,xmm0 // p1 4 (1) fpadd p1 3 (1) p3 4 (1) FADD
    pmaddwd mm1,mm0 // p1 6 (1) fpmul p1 3 (1) p4 3 (1) FMUL
    movmskps edx,xmm2 // p1 6 (2) fp p0 1 (1) p34 3 (1) FA/M
    cmp edx,03h // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    {@A0} jnz @continueLINE // p0 2 (1) alu p5 1 (1) p012 1 (1) ALU
    movd edx,mm1 // p0 5 (2) fp p015 2 (1) p3 3 (1) FADD
    @round: //
    add edx,[edi+ebx] // p01+2 d+2(2) alu+load p015+2 (1) p012 4 (1) ALU+MEM
    mov [esi+edx],al // p0+3 2 (3) store p 34 3 (1) p012 3 (1) MEM
    add ebx,04h // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    js @round // p0 0 (1) branch p5 1 (1) p012 1 (1) ALU
    @continueLINE: //
    {@B0} sub ebp,01h // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    jge @setpixel // p0 0 (1) branch p5 1 (1) p012 1 (1) ALU
    @nxline: //
    {@B5} movd ebx,mm3 // p0 5 (2) fp p015 2 (1) p3 3 (1) FADD
    @1stline: //
    {@B8} cmp ebx,00h // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    jz @return // p0 0 (1) branch p5 1 (1) p012 1 (1) ALU
    mov eax,[ebx+TMAPRECORD.REF] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    {@C0} mov edx,[ebx+TMAPRECORD.SELF] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    mov ebp,[eax+TMAPHEADER.YCOOR] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    cvtpi2ps xmm5,[edx+TMAPHEADER.XCOOR] // p1+2 10+2(4) mmx+load p1+2 (1) p34+5 7 (2) FPU+MEM
    mov eax,[eax+TMAPHEADER.XCOOR] // p2 2 (1) load p2 2 (1) p012 3 (1) MEM
    sub ebp,[edx+TMAPHEADER.YCOOR] // p01+2 d+2(2) alu+load p015+2 (1) p012 4 (1) ALU+MEM
    sub eax,[edx+TMAPHEADER.XCOOR] // p01+2 d+2(2) alu+load p015+2 (1) p012 4 (1) ALU+MEM
    {@D0} xor edx,edx // p0 d (1) logic p015 1 (1) p012 1 (1) ALU
    movlhps xmm5,xmm5 // p1 2 (1) mmxshf p0 1 (1) p34 3 (1) FA/M
    movd mm3,ds:[ebx+TMAPRECORD.NX] // p2 8 (1) mmxalu p2 2 (1) p345 4 (1) FANY
    xor ebx,ebx // p0 d (1) logic p015 1 (1) p012 1 (1) ALU
    sub edx,ebp // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    cmovs edx,ebp // p0+1 6 (3) alu p015 2 (2) p012 1 (1) ALU
    {@E0} sub ebx,eax // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    cmovs ebx,eax // p0+1 6 (3) alu p015 2 (2) p012 1 (1) ALU
    cmp edx,ebx // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    mov ebx,ebp // p01 d (1) alu p015 1 (1) p012 1 (1) ALU
    cmovb ebx,eax // p0+1 6 (3) alu p015 2 (2) p012 1 (1) ALU
    cmovb eax,ebp // p0+1 6 (3) alu p015 2 (2) p012 1 (1) ALU
    cmovb ebp,ebx // p0+1 6 (3) alu p015 2 (2) p012 1 (1) ALU
    {@F2} sbb edx,edx // p1 5 (3) alu p015 2 (2) p012 1 (1) ALU
    neg ebx // p0 d (1) alu0 p015 1 (1) p012 1 (1) ALU
    mov ecx,ecx //
    cvtsi2ss xmm0,eax // p1 10 (3) fp-mmx p1 4 (1) p345 14 (v) FPU+ALU
    cvtsi2ss xmm1,ebp // p1 10 (3) fp-mmx p1 4 (1) p345 14 (v) FPU+ALU
    {@00} movaps xmm2,xmm1 // p0 6 (1) mov p015 1 (1) p345 2 (1) FANY
    divss xmm0,xmm1 // p1 23 (1) fpdiv p0 17 (1) p4 16 (1) FMUL
    cmovns ebp,ebx // p0+1 6 (3) alu p015 2 (2) p012 1 (1) ALU
    shufps xmm2,xmm2,00000000b // p1 4 (1) mmxshf p1 3 (3) p34 3 (1) FA/M
    test edx,edx // p0 d (1) logic p015 1 (1) p012 1 (1) ALU
    {@10} andps xmm2,xmm7 // p1 2 (1) mmxalu p015 1 (1) p34 2 (1) FA/M
    shufps xmm0,xmm4,00000000b // p1 4 (1) mmxshf p1 3 (3) p34 3 (1) FA/M
    movd eax,mm2 // p0 5 (2) fp p015 2 (1) p3 3 (1) FADD
    xorps xmm0,xmm2 // p1 2 (1) mmxalu p015 1 (1) p34 2 (1) FA/M
    {@1D} jz @reorder // p0 0 (1) branch p5 1 (1) p012 2 (1) ALU
    {@23} shufps xmm0,xmm0,01110010b // p1 4 (1) mmxshf p1 3 (3) p34 3 (1) FA/M
    jmp @setpixels // p1 0 (1) branch p5 1 (1) p012 2 (1) ALU
    @return:
    popad
    emms

  • P.H.

    senior tag

    A mátrixokat kiszámoló algoritmus is kis átszervezésen esett át.

    AMD CPU-k 2 órajelenként tudnak végrehajtani egy ugrást, így a 3 utasításból álló ciklusok nem hatékonyak, egy-egy ciklus ugyanúgy legalább 2 órajel alatt fog lefutni, mint a 4-5-6 utasításból állóak; így érdemes ezekbe beletuszkolni további műveleteket, pl. hogy a ciklus feleannyiszor fusson le.

    Továbbá Intel processzorokon nem mindegy, hogy a kizárólag align-ra szolgáló, soha le nem futó átugrott kódrészek NOP-ból vagy más, nagyobb utasításból állnak (pl. 8 NOP vagy csak 3 utasítás, mint mov esi,esi; nop; mov eax,7FFFFFFFh): The maximum throughput of the predecoders is 16 bytes or 6 instructions per clock cycle, whichever is smallest. The throughput of the rest of the pipeline is typically 4 instructions per clock cycle, or 5 in case of macro-op fusion.[...] The predecoder throughput can also be reduced if there are more than 6 instructions in a 16-bytes block of code. The reason for this is that the predecoder will not load a new 16-bytes block of code until the previous block is exhausted. If there are 7 instructions in a 16-bytes block then the predecoders will process the first 6 instructions in the first clock cycle and 1 instruction in the next clock cycle.
    Emellett az uop-cache-sel rendelkező Intel CPU-knál 1-1 32 byte-os kódrészhez maximum 3x6 uop tartozhat; amely kódrész ebben nem fér bele (pl. mert 16-nál több - akár le nem futó - NOP-ot tartalmaz), az nem kerül be ebbe a cache-be. Nem tisztázott, hogy ezek a NOP-ok beleszámítanak-e itt a 3x6 uop-számba.

    xor ebx,ebx
    mov esi,ebp
    mov ecx,ebp
    and esi,-8
    {@F1} @mark0:
    {0} mov [edi+esi*04h+00h+__0STARROW],ebx
    {1} mov [edi+esi*04h+10h+__0STARROW],ebx
    {2*} add esi,08h
    {0*} jnz @mark0
    { x2 } nop; nop
    @@ARGUMENT:
    {@00} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {@10} mov [edi+ecx*04h+__COLROWMARK],esi
    {0} inc edx
    {1} mov [edi+ecx*04h+__0STAR],esi
    {2*} add ecx,04h
    {0*} jnz @@ARGUMENT
    { x1 } nop
    mov eax,edi
    {@20} lea edx,[ebp-04h]
    jmp @@REDUCE_ROWS
    { x3 } nop; nop; nop
    {@28} @subrow:
    {0} sub [eax+ecx],esi
    {1*} add ecx,04h
    {2*} jnz @subrow
    @@REDUCE_ROWS:
    {0*} add edx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} or esi,-1
    {1*} cmp [edi+edx*04h+__0STAR],ecx
    {2*} jnz @@REDUCE_ROWS
    {@40} mov ecx,ebp
    @findrowmin:
    {@42} mov ebx,[eax+ebp]
    {1} or ebx,[edi+ebp*04h+__0STARROW]
    {2} cmp esi,ebx
    {0} cmova esi,ebx
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {0} mov ebp,ecx
    {1*} test esi,esi
    {2*} jns @subrow
    @@ABNORMAL_EXIT:
    {@59} mov esi,[esp+__MARKS]
    or edx,-1
    {@60} mov [esi+TRESULT.OPTIMUM],edx
    mov ebx,[esi+TRESULT.NEXTIVALUE]
    jmp dword ptr [esp+_INVALIDRESULT]
    { x2 } mov edi,edi
    @@REDUCE_COLUMNS:
    {@6C} sub edx,04h
    {1} sub eax,04h
    {2*} cmp edx,ebp
    {0*} jb @@1ST_STEP
    {1*} cmp [edi+edx*04h+__0STARROW],ecx
    {2*} jnz @@REDUCE_COLUMNS
    {@80} or esi,-1
    {@83} @findcolmin:
    {0} mov ebx,[eax]
    {1} or ebx,[edi+ecx*04h-10h+__COLROWMARK]
    {2} sub ecx,04h
    {0} cmp esi,ebx
    {1} cmova esi,ebx
    {2} add eax,ebp
    {0*} cmp ecx,ebp
    {1*} jnz @findcolmin
    xor ebx,ebx
    sub ecx,04h
    test esi,esi
    js @@ABNORMAL_EXIT
    {@A0} @subcol:
    {0*} add ecx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    cmp ebx,[edi+ecx*04h+__0STAR]
    {@AF} jnz @subcol
    {@B1} mov [edi+edx*04h+__0STARROW],ecx
    not ebx
    mov [edi+ecx*04h+__0STAR],edx
    jmp @subcol
    {@BD} { x3 } nop; nop; nop
    {@C0} { x11 } mov eax,7FFFFFFFh; add edx,00h; add ecx,00h
    { x12 } mov eax,7FFFFFFFh; add edx,00h; lea esi,[esi+00h]

    @@3RD_STEP:
    {0} mov [edi+ebx*04h+__COLON],ecx
    {1} or eax,-1
    {2} mov ecx,ebp
    @markrow:
    {@E0} mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    mov byte ptr [edi+esi*04h+__COLMARK],00h
    @@2ND_STEP:
    sub ecx,04h
    @chk2mtx:
    {@EC} mov esi,edi
    mov ebx,ebp
    {@F0} @check2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2} cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    {0} jnz @check2col
    {0} sub ecx,ebp
    {1} add esi,ecx
    {@00} push ecx
    {@01} @zeroincol:
    {0} movsx ecx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or ecx,[esi]
    {2} jz @zero
    {0} cmp ecx,eax
    {1} cmovb eax,ecx
    {2} cmovb edx,ebx
    {0} sub esi,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    {@18} @zero:
    {0} pop esi
    {1} lea ecx,[esi+ebp]
    {2} shl esi,10h
    {0} cmp edx,00h
    {1} mov si,dx
    {2} cmovs edx,esi
    {0*} test ebx,ebx
    {1*} jz @chk2mtx
    {2} mov esi,[edi+ebx*04h+__0STAR]
    {@30*} test esi,esi
    {1*} jz @@4TH_STEP
    {2} cmp esi,ecx
    {0} mov [edi+ebx*04h+__COLON],ecx
    {1} cmovl ecx,esi
    {2} cmp dx,bx
    {@40} cmovz ecx,ebp
    {1} cmovz eax,ebp
    {2} jmp @markrow
    { x8 } mov esi,esi; nop; mov eax,7FFFFFFFh
    @@5TH_STEP:
    {@50} push edx
    {@51} @nx5row:
    {0} movsx edx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} sub esi,ebp
    {2} sub ecx,eax
    {0} xor edx,eax
    {1} cmovs eax,ecx
    {2} mov ecx,ebp
    {@60} @decrease_row_free:
    {0} mov edx,[edi+ecx*04h+__COLROWMARK]
    {1} xor edx,eax
    {2} or edx,[esi+ecx]
    {0} mov edx,00000000h
    {1} cmovns edx,eax
    {@70} sub [esi+ecx],edx
    {0*} add ecx,04h
    {1*} jnz @decrease_row_free
    {0*} add ebx,04h
    {1*} jnz @nx5row
    {@7D} pop ecx
    { x2 } nop; nop
    {@80} movsx ebx,cx
    shr ecx,10h
    add ecx,ebp
    mov esi,[edi+ebx*04h+__0STAR]
    test esi,esi
    {@8E} jnz @@3RD_STEP
    @@4TH_STEP:
    {0} mov [edi+ebx*04h+__0STAR],ecx
    {1} mov edx,ebx
    {2} mov ebx,[edi+ecx*04h+__0STARROW]
    {0} test ebx,ebx
    {@A0} mov [edi+ecx*04h+__0STARROW],edx
    {2} mov ecx,[edi+ebx*04h+__COLON]
    {0} jnz @@4TH_STEP
    @@1ST_STEP:
    {@AA} mov ecx,ebp
    @restructure:
    {0} mov ebx,[edi+ebp*04h+__0STARROW]
    {@B0} and edx,ebx
    {2} movsx bx,byte ptr [edi+ebp*04h+__FIXEDROW]
    {0} mov [edi+ebp*04h+__COLROWMARK],ebx
    {1*} add ebp,04h
    {2*} jnz @restructure
    {@C0} mov ebp,ecx
    or eax,-1
    test edx,edx
    jns @@2ND_STEP

    {@CD} mov ebx,[esp+__SAVE]
    {@D1} xor edx,edx
    mov esi,[esp+__MARKS]
    @@results:
    {@D7} mov eax,[edi+ecx*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add edx,[ebx+eax]
    {@E0} sub eax,ebp
    {1} shr eax,02h
    {2} mov [esi],al
    {0} lea esi,[esi+01h]
    {1*} add ecx,04h
    {2*} jnz @@results
    {@F0} ...

  • P.H.

    senior tag

    válasz P.H. #80 üzenetére

    Egy év eltelt, kissé változott a kódolás, de még fontosabb, hogy elkészült a hozzá tartozó egy szálas kiszolgáló kód - amely előkészíti a kiszámolandó mátrixokat - végleges(?) 32 bites változata. Ennek teljes kidolgozása +8-9% sebességnövekedést okozott K10-en.

    jmp @@NEXTMATRIX
    @terminate:
    { x1 } nop
    jmp @@READY
    @@NEXTMATRIX:
    {align $34} nop; mov eax,[APPLICATION]; call TAPPLICATION.PROCESSMESSAGES
    {align $40} mov [ebx+TTSP30.COLLECTOR],edi
    or ecx,-1
    mov eax,[ebx+TTSP30.MEMORY]
    test cl,[ebx+TTSP30.CIRCLESTOP]
    jnz @terminate
    add [ebx+TTSP30.GLOBALSIZE],eax
    {align $50} mov [ebx+TTSP30.MEMORY],ecx
    mov edx,esi
    mov ebp,[esi+TCIRCLE.NEXT]
    cmovc edx,ebp
    mov eax,[edi+TCIRCLE.NEXT]
    cmovc ebp,eax
    {align $5F} mov [ebx+TTSP30.ENTRY],edx
    {align $62} cmovc eax,esi
    mov [esi+TCIRCLE.NEXT],ebp
    mov [edi+TCIRCLE.NEXT],eax
    lea esi,[ebx+TTSP30.RESULTS]
    cmp edx,ebp
    jz @terminate
    {align $70} mov ebx,[edx+TCIRCLE.QUANTITY]
    add dword ptr [edx+TCIRCLE.QUANTITY],02h
    mov ebp,[esp+_ROWSIZE4]
    mov edi,[esp+_CMTX]
    shr ebx,03h
    @createBASE:
    {align $81} mov eax,[edx+ebx*08h+04h]
    mov [esp+_BASEELEMENT+ebx*08h+04h],eax
    mov eax,[edx+ebx*08h+00h]
    mov [esp+_BASEELEMENT+ebx*08h+00h],eax
    {align $90} dec ebx
    jnz @createBASE
    {align $93} add edx,offset(TCIRCLE.SUGGESTED)
    movzx eax,al
    mov [esp+_BASEELEMENT+TCIRCLE.NEXT],edx
    cmp [edx+eax],bl
    {align $A0} jl @matrix0
    mov [esp+_CDEST],ebx
    @INVALIDmatrix:
    {align $A6} mov dword ptr [esi+TRESULT.OPTIMUM],0FFFFFFFFh
    inc ebx
    mov ecx,eax
    @create_matrixes:
    {align $B0} movzx eax,byte ptr [esp+_BASEELEMENT+TCIRCLE.SHORTEST+ebx+00h]
    cmp al,byte ptr [edx-TCIRCLE.SUGGESTED+TCIRCLE.SHORTEST+00h]
    jz @@CHECKRESULTS
    mov [edx+ecx],al
    add esi,TRESULTSIZE
    {align $C0} cmp byte ptr [edx+eax],0FFh
    jnz @INVALIDmatrix
    @matrix0:
    movzx ebx,byte ptr [esp+_BASEELEMENT+TCIRCLE.SHORTEST+ebx+01h]
    mov ecx,[esp+_SIZE2BYTE]
    imul eax,ebp
    shl ebx,02h
    mov [esp+_CDEST],esi
    sub ebx,eax
    mov eax,[esp+_SAVEMTX]
    mov [esi+TRESULT.NXTILTED],ebx
    @copyMTX:
    {align $E2} mov esi,[eax+ecx+04h]
    mov [edi+ecx+04h],esi
    mov esi,[eax+ecx]
    mov [edi+ecx],esi
    {align $F0} sub ecx,08h
    jns @copyMTX
    {align $F5} lea ecx,[esp+_BASEELEMENT+TCIRCLE.TILTEDS]
    mov eax,[esp+_COUNT386]
    @tilt:
    {align $00} mov [edi+ebx],ebp
    movzx ebx,word ptr [ecx]
    add ecx,02h
    test ebx,ebx
    jnz @tilt
    jmp eax
    { x1 } nop
    @VALIDmatrix:
    {align $10} mov ebx,[esi+TRESULTSIZE+TRESULT.IVALUE]
    mov [esi+TRESULT.OPTIMUM],edx
    mov [esi+TRESULT.CCIRCLE],ecx
    mov edx,[esp+_BASEELEMENT+TCIRCLE.NEXT]
    {align $20} movzx ecx,byte ptr [esp+_BASEELEMENT+TCIRCLE.SHORTEST+ebx-01h]
    jmp @create_matrixes
    { x2 } nop; nop
    @@CHECKRESULTS:
    {align $29} add [CIRCLEVAR],ebx
    mov ebx,offset(TSP30)
    mov ebp,offset(TSP30.RESULTS)
    mov edi,[ebx+TTSP30.COLLECTOR]
    @@AFTERCIRCLE:
    mov eax,[esp+_BASEELEMENT+TCIRCLE.QUANTITY]
    { x1 } nop
    @@HEADMATRIX:
    {align $40} mov esi,[ebx+TTSP30.ENTRY]
    @next:
    cmp ebp,[esp+_CDEST]
    ja @@NEXTMATRIX
    mov ecx,[ebp+TRESULT.OPTIMUM]
    {align $50} add ebp,TRESULTSIZE
    { x1 } nop
    cmp ecx,[ebx+TTSP30.GLOBALOPTIMUM]
    jae @next
    mov edx,[ebp-TRESULTSIZE+TRESULT.CCIRCLE]
    cmp edx,[esp+_MTXSIZE]
    {align @60} jz @@CIRCLE0
    { x1 } nop
    cmp dword ptr [edi+TCIRCLE.NEXT],00h
    jz @@PLUSMEM
    @enqueue:
    add dword ptr [ebx+TTSP30.MEMORY],01h
    {align $70} cmovnz esi,[edi+TCIRCLE.NEXT]
    { x1 } nop
    cmovnz edi,esi
    mov [esi+TCIRCLE.RESULT],ecx
    movzx ecx,dl
    shr edx,08h
    {align $80} lea ebx,[esi+TCIRCLE.SHORTEST+ecx]
    neg ecx
    mov [ebx],dl
    @shortest:
    mov [ebx+ecx],dl
    movzx edx,byte ptr [ebp-TRESULTSIZE+TRESULT.ORDERSET+edx]
    {align $90} add ecx,01h
    jnz @shortest
    movzx edx,byte ptr [esp+_BASEELEMENT+TCIRCLE.SHORTEST+00h]
    lea ebx,[eax-TCIRCLE.QUANTITY]
    shr ebx,03h
    @clone:
    {align $A0} mov eax,[esp+_BASEELEMENT+ebx*08h+04h+TCIRCLE.QUANTITY]
    mov [esi+ebx*08h+04h+TCIRCLE.QUANTITY],eax
    mov eax,[esp+_BASEELEMENT+ebx*08h+00h+TCIRCLE.QUANTITY]
    mov [esi+ebx*08h+00h+TCIRCLE.QUANTITY],eax
    {align $B0} dec ebx
    jns @clone
    mov ebx,[ebp-TRESULTSIZE+TRESULT.NXTILTED]
    mov [esi+eax-02h],ebx
    lea ebx,[TSP30]
    @suggest:
    {align $C0} cmp ecx,[ebp-TRESULTSIZE+TRESULT.IVALUE]
    jae @@HEADMATRIX
    movzx ebx,byte ptr [esp+_BASEELEMENT+TCIRCLE.SHORTEST+ecx+01h]
    add ecx,01h
    mov byte ptr [esi+TCIRCLE.SUGGESTED+edx],bl
    mov edx,ebx
    mov ebx,offset(TSP30)
    jmp @suggest
    {align $DE} { x3 } nop; nop; nop
    { x8 } nop; nop; nop; nop; nop; nop; nop; nop
    @@PLUSMEM:
    {align $E9} lea eax,[ebx+TTSP30.WORKAREAS]; xor edx,edx; call _ADDINT
    mov edx,[ebx+TTSP30.STRUCTURESIZE]; mov ecx,3000; call _REALLO
    {align $00} add [ebx+TTSP30.COLLECTED],ecx
    dec ecx
    @setmem:
    {align $04} mov [eax+edx+TCIRCLE.NEXT],eax
    add eax,edx
    sub ecx,01h
    jnz @setmem
    {align $0E} mov edx,[ebp-TRESULTSIZE+TRESULT.CCIRCLE]
    mov ecx,[ebp-TRESULTSIZE+TRESULT.OPTIMUM]
    mov [edi+TCIRCLE.NEXT],eax
    mov eax,[esp+_BASEELEMENT+TCIRCLE.QUANTITY]
    jmp @enqueue
    { x1 } nop
    @@CIRCLE0:
    ...

  • P.H.

    senior tag

    Miért is kell(ene) az AGLU a Bulldozer-be?
    "And two which handle address generation and simple ALU operations (AGLU)."

    Nézzük ezt az egyszerű for-ciklust:
    @decrease_free_row:
    mov edx,[edi+ecx*04h+__COLROWMARK]
    xor edx,eax
    or edx,[esi+ecx]
    mov edx,00000000h
    cmovns edx,eax
    sub [esi+ecx],edx
    add ecx,04h
    jnz @decrease_row_free

    Tegyük fel, hogy rendesen igazított a kód, azaz teljesen belefér egy 32 byte-os aligned memóriaterületre, így a dekódolás nem szűk keresztmetszet.

    A következő lefutási képe van 4 cikluslefutásnak K10-en (K10-en kénytelen azon az ALU/AGU-n futni az utasítás, amelyre a dekódolás során esik az adott órajelben dekódolt utasításhármasban):
    decode:
    00 (1)mov edx,[edi+ecx*04h+__COLROWMARK] (1)xor edx,eax (1)or edx,[esi+ecx]
    01 (1)mov edx,00000000h (1)cmovns edx,eax (1)sub [esi+ecx],edx
    02 (1)add ecx,04h (1)jnz @decrease_row_free (1)
    03 (2)mov edx,[edi+ecx*04h+__COLROWMARK] (2)xor edx,eax (2)or edx,[esi+ecx]
    04 (2)mov edx,00000000h (2)cmovns edx,eax (2)sub [esi+ecx],edx
    05 (2)add ecx,04h (2)jnz @decrease_row_free (2)
    06 (3)mov edx,[edi+ecx*04h+__COLROWMARK] (3)xor edx,eax (3)or edx,[esi+ecx]
    07 (3)mov edx,00000000h (3)cmovns edx,eax (3)sub [esi+ecx],edx
    08 (3)add ecx,04h (3)jnz @decrease_row_free (3)
    09 (4)mov edx,[edi+ecx*04h+__COLROWMARK] (4)xor edx,eax (4)or edx,[esi+ecx]
    10 (4)mov edx,00000000h (4)cmovns edx,eax (4)sub [esi+ecx],edx
    11 (4)add ecx,04h (4)jnz @decrease_row_free (4)

    exec:
    clk 1. ALU 1.AGU | 2. ALU 2.AGU | 3. ALU 3.AGU
    ---------------------------------------- | ------------------------------------- | -----------------------------------
    01 (1)mov edx,[esi+ecx*4] | | (1)ld x1,[esi+ecx]
    02 (1)mov edx,0 | | (1)ld y1,[esi+ecx]
    03 (1)add ecx,4 | |
    04 (2)mov edx,[esi+ecx*4] | (1)xor edx,eax | (2)ld x2,[esi+ecx]
    05 (2)mov edx,0 | (1)jnz @decrease_free_row | (1)or edx,x1 (2)ld y2,[esi+ecx]
    06 (2)add ecx,4 | (1)cmovns edx,eax |
    07 (3)mov edx,[esi+ecx*4] | (2)xor edx,eax | (1)sub y1,edx (3)ld x3,[esi+ecx]
    08 (3)mov edx,0 | (2)jnz @decrease_free_row | (2)or edx,x2 (1)st [esi+ecx],y1
    09 (3)add ecx,4 | (2)cmovns edx,eax | (3)ld y3,[esi+ecx]
    10 (4)mov edx,[esi+ecx*4] | (3)xor edx,eax | (2)sub y2,edx (4)ld x4,[esi+ecx]
    11 (4)mov edx,0 | (3)jnz @decrease_free_row | (3)or edx,x3 (2)st [esi+ecx],y1
    12 (4)add ecx,4 | (3)cmovs edx,eax | (4)ld y4,[esi+ecx]
    13 | (4)xor edx,eax | (3)sub y3,edx
    14 | (4)jnz @decrease_free_row | (4)or edx,x4 (3)st [esi+ecx],y3
    15 | (4)cmovns edx,eax |
    16 | | (4)sub y4,edx
    17 | | (4)st [esi+ecx],y4

    A következő lefutási képe van 4 cikluslefutásnak Bulldozer-en (itt már egységes ütemező van a 4 végrehajtóra):
    decode:
    00 (1)mov edx,[edi+ecx*04h+__COLROWMARK] (1)xor edx,eax (1)or edx,[esi+ecx] (1)mov edx,00000000h
    01 (1)cmovns edx,eax (1)sub [esi+ecx],edx (1)add ecx,04h (1)jnz @decrease_row_free
    02 (2)mov edx,[edi+ecx*04h+__COLROWMARK] (2)xor edx,eax (2)or edx,[esi+ecx] (2)mov edx,00000000h
    03 (2)cmovns edx,eax (2)sub [esi+ecx],edx (2)add ecx,04h (2)jnz @decrease_row_free
    04 (3)mov edx,[edi+ecx*04h+__COLROWMARK] (3)xor edx,eax (3)or edx,[esi+ecx] (3)mov edx,00000000h
    05 (3)cmovns edx,eax (3)sub [esi+ecx],edx (3)add ecx,04h (3)jnz @decrease_row_free
    06 (4)mov edx,[edi+ecx*04h+__COLROWMARK] (4)xor edx,eax (4)or edx,[esi+ecx] (4)mov edx,00000000h
    07 (4)cmovns edx,eax (4)sub [esi+ecx],edx (4)add ecx,04h (4)jnz @decrease_row_free

    exec:
    clk ALU0 | ALU1 | AG0 | AG1
    | | |
    01 (1)mov edx,0 | | (1)mov edx,[esi+ecx*4] | (1)ld x1,[esi+ecx]
    02 (1)add ecx,4 | | (1)ld y1,[esi+ecx] |
    03 (2)mov edx,0 | (1)jnz @decrease_free_row | (2)mov edx,[esi+ecx*4] | (2)ld x2,[esi+ecx]
    04 (2)add ecx,4 | | (2)ld y2,[esi+ecx] |
    05 (1)xor edx,eax | (2)jnz @decrease_free_row | (3)mov edx,[esi+ecx*4] | (3)ld x3,[esi+ecx]
    06 (1)or edx,x1 | (3)mov edx,0 <<< +1 | (3)ld y3,[esi+ecx] |
    07 (1)cmovns edx,eax | (2)xor edx,eax | |
    08 (1)sub y1,edx | (2)or edx,x2 | |
    09 (2)cmovns edx,eax | (3)xor edx,eax | (1)st [esi+ecx],y1 |
    10 (2)sub y2,edx | (3)or edx,x3 | |
    11 (3)cmovns edx,eax | (3)add ecx,4 <<< +5 | (2)st [esi+ecx],y2 |
    12 (3)sub y3,edx | (3)jnz @decrease_free_row | (4)mov edx,[esi+ecx*4] | (4)ld x4,[esi+ecx]
    13 | | (3)st [esi+ecx],y3 |
    14 | | (4)ld y4,[esi+ecx] <<< +1 |
    15 | | |
    16 (4)xor edx,eax | | |
    17 (4)or edx,x4 | | |
    18 (4)cmovns edx,eax | | |
    19 (4)sub y4,edx | | |
    20 | | (4)st [esi+ecx],y3 |

    AGLU-val (ADD + logic képesség az AGU-knak) felszerelt esetben ez lenne a lefutási kép (a decode azonos):

    exec:
    clk ALU0 | ALU1 | AG0 | AG1
    | | |
    01 (1)mov edx,0 | | (1)mov edx,[esi+ecx*4] | (1)ld x1,[esi+ecx]
    02 (1)add ecx,4 | | (1)ld y1,[esi+ecx] |
    03 (2)mov edx,0 | (1)jnz @decrease_free_row | (2)mov edx,[esi+ecx*4] | (2)ld x2,[esi+ecx]
    04 (2)add ecx,4 | | (2)ld y2,[esi+ecx] |
    05 (1)xor edx,eax | (2)jnz @decrease_free_row | (3)mov edx,[esi+ecx*4] | (3)ld x3,[esi+ecx]
    06 (1)or edx,x1 | (3)mov edx,0 <<< +1 | (3)ld y3,[esi+ecx] | (3)add ecx,4
    07 (1)cmovns edx,eax | (2)xor edx,eax | (4)mov edx,[esi+ecx*4] | (4)ld x4,[esi+ecx]
    08 (1)sub y1,edx | (2)or edx,x2 | (4)ld y4,[esi+ecx] | (4)add ecx,4
    09 (2)cmovns edx,eax | (3)xor edx,eax | (1)st [esi+ecx],y1 |
    10 (2)sub y2,edx | (3)or edx,x3 | |
    11 (3)cmovns edx,eax | (3)jnz @decrease_free_row | (2)st [esi+ecx],y2 |
    12 (3)sub y3,edx | (4)jnz @decrease_free_row | (4)xor edx,eax |
    13 (4)or edx,x4 | | (3)st [esi+ecx],y3 |
    14 (4)cmovns edx,eax | | |
    15 (4)sub y4,edx | | |
    16 | | (4)st [esi+ecx],y4 |

    K10-en a 17. órajelben indul az utolsó utasítás, Bulldozeren a 20. órajelben, AGLU esetén pedig a 16. órajelben.

    A cikluslefutásoknak függetlenek egymástól, csakis az ADD ECX,00000004h utasítás lefutásán múlik, hogy mikor indulhatnak el a következő ciklusmag utasításai. Az ütemező erről mit sem tud, szabálya, hogy ha több utasításnak áll készen az összes bemeneti paramétere, akkor kötelező neki a programsorrendben korábbiakat indítani.
    Viszont mivel a Bulldozerben csak két végrehajtó képes az ADD műveletet fogadni, ezért a 3. cikluslefutás ADD ECX,4 művelete 5 órajellel később indul, mint mire ismert a bemenő paramétere, annyi végrehajtható utasítás gyűlik össze a két ALU számára; emiatt viszont a 13-15. órajelben egy buborék keletkezik az ALU-kban, nincs mit csinálniuk, meg kell várniuk az L1-ból az adatokat.
    Ha az AGU-k képesek lennének végrehajtani csak az összeadást, akkor 20 helyett 17 órajel alatt elindulhatna az összes utasítás; ha a logikai (XOR) műveletet is végre tudják hajtani, akkor 16 órajelre csökken ez az érték: ez egyenlő vagy gyorsabb, mint a K10 3 ALU + 3 AGU + 3 clock L1 load-to-use latency sebessége, 2 ALU + 2 AGLU + 4 clock L1 load-to-use latency felépítés mellett is.

  • P.H.

    senior tag

    K10: az integer-része egy klasszikus VLIW-felépítés, annak minden előnyével és hátrányával együtt: 3 ALU+3AGU párhuzamosan működve. Az utasítás elrendezés alapvető fontosságú, mégsem lehet kikerülni azt az alapvető tényt, hogy a 3. pipe-ra (és sokszor a másodikra is) kevesebb utasítás jut, mint az elsőre. Ezért nem volt multithread a Bulldozer előtt:
    - ahhoz, hogy a 3. pipe-ra megfelelő számú utasítást küldjünk, egy-egy ciklust is meg kell tűzdelni NOP-okkal: nem elég, ha $20-ra alignált utasítás van a ciklusban; ez ugyan nem okoz késleltetést, viszont megint az 1. pipe kapja a rajta levő utasítást
    - az utasításdekódolás nagyon érzékeny: ha egy ciklus csak 8 utasításból áll, akkor az azt követő 9. utasításnak is be kell férni a ciklus elejétől számított 32-aligned byte-ba; ha csak 7-ből, akkor a következő kettőnek kell beférni. 3-6-9 utasításból álló ciklus nem kell figyelni a következő utasításra

    Ezért növelte a K10-zel az AMD a K8 16-járól 32-re az órajelenként beolvasott L1I-byte-ok számát: ugyanez a legnagyobb gondja a Pentium M-nek is, a Core2-nél viszont a 64 byte-os Loop Stream Detector megszüntette ezt a problémát; a Bulldozer/Piledriver-be került egy - szálankénti - x16*16 byte-os Instruction Byte Buffer ugyanebből az okból kifolyólag.

    A Steamroller nagy előrelépés lesz a két megegyező dekóderével: a Bulldozer/Piledriver maximum 2 órajelenként tud 4 utasítást küldeni egy-egy magnak modulonként 2 szál végrehajtása esetén, azaz órajelenként legfejlebb 2-2-t. És amennyi bemegy, annál több nem is tud kijönni/végezni... (az IPC mindig a ténylegesen végrehajtott utasítások száma, nem azoké, amik bekerültek).
    Ami viszont még ennél is nagyobb jelentőségű: "Although AMD doesn’t like to call it a cache, Steamroller now features a decoded micro-op queue. As x86 instructions are decoded into micro-ops, the address and decoded op are both stored in this queue. Should a fetch come in for an address that appears in the queue, Steamroller’s front end will power down the decode hardware and simply service the fetch request out of the micro-op queue. This is similar in nature to Sandy Bridge’s decoded uop cache, however it is likely smaller. AMD wasn’t willing to disclose how many micro-ops could fit in the queue, other than to say that it’s big enough to get a decent hit rate. "
    A mérete nem ismert, aligha nagyobb sokkal, mint a Nehalem uop-okra átformázott LSD-je (az uop-ok igen nagyok és az AMD-é sokkal nagyobb, mint az Intelé, valószínűleg jóval 12 byte felett vannak: a micro- és macroop-fusion nélküli Northwood-é 54 bit volt, az x64-képes Prescotté volt 64 bit), viszont ez egy tényleges evolúvió első lépcsője: a végleges cél egy 1000 db körüli uop-cache lehet. Már csak 2 AGLU kell a 2 ALU helyett (Excavator talán), és minden rendben lesz.

    Addig is programozói álmodozás vége, a rideg valóság a K10.5. Újratervezett align -> 71K mátrix/ezredmásodperc:
    xor ebx,ebx
    mov esi,ebp
    mov eax,edi
    @mark0:
    {0} mov [edi+esi*04h+__0STARROW],ebx
    {1*} add esi,04h
    {2*} jnz @mark0
    mov ecx,ebp
    @@ARGUMENT:
    {0} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {2} mov [edi+ecx*04h+__COLROWMARK],esi
    {0} add edx,01h
    {1} mov [edi+ecx*04h+__0STAR],esi
    {0*} add ecx,04h
    {1*} jnz @@ARGUMENT
    lea ebx,[ebp-04h]
    @@REDUCE_ROWS:
    add ebx,04h
    jz @@REDUCE_COLUMNS
    sub eax,ebp
    cmp [edi+ebx*04h+__0STAR],ecx
    jnz @@REDUCE_ROWS
    mov ecx,ebp
    or esi,-1
    @findrowmin:
    {@29} mov edx,[eax+ebp]
    {1} or edx,[edi+ebp*04h+__0STARROW]
    {2} cmp esi,edx
    {0} cmova esi,edx
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {0*} cmp esi,ebp
    {1*} js @@ABNORMAL_EXIT
    {2} mov ebp,ecx
    {@40} @subrow:
    {0} sub [eax+ecx],esi
    {1*} add ecx,04h
    {2*} jnz @subrow
    jmp @@REDUCE_ROWS; nop; nop { 2x }
    @@REDUCE_COLUMNS:
    {0} sub ebx,04h
    {1} sub eax,04h
    {2*} cmp ebx,ebp
    {0*} jl @@1ST_STEP
    {1*} cmp [edi+ebx*04h+__0STARROW],ecx
    {2*} jnz @@REDUCE_COLUMNS
    or esi,-1
    {@60} @findcolmin:
    {0} mov edx,[eax]
    {1} or edx,[edi+ecx*04h-10h+__COLROWMARK]
    {2} sub ecx,04h
    {0} cmp esi,edx
    {1} cmova esi,edx
    {2} add eax,ebp
    {0*} cmp ecx,ebp
    {1*} jnz @findcolmin
    xor edx,edx
    sub ecx,04h
    test esi,esi
    js @@ABNORMAL_EXIT
    {@80} @subcol:
    {0*} add ecx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    cmp edx,[edi+ecx*04h+__0STAR]
    jnz @subcol
    mov [edi+ebx*04h+__0STARROW],ecx
    not edx
    mov [edi+ecx*04h+__0STAR],ebx
    jmp @subcol; nop; nop; nop; { 3x }
    @@ABNORMAL_EXIT:
    {@A0} mov esi,[esp+__MARKS]
    or edx,-1
    jmp dword ptr [esp+_INVALIDRESULT]

    @@3RD_STEP:
    {@AB} mov [edi+ebx*04h+__COLON],ecx
    {1} cmp esi,ecx
    {2} mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    {0} mov byte ptr [edi+esi*04h+__COLMARK],00h
    {1} cmovl ecx,esi
    {2} or esi,-1
    {@C0} nop
    {1} cmp dx,bx
    {2} cmovz ecx,ebp
    {0} cmovz eax,esi
    @@2ND_STEP:
    sub ecx,04h
    @chk2mtx:
    {0} mov esi,edi
    {1} mov ebx,ebp
    @check2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2} cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    {0} jnz @check2col
    {0} sub ecx,ebp
    {1} add esi,ecx
    {2} push ecx
    {@E2} @zeroincol:
    {0} movsx ecx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or ecx,[esi]
    {2} jz @zero
    {0} cmp ecx,eax
    {1} cmovb eax,ecx
    {2} cmovb edx,ebx
    {0} sub esi,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    @zero:
    {0} pop esi
    {1} lea ecx,[esi+ebp]
    {2} shl esi,10h
    {@00} test edx,edx
    {1} mov si,dx
    {2} cmovs edx,esi
    {0*} test ebx,ebx
    {1*} jz @chk2mtx
    {2} mov esi,[edi+ebx*04h+__0STAR]
    {0*} test esi,esi
    {1*} jnz @@3RD_STEP
    {2} jmp @@4TH_STEP
    @@5TH_STEP:
    push edx
    sub esi,ebp
    {@19} @nx5row:
    {0} movsx edx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} sub ecx,eax
    {0} xor edx,eax
    {1} cmovs eax,ecx
    {2} mov ecx,ebp
    {@26} @decrease_row_free:
    {0} mov edx,[edi+ecx*04h+__COLROWMARK]
    {1} xor edx,eax
    {2} or edx,[esi+ecx]
    {0} mov edx,00000000h
    {1} cmovns edx,eax
    {2} sub [esi+ecx],edx
    {0*} add ecx,04h
    {1*} jnz @decrease_row_free
    {0} sub esi,ebp
    {1*} add ebx,04h
    {2*} jnz @nx5row
    pop ecx
    movsx ebx,cx
    movsx edx,cx
    shr ecx,10h
    add ecx,ebp
    mov esi,[edi+ebx*04h+__0STAR]
    test esi,esi
    jnz @@3RD_STEP
    @@4TH_STEP:
    {@5D} mov [edi+ebx*04h+__0STAR],ecx
    {0} mov edx,ebx
    {1} mov ebx,[edi+ecx*04h+__0STARROW]
    {2} cmp ebx,esi
    {0} mov [edi+ecx*04h+__0STARROW],edx
    {1} mov ecx,[edi+ebx*04h+__COLON]
    {2} jnz @@4TH_STEP
    lea eax,[eax+7FFFFFFFh] { x6 }
    lea esi,[esi*08h+7FFFFFFFh] { x7 }
    {@80} mov ecx,7FFFFFFFh { x5 }
    @@1ST_STEP:
    {@85} mov eax,ebp
    {1} or edx,-1
    {2} mov ecx,ebp
    @restructure:
    {0} mov ebx,[edi+ebp*04h+__0STARROW]
    {1} and edx,ebx
    {2} movsx bx,byte ptr [edi+ebp*04h+__FIXEDROW]
    {0} mov [edi+ebp*04h+__COLROWMARK],ebx
    {1*} add ebp,04h
    {2*} jnz @restructure
    {@A0} mov ebp,eax
    cmp edx,00h
    jns @@2ND_STEP
    mov ebx,[esp+__SAVE]
    xor edx,edx
    mov esi,[esp+__MARKS]

    @results:
    {@B5} mov ecx,[edi+eax*04h+__0STAR]
    {1} sub ebx,ebp
    {2} add edx,[ebx+ecx]
    {0} sub ecx,ebp
    {@C0} shr ecx,02h
    {2} mov [esi],cl
    {0} add esi,01h
    {1*} add eax,04h
    {2*} jnz @results

  • P.H.

    senior tag

    válasz P.H. #77 üzenetére

    xor ebx,ebx
    mov esi,ebp
    mov eax,edi
    @mark0:
    {0} mov [edi+esi*04h+__0STARROW],ebx
    {1*} add esi,04h
    {2*} jnz @mark0
    mov ecx,ebp
    @@ARGUMENT:
    {0} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {0} mov [edi+ecx*04h+__COLROWMARK],esi
    {2} add edx,01h
    {1} mov [edi+ecx*04h+__0STAR],esi
    {0*} add ecx,04h
    {1*} jnz @@ARGUMENT
    lea ebx,[ebp-04h]
    @@REDUCE_ROWS:
    add ebx,04h
    jz @@REDUCE_COLUMNS
    sub eax,ebp
    cmp [edi+ebx*04h+__0STAR],ecx
    jnz @@REDUCE_ROWS
    mov ecx,ebp
    or esi,-1
    @findrowmin:
    {0} mov edx,[eax+ebp]
    {1} or edx,[edi+ebp*04h+__0STARROW]
    {2} cmp esi,edx
    {0} cmova esi,edx
    {1*} add ebp,04h
    {2*} jnz @findrowmin
    {0*} cmp esi,ebp
    {1*} js @@ABNORMAL_EXIT
    {2} mov ebp,ecx
    @subrow:
    {0} sub [eax+ecx],esi
    {1*} add ecx,04h
    {2*} jnz @subrow
    jmp @@REDUCE_ROWS;
    @@REDUCE_COLUMNS:
    {0} sub ebx,04h
    {1} sub eax,04h
    {2*} cmp ebx,ebp
    {0*} jl @@1ST_STEP
    {1*} cmp [edi+ebx*04h+__0STARROW],ecx
    {2*} jnz @@REDUCE_COLUMNS
    or esi,-1
    @findcolmin:
    {0} mov edx,[eax]
    {1} or edx,[edi+ecx*04h-10h+__COLROWMARK]
    {2} sub ecx,04h
    {0} cmp esi,edx
    {1} cmova esi,edx
    {2} add eax,ebp
    {0*} cmp ecx,ebp
    {1*} jnz @findcolmin
    xor edx,edx
    sub ecx,04h
    test esi,esi
    js @@ABNORMAL_EXIT
    @subcol:
    {0*} add ecx,04h
    {1*} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    cmp edx,[edi+ecx*04h+__0STAR]
    jnz @subcol
    mov [edi+ebx*04h+__0STARROW],ecx
    not edx
    mov [edi+ecx*04h+__0STAR],ebx
    jmp @subcol
    @@ABNORMAL_EXIT:
    mov esi,[esp+__MARKS]
    or edx,-1
    jmp dword ptr [esp+_INVALIDRESULT]

    @@3RD_STEP:
    mov [edi+ebx*04h+__COLON],ecx
    cmp esi,ecx
    mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    mov byte ptr [edi+esi*04h+__COLMARK],00h
    cmovl ecx,esi
    or esi,-1
    cmp dx,bx
    cmovz ecx,ebp
    cmovz eax,esi
    @@2ND_STEP:
    sub ecx,04h
    @chk2mtx:
    mov esi,edi
    mov ebx,ebp
    @check2col:
    {0*} add ecx,04h
    {1*} jz @@5TH_STEP
    {2} cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    {0} jnz @check2col
    sub ecx,ebp
    add esi,ecx
    push ecx
    @zeroincol:
    {0} movsx ecx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or ecx,[esi]
    {2} jz @zero
    {0} cmp ecx,eax
    {1} cmovb eax,ecx
    {2} cmovb edx,ebx
    {0} sub esi,ebp
    {1*} add ebx,04h
    {2*} jnz @zeroincol
    @zero:
    {0} pop esi
    {1} lea ecx,[esi+ebp]
    {2} shl esi,10h
    {0} cmp edx,00h
    {1} mov si,dx
    {2} cmovs edx,esi
    {0*} cmp ebx,00h
    {1*} jz @chk2mtx
    {2} mov esi,[edi+ebx*04h+__0STAR]
    {0*} cmp esi,00h
    {1*} jnz @@3RD_STEP
    {2} jmp @@4TH_STEP
    @@5TH_STEP:
    push edx
    @nx5row:
    {0} mov edx,[edi+ebx*04h+__COLROWMARK]
    {1} sub ecx,eax
    {2} sub esi,ebp
    {0} xor edx,eax
    {1} cmovs eax,ecx
    {2} mov ecx,ebp
    @decrease_row_free:
    {0} movsx edx,byte ptr [edi+ecx*04h+__COLMARK]
    {1} xor edx,eax
    {0} or edx,[esi+ecx]
    {1} mov edx,00000000h
    {2} cmovns edx,eax
    {0} sub [esi+ecx],edx
    {1*} add ecx,04h
    {2*} jnz @decrease_row_free
    add ebx,04h
    jnz @nx5row
    pop ecx
    movsx ebx,cx
    movsx edx,cx
    shr ecx,10h
    add ecx,ebp
    mov esi,[edi+ebx*04h+__0STAR]
    test esi,esi
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov [edi+ebx*04h+__0STAR],ecx
    mov edx,ebx
    mov ebx,[edi+ecx*04h+__0STARROW]
    cmp ebx,esi
    mov [edi+ecx*04h+__0STARROW],edx
    mov ecx,[edi+ebx*04h+__COLON]
    jnz @@4TH_STEP
    @@1ST_STEP:
    {0} mov eax,ebp
    {1} mov dl,0FFh {cdq ?}
    {2} mov ecx,ebp
    @restructure:
    {0} movsx ebx,byte ptr [edi+ebp*04h+__FIXEDROW]
    {1} mov bx,[edi+ebp*04h+__0STARROW+02h]
    {2} and dl,bl
    {0} mov [edi+ebp*04h+__COLROWMARK],ebx
    {1*} add ebp,04h
    {2*} jnz @restructure
    mov ebp,eax
    cmp dl,00h
    jz @@2ND_STEP

    mov ebx,[esp+__SAVE]
    xor edx,edx
    mov esi,[esp+__MARKS]
    @results:
    mov ecx,[edi+eax*04h+__0STAR]
    sub ebx,ebp
    add edx,[ebx+ecx]
    sub ecx,ebp
    shr ecx,02h
    mov [esi],cl
    add esi,01h
    add eax,04h
    jnz @results

    Kis átszervezés:
    - a paraméterként megkapott EDI pozitív oldalán a mátrix van, negatív oldalán a(z N x N méretű bemeneti mátrix esetén N x 16 byte méretű) munkaterület.
    - a szintén paraméterként EDX-ben megkapott leírás bárhol lehet

    Elsősorban a 4 utasítás/órajel dekódolóképességű CPU-kat vettem figyelembe (Core2 és újabb Intel CPU-k, Bulldozer), de adott órajelen a Sandy/Ivy Brigde-en a leggyorsabb, a K10-es Opteron a 2. a sorban, Core2-őn kb. 15-12% a lemaradás.

    60x60-as mátrixon tesztelve jellemzően 2.4 IPC:
    - az egyszálas algoritmus lefutása K10-en
    - a többszálas algoritmus - egy magra kényszerítve - lefutása K10-en

    A Core2-k ciklusfelismerése nagyon rendben van: "A branch instruction is recognized as having loop behavior if it goes one way n-1 times and then goes the other way one time. A loop counter makes it possible to predict branches with loop behavior perfectly if the period nis no longer than 64." Mivel maximum 60 x 60-as mátrixokról van szó, a branch prediction success rate Core2-n 99.5%; K10 esetében 98.5% körül mozog, sajnos Sandy Bridge-nél is: "There appears to be a two-level predictor with a 32-bit global history buffer and a history pattern table of unknown size. There is no specialized loop predictor."

    Az Intel-eket többé-kevésbé visszahúzza a CMOV és a load-op-store utasítások 'lassú' kezelése: ez elsősorban ezen utasítások lassú dekódolása miatt van (Core2), de a Sandy Bridge esetében igen nagy az előrelépés ezen a téren. (Arra viszont jó lenne fényt deríteni, hogy a Sandy Bridge uop-cache-e hány uop-ot tud a végrehajtó egységekhez juttatni órajelenként: úgy tűnik, a 4 nem igaz, 5 vagy 6 a valóság, észben tartva, hogy a raw dekóder 4+1+1+1 = 7-et tud szolgáltatni).
    In Haswell we trust...

    A futásai idő mostmár 60%-a a @decrease_row_free ciklusban, és immár csak 25%-a a @zeroincol ciklusban megy el; a maradék a többi kód és az (itt nem leírt) adminisztráció.

    A fent leírt jelölés + mátrix memóriaelrendezést alkalmazva egy 60x60-as mátrix 15KB összefüggő memóriaterületet igényel, ez megfelel minden modern CPU-nak.

    Core2 óta minden Intel CPU-ban van LSD/loop-puffer az utasításoknak; K10 esetében nincs. Viszont ez sem helytálló teljesen: "The minimum execution time per iteration for a loop is approximately equal to the number of 32-byte boundaries on K10, or 16-byte boundaries on K8, in the code plus 2 times the number of taken branches and jumps."
    K10-en ha egy rövid ciklus 3-többszöröse (3-6-9) utasításból áll, akkor nincs helye játéknak, bele kell férnie egy 32 byte-os területbe. Viszont úgy veszem észre, hogy ha kevesebb (4, 5, 7, 8) utasításból áll a ciklus, akkor a $10-re alignált utasítások nem okoznak késleltetést, viszont új hármast kezdenek; ezzel a statikus 3-as utasításleosztást lehet befolyásolni (lásd @decrease_row_free ciklust: egyetlen 32 byte-os egységbe rendezve lassabb a 8 utasítás lefolyása, mintha az első utasítás $3A-ra - azaz a 3. utasítás $40-re, ezzel indul a következő triplet - van rendezve, így a 3 integer-pipe más utasításokat kap meg, amelyek nem akadályozzák egymást).
    Az utasítások/ciklusok rendezésének (alignálásának) hiánya vagy figyelmen kívül hagyása 15-20% visszaesést jelent a K10-es teljesítményben.

  • P.H.

    senior tag

    válasz P.H. #39 üzenetére

    Line algoritmus nagy mennyiségű vonalhoz, új megfogalmazásban:

    bemenő paraméterek:
    EAX: X0 coordinate
    EDX: Y0 coordinate
    ECX: X1 coordinate
    EBP: Y1 coordinate
    ESI: BITS array
    EDI: _ADDER array
    MM7: [$0000][$0000][width][ 1] // image width + 1 (UINTs)
    XMM5 [ CHS][ CHS][ CHS][ CHS] // sign change constants
    XMM6: [bttom][right][ top][ left] // image boundaries
    XMM7: [-----][-----][-----][ 1.0]

    cvtsi2ss xmm2,eax
    sub ecx,eax
    sub ebp,edx
    push ebx
    mov eax,ecx
    mov ebx,ecx
    sar eax,1Fh
    cvtsi2ss xmm3,edx
    xor ebx,eax
    mov edx,ebp
    sub ebx,eax
    mov eax,ebp
    sar eax,1Fh
    xor edx,eax
    sub edx,eax
    cmp edx,ebx
    jae @movement
    xchg ebp,ecx
    @movement:
    cvtsi2ss xmm1,ebp
    shufps xmm2,xmm3,01000100b
    test ebp,ebp
    jz @return
    cvtsi2ss xmm0,ecx
    rcpss xmm1,xmm1
    shufps xmm2,xmm2,10001000b
    mulss xmm0,xmm1
    shufps xmm0,xmm7,00000000b
    jns @direction
    neg ebp
    xorps xmm0,xmm5
    @direction:
    cmp edx,ebx
    mov ebx,[edi+_PENWIDTH]
    jae @inlineCOORDINATES
    shufps xmm0,xmm0,11000110b
    @inlineCOORDINATES:
    mov al,[edi+_DRAWCOLOR]
    sub edi,ebx
    shufps xmm0,xmm0,10001000b
    @setpixel:
    cvtps2pi mm0,xmm2
    movaps xmm4,xmm6
    cmpltps xmm6,xmm2
    pshufw mm0,mm0,11111000b
    addps xmm2,xmm0
    movmskps edx,xmm6
    movaps xmm6,xmm4
    pmaddwd mm0,mm7
    cmp edx,03h
    jnz @continueLINE
    movd edx,mm0
    mov ecx,ebx
    @rounds:
    add edx,[edi+ecx]
    add ecx,04h
    mov [esi+edx],al
    js @rounds
    @continueLINE:
    sub ebp,01h
    jge @setpixel
    add edi,ebx
    @return:
    pop ebx

  • P.H.

    senior tag

    Egy, az algoritmus által adott lehetőséget kihasználva (a szabad 0 keresését - @@2ND_STEP - nem kell mindíg a mátrixban elölről kezdeni) az egyszálas 25x25-ös mátrixszámítás tempóját sikerült 69,5 mátrix/ezredmásodpercre feltornászni.

    PerfMonitor egyszálas elemzés az új kódra alapuló teljes lefutásról a maximális 60x60-as mátrixméretre: K10-en sikerült ráérezni a hardware prefetcher-ekre, szinte a teljes lefutás (a tesztadaton 1,5 perc) tisztán L1I-ből és L1D-ből fut (cache success rate 100%).

    xor ecx,ecx
    lea ebx,[ecx+ebp*04h]
    @mark0:
    {0} mov [edi+ebx+__0STARROW],ecx
    {1} add ebx,10h
    {2} jnz @mark0
    mov ecx,ebp
    @@ARGUMENT:
    {0} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {2} add edx,01h
    {0} mov [edi+ecx*04h+__COLROWMARK],esi
    {1} mov [edi+ecx*04h+__0STAR],esi
    {2} add ecx,04h
    {0} jnz @@ARGUMENT
    lea ebx,[ebp-04h]
    @@REDUCE_ROWS:
    add ebx,04h
    jz @@REDUCE_COLUMNS
    sub eax,ebp
    cmp [edi+ebx*04h+__0STAR],ecx
    jnz @@REDUCE_ROWS
    mov ecx,ebp
    or esi,-1
    @findrowmin:
    {0} mov edx,[eax+ecx]
    {1} or edx,[edi+ecx*04h+__0STARROW]
    {2} cmp esi,edx
    {0} cmova esi,edx
    {1} add ecx,04h
    {2} jnz @findrowmin
    {0} cmp esi,ecx
    {1} js @@ABNORMAL_EXIT
    {2} mov ecx,ebp
    @subrow:
    {0} sub [eax+ecx],esi
    {1} add ecx,04h
    {2} jnz @subrow
    jmp @@REDUCE_ROWS
    @@REDUCE_COLUMNS:
    {0} sub ebx,04h
    {1} sub eax,04h
    {2} cmp ebx,ebp
    {0} jl @@1ST_STEP
    {1} cmp [edi+ebx*04h+__0STARROW],ecx
    {2} jnz @@REDUCE_COLUMNS
    or esi,-1
    @findcolmin:
    {0} sub ecx,04h
    {1} mov edx,[eax]
    {2} or edx,[edi+ecx*04h+__COLROWMARK]
    {0} cmp esi,edx
    {1} cmova esi,edx
    {2} add eax,ebp
    {0} cmp ecx,ebp
    {1} jnz @findcolmin
    xor edx,edx
    sub ecx,04h
    test esi,esi
    js @@ABNORMAL_EXIT
    @subcol:
    {0} add ecx,04h
    {1} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    cmp edx,[edi+ecx*04h+__0STAR]
    jnz @subcol
    mov [edi+ebx*04h+__0STARROW],ecx
    not edx
    mov [edi+ecx*04h+__0STAR],ebx
    jmp @subcol
    @@ABNORMAL_EXIT:
    mov esi,[esp+__MARKS]
    or edx,-1
    jmp dword ptr [esp+_INVALIDRESULT]

    @@3RD_STEP:
    {0} mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    {1} mov [edi+ebx*04h+__COLON],ecx
    {2} mov byte ptr [edi+esi*04h+__COLMARK],00h
    @@2ND_STEP:
    {0} xor esi,esi
    {1} mov ecx,ebp
    {2} or edx,-1
    {0} xor eax,eax
    @restart:
    {0} cmp esi,ecx
    {1} cmovl ecx,esi
    {2} sub ecx,04h
    @chk2mtx:
    {0} mov esi,[esp+__MTX]
    {1} mov ebx,ebp
    @check2col:
    {0} add ecx,04h
    {1} jz @@5TH_STEP
    {2} cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    {0} jnz @check2col
    {0} sub ecx,ebp
    {1} push ecx
    {2} add esi,ecx
    @zeroincol:
    {0} movsx ecx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or ecx,[esi]
    {2} jz @zero
    {0} cmp ecx,edx
    {1} cmovb edx,ecx
    {2} cmovb eax,ebx
    {0} sub esi,ebp
    {1} add ebx,04h
    {2} jnz @zeroincol
    @zero:
    {0} pop esi
    {1} lea ecx,[esi+ebp]
    {2} shl esi,10h
    {0} test eax,eax
    {1} mov si,ax
    {2} cmovs eax,esi
    {0} test ebx,ebx
    {1} jz @chk2mtx
    {2} mov esi,[edi+ebx*04h+__0STAR]
    {0} test esi,esi
    {1} jz @@4TH_STEP
    {2} mov byte ptr [edi+ebx*04h+__ROWMARK],0FFh
    {0} mov [edi+ebx*04h+__COLON],ecx
    {1} mov byte ptr [edi+esi*04h+__COLMARK],00h
    {2} cmp ax,bx
    {0} jnz @restart
    {0} jmp @@2ND_STEP
    @@5TH_STEP:
    push eax
    @nx5row:
    {0} mov eax,[edi+ebx*04h+__COLROWMARK]
    {1} sub ecx,edx
    {2} sub esi,ebp
    {0} xor eax,edx
    {1} cmovs edx,ecx
    {2} mov ecx,ebp
    @decrease_row_free:
    {0} movsx eax,byte ptr [edi+ecx*04h+__COLMARK]
    {1} xor eax,edx
    {2} or eax,[esi+ecx]
    {0} mov eax,00000000h
    {1} cmovns eax,edx
    {2} sub [esi+ecx],eax
    {0} add ecx,04h
    {1} jnz @decrease_row_free
    {0} add ebx,04h
    {1} jnz @nx5row
    pop ecx
    xor esi,esi
    movsx ebx,cx
    shr ecx,10h
    add ecx,ebp
    add esi,[edi+ebx*04h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    {0} mov [edi+ebx*04h+__0STAR],ecx
    {1} mov edx,ebx
    {2} mov ebx,[edi+ecx*04h+__0STARROW]
    {0} test ebx,ebx
    {1} mov [edi+ecx*04h+__0STARROW],edx
    {2} mov ecx,[edi+ebx*04h+__COLON]
    {0} jnz @@4TH_STEP
    @@1ST_STEP:
    {1} mov eax,ebp
    {2} mov edx,[esp+__SYS0]
    @restructure:
    {0} movsx ebx,byte ptr [edi+ebp*04h+__FIXEDROW]
    {1} movzx ecx,byte ptr [edi+ebp*04h+__0STARROW+03h]
    {2} shl ebx,10h
    {0} add dl,cl
    {1} add ecx,ebx
    {2} mov [edi+ebp*04h+__COLROWMARK],ecx
    {0} add ebp,04h
    {1} jnz @restructure
    mov ebp,eax
    test edx,edx
    jnz @@2ND_STEP

    mov ebx,[esp+__SAVE]
    mov esi,[esp+__MARKS]
    @results:
    {0} mov ecx,[edi+eax*04h+__0STAR]
    {1} sub ecx,ebp
    {2} add edx,[ebx+ecx]
    {0} shr ecx,02h
    {1} sub ebx,ebp
    {2} mov [esi],cl
    {0} add esi,01h
    {1} add eax,04h
    {2} jnz @results

  • P.H.

    senior tag

    válasz P.H. #72 üzenetére

    Minor optimalizáció kifejezetten a többszálú alkalmazáshoz, nagy (50x50 méretnél nagyobb) mátrixokhoz: a bemenő memóriaparaméter-terület lehet különálló és a két kulcsciklusban némi +ILP érhető el.
    0-2% gyorsulás többszálas esetben; lassulás egyetlen szálnál vagy kis mátrix esetén sincs.

    xor ecx,ecx
    lea ebx,[ecx+ebp*04h]
    @mark0:
    {0} mov [edi+ebx+__0STARROW],ecx
    {1} add ebx,10h
    {2} jnz @mark0
    mov ecx,ebp
    @@ARGUMENT:
    {0} movsx esi,byte ptr [edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {2} add edx,01h
    {0} mov [edi+ecx*04h+__COLROWMARK],esi
    {1} mov [edi+ecx*04h+__0STAR],esi
    {2} add ecx,04h
    {0} jnz @@ARGUMENT
    lea ebx,[ebp-04h]
    @@REDUCE_ROWS:
    add ebx,04h
    jz @@REDUCE_COLUMNS
    sub eax,ebp
    cmp [edi+ebx*04h+__0STAR],ecx
    jnz @@REDUCE_ROWS
    mov ecx,ebp
    or esi,-1
    @findrowmin:
    {0} mov edx,[eax+ecx]
    {1} or edx,[edi+ecx*04h+__0STARROW]
    {2} cmp esi,edx
    {0} cmova esi,edx
    {1} add ecx,04h
    {2} jnz @findrowmin
    {0} cmp esi,ecx
    {1} js @@ABNORMAL_EXIT
    {2} mov ecx,ebp
    @subrow:
    {0} sub [eax+ecx],esi
    {1} add ecx,04h
    {2} jnz @subrow
    jmp @@REDUCE_ROWS
    @@REDUCE_COLUMNS:
    {0} sub ebx,04h
    {1} sub eax,04h
    {2} cmp ebx,ebp
    {0} jl @@1ST_STEP
    {1} cmp [edi+ebx*04h+__0STARROW],ecx
    {2} jnz @@REDUCE_COLUMNS
    or esi,-1
    @findcolmin:
    {0} sub ecx,04h
    {1} mov edx,[eax]
    {2} or edx,[edi+ecx*04h+__COLROWMARK]
    {0} cmp esi,edx
    {1} cmova esi,edx
    {2} add eax,ebp
    {0} cmp ecx,ebp
    {1} jnz @findcolmin
    xor edx,edx
    sub ecx,04h
    test esi,esi
    js @@ABNORMAL_EXIT
    @subcol:
    {0} add ecx,04h
    {1} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    cmp edx,[edi+ecx*04h+__0STAR]
    jnz @subcol
    mov [edi+ebx*04h+__0STARROW],ecx
    not edx
    mov [edi+ecx*04h+__0STAR],ebx
    jmp @subcol
    @@ABNORMAL_EXIT:
    mov esi,[esp+__MARKS]
    or edx,-1
    jmp dword ptr [esp+_INVALIDRESULT]

    @@3RD_STEP:
    {0} mov byte ptr [edi+eax*04h+__ROWMARK],0FFh
    {1} mov [edi+eax*04h+__COLON],ecx
    {2} mov byte ptr [edi+ebx*04h+__COLMARK],00h
    @@2ND_STEP:
    {0} lea ecx,[ebp-04h]
    {1} mov edx,00FFFFFFh
    @chk2mtx:
    {0} mov ebx,eax
    {1} sub eax,ebp
    {2} mov esi,[esp+__MTX]
    {0} shl eax,10h
    {1} mov ax,cx
    {2} test ebx,ebx
    {0} cmovns eax,ebx
    {1} mov ebx,ebp
    @check2col:
    {0} add ecx,04h
    {1} jz @@5TH_STEP
    {2} cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    {0} jnz @check2col
    {0} push ecx
    {1} add esi,ecx
    {2} neg ebp
    @zeroincol:
    {0} movsx ecx,byte ptr [edi+ebx*04h+__ROWMARK]
    {1} or ecx,[esi+ebp]
    {2} add esi,ebp
    {0} cmp ecx,edx
    {1} cmovb edx,ecx
    {2} cmovb eax,ebx
    {0} add ebx,04h
    {1} jnz @zeroincol
    {0} pop ecx
    {1} neg ebp
    {2} cmp edx,ebx
    {0} jnz @chk2mtx
    {0} add ebx,[edi+eax*04h+__0STAR]
    {1} jnz @@3RD_STEP
    {2} jmp @@4TH_STEP
    @@5TH_STEP:
    push eax
    @nx5row:
    {0} mov eax,[edi+ebx*04h+__COLROWMARK]
    {1} sub ecx,edx
    {2} sub esi,ebp
    {0} xor eax,edx
    {1} cmovs edx,ecx
    {2} mov ecx,ebp
    @decrease_row_free:
    {0} movsx eax,byte ptr [edi+ecx*04h+__COLMARK]
    {1} xor eax,edx
    {2} or eax,[esi+ecx]
    {0} mov eax,00000000h
    {1} cmovns eax,edx
    {2} sub [esi+ecx],eax
    {0} add ecx,04h
    {1} jnz @decrease_row_free
    {0} add ebx,04h
    {1} jnz @nx5row
    pop eax
    movsx ecx,ax
    shr eax,10h
    add eax,ebp
    add ebx,[edi+eax*04h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    {0} mov [edi+eax*04h+__0STAR],ecx
    {1} mov edx,eax
    {2} mov eax,[edi+ecx*04h+__0STARROW]
    {0} cmp eax,ebx
    {1} mov [edi+ecx*04h+__0STARROW],edx
    {2} mov ecx,[edi+eax*04h+__COLON]
    {0} jnz @@4TH_STEP
    @@1ST_STEP:
    {1} mov eax,ebp
    {2} mov edx,[esp+__SYS0]
    @restructure:
    {0} movsx ebx,byte ptr [edi+ebp*04h+__FIXEDROW]
    {1} movzx ecx,byte ptr [edi+ebp*04h+__0STARROW+03h]
    {2} shl ebx,10h
    {0} add dl,cl
    {1} add ecx,ebx
    {2} mov [edi+ebp*04h+__COLROWMARK],ecx
    {0} add ebp,04h
    {1} jnz @restructure
    mov ebp,eax
    test edx,edx
    jnz @@2ND_STEP

    mov ebx,[esp+__SAVE]
    mov esi,[esp+__MARKS]
    @results:
    {0} mov ecx,[edi+eax*04h+__0STAR]
    {1} sub ecx,ebp
    {2} add edx,[ebx+ecx]
    {0} shr ecx,02h
    {1} sub ebx,ebp
    {2} mov [esi],cl
    {0} add esi,01h
    {1} add eax,04h
    {2} jnz @results

  • P.H.

    senior tag

    válasz P.H. #74 üzenetére

    Tipikus CPU-terhelés:

    (4 másodperces frissítésű Task Manager XP x64-en, 2 db 4 magos Opteron, 32+1 szál, 50x50-es mátrixok)

    Több dolog is leolvasható róla:
    - szerver magos Windows (jelen esetben Windows Server 2003 kernelű XP x64) nem dobálja a szálakat
    - szerver magos Windows esetén a legtöbbet 'használt' szálak egy foglalaton maradnak (NUMA) ("Az alap algoritmus sajátossága, hogy NxN méretű kiindulási mátrixra lépésenként legalább 2, legfejlebb N/2 új mátrixot generál és számoltat, törekedve arra, hogy minél kisebb legyen ez a szám")
    - a fő szál, ami osztja a kiszámolandó mátrixokat a többi szálnak, a 2. magon fut (nem számol mátrixot, viszont nagy a kernel-terhelése), a mindig meglevő 2 mátrixot az 3. és 4. mag, a 3. mátrixot az 1. mag számolja. 4 vagy több kiszámolandó mátrix ritkábban keletkezik, azok kerülnek át a másik CPU-ra.

  • P.H.

    senior tag

    A multithread-kód egy szálának 3. verziója, teljesen igazítva: az előző v1 verzió 8 magnyi Opteronon 125 db 25x25 mátrixot oldott meg ezredmásodpercenként, ez a v3 (több feladatot átvéve többszálra a koordináló száltól) 161 mátrix/millisec sebességgel fut.
    (A mátrixok megoldásáért felelős kód 99.5%-ban ugyanaz; több kiskapu is nyitva maradt benne, ami lehetővé tette az átkonfigurálását méretnövekedés nélkül, csupán 1-1 utasítás megváltoztatásával/hozzáadásával)

    ...
    jmp @@THREADLOOP
    @VALIDresult:
    {at $38}or ebp,ebx
    mov ebx,[esi+TRESULT.DEST]
    movzx eax,ch
    {at $40}mov [esi+TRESULT.CCIRCLE],ebp
    mov [ebx+TCIRCLE.CIRCLESIZE],cl
    xor ebp,ebp
    mov byte ptr [ebx+TCIRCLE.SHORTEST+00h],al
    mov [ebx+TCIRCLE.NEXT],ebp
    @createSHORTEST:
    {at $4D}movzx eax,byte ptr [esi+TRESULT.ORDERSET+eax]
    add ebp,01h
    mov byte ptr [ebx+TCIRCLE.SHORTEST+ebp],al
    sub cl,01h
    jnz @createSHORTEST
    mov [ebx+TCIRCLE.RESULT],edx
    add dword ptr [ebx+TCIRCLE.QUANTITY],02h
    @INVALIDresult:
    mov [esi+TRESULT.OPTIMUM],edx
    mov ebp,[esp+_MTXSIZE]
    push dword ptr [esi+TRESULT.READY]; call WINDOWS.SETEVENT
    @@THREADLOOP:
    mov edi,[esi+TRESULT.IVALUE]
    push INFINITE; push dword ptr [esi+TRESULT.STARTER]; call WINDOWS.WAITFORSINGLEOBJECT
    {at $80}mov ebx,[esi+TRESULT.SOURCE]
    and ebp,-4
    mov edx,[esi+TRESULT.DEST]
    cmp [esi+TRESULT.TERMINATOR],al
    jnz @return
    mov esi,[esp+_SIZE2BYTE]
    @createARGUMENT:
    {at $92}mov eax,dword ptr [ebx+TCIRCLE.SUGGESTED+ebp]
    mov dword ptr [edx+TCIRCLE.SUGGESTED+ebp],eax
    sub ebp,04h
    jns @createARGUMENT
    movzx eax,word ptr [ebx+TCIRCLE.SHORTEST+edi+00h]
    add edx,offset(TCIRCLE.SUGGESTED)
    mov ecx,eax
    @extendARGUMENT:
    {at $A9}movzx ebp,byte ptr [ebx+TCIRCLE.SHORTEST+edi-01h]
    sub edi,01h
    js @matrix
    mov byte ptr [edx+ebp],al
    mov eax,ebp
    jmp @extendARGUMENT
    @matrix:
    {at $BA}mov ebp,[esp+_SAVEMTX]
    mov eax,[esp+_CMTX]
    @copyMTX:
    {at $C1}mov edi,[esi+ebp+04h]
    mov [eax+esi+04h],edi
    mov edi,[esi+ebp]
    mov [eax+esi],edi
    sub esi,08h
    jns @copyMTX
    {at $D4}mov ebp,[esp+_MTXSIZE]
    movzx esi,cl
    shr ecx,08h
    imul esi,ebp
    mov edi,[ebx+TCIRCLE.QUANTITY]
    shl ebp,02h
    add esi,ecx
    mov [edx-TCIRCLE.SUGGESTED+TCIRCLE.QUANTITY],edi
    @tilt:
    {at $EC}mov word ptr [edx-TCIRCLE.SUGGESTED+TCIRCLE.TILTEDS+edi],si
    mov byte ptr [eax+esi*04h+03h],__INVALID
    movzx esi,word ptr [ebx+TCIRCLE.TILTEDS+edi-02h]
    sub edi,02h
    jns @tilt
    {at $00}lea edi,[esp+_THREADMARKS+ebp*04h+20h]
    neg ebp
    jmp _OPTCOUNTPPRO
    @return:
    {at $12}lea eax,[esi+TRESULT.CMTX]; xor edx,edx; call _REALLOCARRAY
    add esp,_STACK+_SAVE
    popad
    ret 04h

  • P.H.

    senior tag

    válasz P.H. #72 üzenetére

    A hozzá készített multithread-hívó kód egy szálának részlete, ahogy én látom/írom:

    Az alap algoritmus sajátossága, hogy NxN méretű kiindulási mátrixra lépésenként legalább 2, legfejlebb N/2 új mátrixot generál és számoltat, törekedve arra, hogy minél kisebb legyen ez a szám; így többszálúsítással legalább 2x-esre gyorsul az algoritmus, a 2 magos CPU-kat teljesen kihasználja. (Efelett azonban nem skálázódik a magszámmal: bár 60x60-as mátrix esetén már 30 szálról van szó, 8 magos gépen kb. 40-60%-os tipikus terhelést produkál.)
    Ebből a természetéből kifolyólag célravezetőbb minél kisebb terhelésre optimalizálni a teljes algoritmust, így ha bármi más program is fut mellette, akkor is hozza a legjobb eredményeket.

    A többszálú kód tesztelését ezért először egymagos Prescott Celeron D-n csináltam, hogy kiderüljön, a szinkronizációs overhead mellett mennyit jelent az, hogy minden egyes szál saját munkaterületen (2 Kb) és saját munkamátrixon (NxNx4 byte, 25x25-ös mátrix esetén legrosszabb esetben 12x2.5 Kb) dolgozik, míg az egyszálas a cache-elés miatt célszerűen ugyanarra az egyetlen (2+2.5 KB-os) területre:
    - az eredeti egyszálas algoritmus 18,5 mátrix/ezredmásodperc sebességgel dolgozik
    - a többszálas verzió 16,5 mátrix/millisec-et teljesít

  • P.H.

    senior tag

    'Kész' sosem lesz, de ez egy erős lokális minimum. Megfelelő padolással 25x25 mátrixméretre:
    - K10 Opteron 2650 MHz 65 mátrix/ezredmásodperc, X2 2900 MHz-en 72 mátrix/millisec
    - Core2 igényeit (4-1-1-1 fused) figyelembe véve az utasítássorrend kialakításánál E3300 2500 MHz-en 58,5 mátrix/ezredmásodperc (a korábbi 44 mátrix/millisec helyett)
    - PentiumM és P3 (3-1-1) utasítássorrend is lehetőség szerint figyelembe lett véve
    - Bulldozer is valószínűleg szeretni fogja, a kulcsfontosságú ciklusok lehetőleg 8 utasításból állnak; ez ugyan lecsökkenti a lehetséges K10-es maximális IPC-t 2.6-ra viszont ezt jól közelíti 2.2-2.3 IPC-vel
    - Prescotton 18,5 mátrix/ezredmásodperc sebességgel megy, rá figyelve a minimálisra csökkentettem a szükséges memóriaírások számát de még nincs meg a bűvös 1.0 IPC.

    Most mehet a kód megint többszálúsításra.

    xor edx,edx
    mov ecx,ebp
    lea ebx,[edx+ebp*04h]
    @mark0:
    {0} mov [edi+ebx+__0STARROW],edx
    {1} add ebx,10h
    {2} jnz @mark0
    @@ARGUMENT:
    {0} movsx esi,byte ptr [edi+edx]
    {1} cmp esi,ebx
    {2} lea esi,[ebp+esi*04h]
    {0} mov [edi+esi*04h+__0STARROW],ecx
    {1} cmovs esi,ebx
    {2} add edx,01h
    {0} mov [edi+ecx*04h+__COLROWMARK],esi
    {1} mov [edi+ecx*04h+__0STAR],esi
    {2} add ecx,04h
    {0} jnz @@ARGUMENT
    lea ebx,[ebp-04h]
    @@REDUCE_ROWS:
    add ebx,04h
    jz @@REDUCE_COLUMNS
    sub eax,ebp
    cmp [edi+ebx*04h+__0STAR],ecx
    jnz @@REDUCE_ROWS
    mov ecx,ebp
    or esi,-1
    @findrowmin:
    {0} mov edx,[eax+ecx]
    {1} or edx,[edi+ecx*04h+__0STARROW]
    {2} cmp esi,edx
    {0} cmova esi,edx
    {1} add ecx,04h
    {2} jnz @findrowmin
    {0} cmp esi,ecx
    {1} js @@ABNORMAL_EXIT
    {2} mov ecx,ebp
    @subrow:
    {0} sub [eax+ecx],esi
    {1} add ecx,04h
    {2} jnz @subrow
    jmp @@REDUCE_ROWS
    @@REDUCE_COLUMNS:
    {0} sub ebx,04h
    {1} sub eax,04h
    {2} cmp ebx,ebp
    {0} jl @@1ST_STEP
    {1} cmp [edi+ebx*04h+__0STARROW],ecx
    {2} jnz @@REDUCE_COLUMNS
    or esi,-1
    @findcolmin:
    {0} sub ecx,04h
    {1} mov edx,[eax]
    {2} or edx,[edi+ecx*04h+__COLROWMARK]
    {0} cmp esi,edx
    {1} cmova esi,edx
    {2} add eax,ebp
    {0} cmp ecx,ebp
    {1} jnz @findcolmin
    xor edx,edx
    sub ecx,04h
    test esi,esi
    js @@ABNORMAL_EXIT
    @subcol:
    {0} add ecx,04h
    {1} jz @@REDUCE_COLUMNS
    {2} sub eax,ebp
    {0} sub [eax],esi
    {1} jnz @subcol
    cmp edx,[edi+ecx*04h+__0STAR]
    jnz @subcol
    mov [edi+ebx*04h+__0STARROW],ecx
    not edx
    mov [edi+ecx*04h+__0STAR],ebx
    jmp @subcol
    @@ABNORMAL_EXIT:
    mov esi,[esp+__MARKS]
    jmp dword ptr [esp+_INVALIDRESULT]

    @@3RD_STEP:
    {0} mov byte ptr [edi+eax*04h+__ROWMARK],0FFh
    {1} mov [edi+eax*04h+__COLON],ecx
    {2} mov byte ptr [edi+ebx*04h+__COLMARK],00h
    @@2ND_STEP:
    {0} lea ecx,[ebp-04h]
    {1} mov edx,00FFFFFFh
    @chk2mtx:
    {0} mov ebx,eax
    {1} sub eax,ebp
    {2} mov esi,[esp+__MTX]
    {0} shl eax,10h
    {1} mov ax,cx
    {2} test ebx,ebx
    {0} cmovns eax,ebx
    {1} mov ebx,ebp
    @check2col:
    {0} add ecx,04h
    {1} jz @@5TH_STEP
    {2} cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    {0} jnz @check2col
    {0} push ecx
    {1} add esi,ecx
    @zeroincol:
    {0} sub esi,ebp
    {1} movsx ecx,byte ptr [edi+ebx*04h+__ROWMARK]
    {2} or ecx,[esi]
    {0} cmp ecx,edx
    {1} cmovb edx,ecx
    {2} cmovb eax,ebx
    {0} add ebx,04h
    {1} jnz @zeroincol
    {0} pop ecx
    {1} cmp edx,ebx
    {2} jnz @chk2mtx
    {0} add ebx,[edi+eax*04h+__0STAR]
    {1} jnz @@3RD_STEP
    {2} jmp @@4TH_STEP
    @@5TH_STEP:
    push eax
    @nx5row:
    {0} mov eax,edx
    {1} sub ecx,edx
    {2} xor eax,[edi+ebx*04h+__COLROWMARK]
    {0} cmovs edx,ecx
    {1} mov ecx,ebp
    {2} sub esi,ebp
    @decrease_row_free:
    {0} movsx eax,byte ptr [edi+ecx*04h+__COLMARK]
    {1} xor eax,edx
    {2} or eax,[esi+ecx]
    {0} mov eax,00000000h
    {1} cmovns eax,edx
    {2} sub [esi+ecx],eax
    {0} add ecx,04h
    {1} jnz @decrease_row_free
    {0} add ebx,04h
    {1} jnz @nx5row
    pop eax
    movsx ecx,ax
    shr eax,10h
    add eax,ebp
    add ebx,[edi+eax*04h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    {0} mov [edi+eax*04h+__0STAR],ecx
    {1} mov edx,eax
    {2} mov eax,[edi+ecx*04h+__0STARROW]
    {0} cmp eax,ebx
    {1} mov [edi+ecx*04h+__0STARROW],edx
    {2} mov ecx,[edi+eax*04h+__COLON]
    {0} jnz @@4TH_STEP
    @@1ST_STEP:
    {1} mov eax,ebp
    {2} mov edx,[esp+__SYS0]
    @restructure:
    {0} movsx ebx,byte ptr [edi+ebp*04h+__FIXEDROW]
    {1} movzx ecx,byte ptr [edi+ebp*04h+__0STARROW+03h]
    {2} shl ebx,10h
    {0} add dl,cl
    {1} add ecx,ebx
    {2} mov [edi+ebp*04h+__COLROWMARK],ecx
    {0} add ebp,04h
    {1} jnz @restructure
    mov ebp,eax
    test edx,edx
    jnz @@2ND_STEP

    mov ebx,[esp+__SAVE]
    mov esi,[esp+__MARKS]
    @results:
    {0} mov ecx,[edi+eax*04h+__0STAR]
    {1} sub ecx,ebp
    {2} add edx,[ebx+ecx]
    {0} shr ecx,02h
    {1} sub ebx,ebp
    {2} mov [esi],cl
    {0} add esi,01h
    {1} add eax,04h
    {2} jnz @results

  • P.H.

    senior tag

    Még kisebb kód:

    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp-01h]
    nop
    lea edi,[ebx+ebp*04h]
    neg ebp
    @mark0:
    mov [ebx+edx*04h],ecx
    sub edx,01h
    jns @mark0
    @@REDUCE_ROWS:
    mov [edi+00h+__0STARROW],edx
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmova esi,[eax]
    cmovz edx,ecx
    add eax,04h
    add ecx,04h
    jnz @findrowmin
    cmp esi,02000000h
    jz @specific
    mov ecx,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+ecx+__MARKBYTE],00h
    cmovz edx,esi
    sub [eax+ecx],edx
    add ecx,04h
    jnz @subrow
    add ebx,04h
    jnz @rowmin
    jmp @@RECUDE_COLUMNS
    @specific:
    xor [edi+edx*04h+__0STARROW],ebx
    jns @@ABNORMAL_EXIT
    mov [edi+ebx*04h+__0STAR],edx
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@1ST_STEP
    cmp dword ptr [edi+ebx*04h+__0STARROW],00h
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    lea ecx,[ebp-04h]
    cmp esi,02000000h
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp dl,[eax+__MARKBYTE]
    cmovz edx,esi
    sub [eax],edx
    jnz @subcol
    mov edx,[edi+ecx*04h+__0STAR]
    add edx,[edi+ebx*04h+__0STARROW]
    jnz @subcol
    mov [edi+ebx*04h+__0STARROW],ecx
    mov [edi+ecx*04h+__0STAR],ebx
    jmp @subcol
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret

    @@3RD_STEP:
    mov byte ptr [edi+eax*04h+__ROWMARK],0FFh
    mov byte ptr [edi+ebx*04h+__COLMARK],00h
    mov [edi+eax*04h+__COLON],ecx
    @@2ND_STEP:
    lea ecx,[ebp-04h]
    mov edx,00FFFFFFh
    @chk2mtx:
    mov ebx,eax
    sub eax,ebp
    mov esi,[esp+__MTX]
    shl eax,10h
    mov ax,cx
    test ebx,ebx
    cmovns eax,ebx
    mov ebx,ebp
    @check2col:
    add ecx,04h
    jz @@5TH_STEP
    cmp byte ptr [edi+ecx*04h+__COLMARK],00h
    jnz @check2col
    add esi,ecx
    sal ecx,08h
    @zeroincol:
    sub esi,ebp
    mov cl,[edi+ebx*04h+__ROWMARK]
    cmp edx,[esi]
    sbb cl,00h
    cmovz eax,ebx
    cmovz edx,[esi]
    add ebx,04h
    jnz @zeroincol
    sar ecx,08h
    cmp edx,00h
    jnz @chk2mtx
    add ebx,[edi+eax*04h+__0STAR]
    jnz @@3RD_STEP
    jmp @@4TH_STEP
    @@5TH_STEP:
    mov [edi+__FREE0],eax
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx*04h+__COLROWMARK]
    cmovs edx,ecx
    mov ecx,ebp
    sub esi,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx*04h+__COLMARK],00h
    mov al,[esi+ecx+__MARKBYTE]
    adc al,[edi+ebx*04h+__ROWMARK]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi+ecx],eax
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    jnz @nx5row
    movzx eax,word ptr [edi+__FREE0+02h]
    movsx ecx,word ptr [edi+__FREE0+00h]
    add eax,ebp
    add ebx,[edi+eax*04h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov [edi+eax*04h+__0STAR],ecx
    mov edx,eax
    mov eax,[edi+ecx*04h+__0STARROW]
    mov [edi+ecx*04h+__0STARROW],edx
    mov ecx,[edi+eax*04h+__COLON]
    test eax,eax
    jnz @@4TH_STEP
    @@1ST_STEP:
    mov edx,ebp
    mov ecx,[esp+__SYS0]
    @restructure:
    mov eax,[edi+edx*04h+__0STARROW]
    shr eax,1Fh
    sub ecx,eax
    mov [edi+edx*04h+__COLROWMARK],eax
    add edx,04h
    jnz @restructure
    test ecx,ecx
    jnz @@2ND_STEP

    @count_result_STACK:
    mov eax,ebp
    mov esi,[esp+__SAVE]
    neg ebp
    xor ecx,ecx
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+eax*04h+__0STAR]
    add edx,ebp
    add ecx,[esi+edx]
    shr edx,02h
    add esi,ebp
    mov [ebx],dl
    add ebx,01h
    add eax,04h
    jnz @results

  • P.H.

    senior tag

    válasz P.H. #51 üzenetére

    Ennyit jelent 1 év...
    Újra elővettem (most már nem hagyok kritikus kódokat évekre elsüllyedni), kicsit átszerveztem a memóriahasználatot, a @@4TH_STEP-et és az elejét.

    63 db 25x25 mátrix/ezredmásodperc (K10 Opteron @2640 Mhz) így is megvan, jóval kisebb kóddal, IMUL+IDIV nélkül és kevesebb memóriaírással (jobban szereti a Celeron D @2266 Mhz, ő így 13,6 mátrixot számol ki ezredmásodpercenként):

    mov eax,edi
    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp-01h]
    mov eax,edi
    lea edi,[ebx+ebp*02h]
    neg ebp
    @mark0:
    mov [ebx+edx*04h],ecx
    sub edx,01h
    jns @mark0
    @@REDUCE_ROWS:
    mov [edi+00h],edx
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmova esi,[eax]
    cmovz edx,ecx
    add eax,04h
    add ecx,04h
    jnz @findrowmin
    mov ecx,ebp
    cmp esi,02000000h
    jz @specific
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+ecx+__MARKBYTE],00h
    cmovz edx,esi
    sub [eax+ecx],edx
    add ecx,04h
    jnz @subrow
    add ebx,04h
    jnz @rowmin
    jmp @@RECUDE_COLUMNS
    @specific:
    xor [edi+edx*02h+__0STARROW],ebx
    jns @@ABNORMAL_EXIT
    neg ecx
    mov [edi+ebx*02h+__COLROWMARK],edx
    add ecx,ebx
    mov [edi+ecx*02h+__0STAR],edx
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@1ST_STEP
    cmp dword ptr [edi+ebx*02h+__0STARROW],0
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    lea ecx,[ebp-04h]
    cmp esi,02000000h
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp dl,[eax+__MARKBYTE]
    cmovz edx,esi
    sub [eax],edx
    jnz @subcol
    mov edx,[edi+ecx*02h+__COLROWMARK]
    or edx,[edi+ebx*02h+__0STARROW]
    mov edx,ecx
    jnz @subcol
    mov [edi+ebx*02h+__0STARROW],edx
    sub edx,ebp
    mov [edi+ecx*02h+__COLROWMARK],ebx
    mov [edi+edx*02h+__0STAR],ebx
    jmp @subcol
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret

    @@3RD_STEP:
    mov byte ptr [edi+edx*02h+__ROWMARK],0FFh
    mov byte ptr [edi+ebx*02h+__COLMARK],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    lea ecx,[ebp-04h]
    mov edx,00FFFFFFh
    @chk2mtx:
    mov ebx,eax
    sub eax,ebp
    mov esi,[esp+__MTX]
    shl eax,10h
    mov ax,cx
    test ebx,ebx
    cmovns eax,ebx
    mov ebx,ebp
    @check2col:
    add ecx,04h
    jz @@5TH_STEP
    cmp byte ptr [edi+ecx*02h+__COLMARK],00h
    jnz @check2col
    add esi,ecx
    sal ecx,08h
    @zeroincol:
    sub esi,ebp
    mov cl,[edi+ebx*02h+__ROWMARK]
    cmp edx,[esi]
    sbb cl,00h
    cmovz eax,ebx
    cmovz edx,[esi]
    add ebx,04h
    jnz @zeroincol
    sar ecx,08h
    test edx,edx
    jnz @chk2mtx
    mov edx,eax
    sub eax,ebp
    add ebx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    jmp @@4TH_STEP
    @@5TH_STEP:
    mov [esp+__FREE0],eax
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx*02h+__COLROWMARK]
    cmovs edx,ecx
    mov ecx,ebp
    sub esi,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx*02h+__COLMARK],00h
    mov al,[esi+ecx+__MARKBYTE]
    adc al,[edi+ebx*02h+__ROWMARK]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi+ecx],eax
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    jnz @nx5row
    movzx eax,word ptr [esp+__FREE0+02h]
    movsx ecx,word ptr [esp+__FREE0+00h]
    lea edx,[eax+ebp]
    add ebx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov [edi+eax*02h+__0STAR],ecx
    mov eax,[edi+ecx*02h+__0STARROW]
    mov [edi+ecx*02h+__0STARROW],edx
    mov edx,eax
    sub eax,ebp
    mov ecx,[edi+eax*02h+__COLON]
    test edx,edx
    jnz @@4TH_STEP
    @@1ST_STEP:
    mov edx,ebp
    mov ecx,[esp+__SYS0]
    @restructure:
    mov eax,[edi+edx*02h+__0STARROW]
    shr eax,1Fh
    sub ecx,eax
    mov [edi+edx*02h+__COLROWMARK],eax
    add edx,04h
    jnz @restructure
    test ecx,ecx
    jnz @@2ND_STEP

    @count_result_STACK:
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Lassan, de biztosan elkezdett nőni az utasítások száma és vele együtt bizonyos utasítások hossza is. Ennek eredménye a mindezidáig leghatékonyabb kód K10-en (2.6 GHz + DDR2) és Prescott-on (2.26 GHz Celeron + DDR1).

    @entry:
    mov eax,[esi-04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    mov ebx,[esp+__TMP0] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    or edx,-1 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    mov ebx,[ebx+eax*04h] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    cmp eax,[esp+__ARGUMENT0] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    jz @finish // 1/0.33 ALU 0/1 --5--- 6(1) 0/4 0--- BRANCH
    sub edi,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    jg @finish // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov [esp+__TMP1],eax // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    jz @label2 // 1/0.33 ALU 0/1 --5--- (1) 0/1 0--- BRANCH
    mov ebp,[esi+edi*04h-04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    prefetchnta [ebx] // 1/0.5 AGU 1/1 ---2-- (1) 1/1 --2- LOAD
    mov [esi+__TMP2],ebx // 4/0.5 AGU 3/1 ----34 (1) 1/2 0--- STORE
    @movedown: //
    {0} add edx,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} mov ebx,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {2} cmp edi,edx // 1/0.33 ALU 1/1 --5--- (1) 1/d 01-- ALU
    {0} ja @label1 // 1/0.33 ALU fused ------ 6(1) 0/1 0--- BRANCH
    {1} mov ecx,[esi+edx*04h+00h+__PRIO] // 3.0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {2} mov eax,[esi+ecx*08h+__DIST] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {0} jz @label0 // 1/0.33 ALU 0/1 --5--- (1) 0/1 0--- BRANCH
    {1} mov ecx,eax // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {2} mov edx,[esi+edx*04h-04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {0} neg eax // 1/0.33 ALU 1/0.33 015--- 6(1) 1/d 01-- ALU
    {1} add eax,[esi+edx*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} cdq // 1/0.33 ALU 1/0.5 0-5--- (1) 1/d 01-- ALU
    {0} and eax,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    {1} add edx,ebx // 1/0.33 ALU 1/1 015--- (1) 1/d 01-- ALU
    {2} add eax,ecx // 1/0.33 ALU 1/1 015--- 4(1) 1/d 01-- ALU
    {0} mov ecx,[esi+edx*04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    @label0: //
    {1} cmp eax,[esi+ebp*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    @label1: //
    {2} cmovge ecx,ebp // 1/0.33 ALU *2/2 015--- 5(3) 10/d 01-- ALU
    {0} mov [esi+ebx*02h+__PRIO],ecx // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    {1} mov [esi+ecx*08h+__CONN],ebx // 4/0.5 AGU 3/1 ----34 6(2) 1/2 0--3 STORE+STA
    {2} jnge @movedown // 1/2 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov ebx,[esi+__TMP2] // 1/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    @label2: //
    movzx eax,byte ptr [ebx+STRUCT0.FIELD0] // 1/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    movzx ecx,byte ptr [ebx+STRUCT0.FIELD1] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    cmp byte ptr [esp+__ARGUMENT1+eax],00h // 4/0.5 AGU ALU 1/1 0152-- (2) 5/1 012- ALU+LOAD
    jz @entry // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov [esi+__TMP2],ecx // 4/0.5 AGU 3/1 ----34 (1) 1/2 0--- STORE
    @label3: //
    {0} sub dword ptr [esi+__TMP2],01h // 7/2.5 AGU ALU *6/1 015234 6(3) 5/2 012- LOAD+ALU+STORE
    {1} js @entry // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    {2} add ebx,STRUCT1SIZE // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    @highway: //
    {0} movzx ecx,byte ptr [ebx+STRUCT1.FIELD0] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {1} mov ebp,[ebx+STRUCT1.FIELD1] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    {2} mov edx,10000*1000 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {0} cmp ecx,11 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} cmovnz edx,ebp // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    {2} mov al,[ebx+STRUCT1.FIELD2] // 3/0.5 AGU 2/1 ---2-- 6(1) 5/1 --2- LOAD
    {0} add edx,ebp // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} or al,[ebx+STRUCT1.FIELD3] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 0-2- LOGIC+LOAD
    {2} test [esp+__ARGUMENT2+ecx],al // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 0-2- LOGIC+LOAD
    {0} movzx eax,byte ptr [ebx+STRUCT1.FIELD4] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    {1} mov ecx,[ebx+STRUCT1.FIELD5] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {2} cmovnz ebp,edx // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    {0} cmp al,0FFh // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} jnz @label4 // 1/0.33 ALU 0/1 --5--- 6(1) 0/4 0--- BRANCH
    @label5: //
    {2} mov al,[ebx+STRUCT1.FIELD6] // 3/0.3 AGU 2/1 ---2-- (1) 5/1 --2- LOAD
    {0} lea edx,[ebp+1000*1000] // 2/0.33 AGU 1/1 0----- (1) 1/d 01-- ALU
    {1} cmp al,[esp+__ARGUMENT3] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} mov eax,[esp+__TMP1] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {0} cmova edx,ebp // 1/0.33 ALU *2/2 015--- 5(3) 10/d 01-- ALU
    {1} cmp dword ptr [esi+ecx*08h+__CONN],01h // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} sbb ebp,ebp // 1/0.33 ALU *2/2 015--- 6(3) 10/10 -1-- ALU 1
    {0} add edx,[esi+eax*08h+__DIST] // 4/0.4 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {1} or ebp,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    {2} cmp ebp,[esi+ecx*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- 6(2) 5/1 012- ALU+LOAD
    {0} jge @label3 // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    {1} mov ebp,[esp+__ARGUMENT4] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {2} mov [ebp+ecx*04h],eax // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    mov eax,[esi+ecx*08h+__CONN] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    jc @moveup // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    lea eax,[edi*02h-00000002h] // 2/0.33 AGU 1/1 0----- (2) 2/1 01-- ALU
    sub edi,01h // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    @moveup: //
    {0} mov ebp,eax // 1/0.33 ALU 1/0.33 015--- 5(1) 1/d 01-- ALU
    {1} add eax,02h // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {2} and eax,-4 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    {0} mov ecx,[esi+eax+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {1} sar eax,01h // 1/0.33 ALU 1/0.5 0-5--- (1) 1/d -1-- SHIFT
    {2} cmp edx,[esi+ecx*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- 6(2) 5/1 012- ALU+LOAD
    {0} cmovae ecx,[ebx+STRUCT1.FIELD5] // 4/0.5 AGU ALU *4/2 0152-- (4) 10/3 012- ALU+LOAD
    {1} mov [esi+ebp*02h+__PRIO],ecx // 4/0.5 AGU 3/1 ----34 5(2) 1/2 0--3 STORE+STA
    {2} mov [esi+ecx*08h+__CONN],ebp // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    {0} jnae @moveup // 1/2 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov [esi+ecx*08h+__DIST],edx // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    jmp @label3 // 1/2 ALU 0/1 --5--- (1) 0/1 0--- BRANCH
    @label4: //
    lea edx,[eax+eax*04h] // 2/0.33 AGU 1/1 0----- (2) 2/1 01-- ALU
    add edx,edx // 1/0.33 ALU 1/0.33 015--- (1) d/d 01-- ALU
    sub eax,100 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    cmovbe eax,edx // 1/0.33 ALU *2/2 015--- (3) 10/3 01-- ALU
    cmp eax,[esp+__ARGUMENT5] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    lea edx,[ebp+1000*1000] // 2/0.5 AGU 1/1 0----- (1) 1/d 01-- ALU
    cmovna ebp,edx // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    jmp @label5 // 1/2 ALU 0/1 --5--- (1) 0/1 0--- BRANCH

    Összehasonlításképp a tesztbemeneten:
    - [link] ez a kód vitte le K10-en 1 milliárd órajelről 850 millió órajelre, a Prescott-on valamivel 3 milliárd órajel alá a lefutást
    - [link] ez K10-en 760 millió órajel alatt fut le, a Prescott-on 2.7 milliárd órajel alatt
    - a fenti kód K10-en 725 millió, Prescott-on 2.46 milliárd órajel

  • P.H.

    senior tag

    Sikerült megtalálni azt a megoldást, ami K8/K10-en, Prescott-on és Core2-n egyaránt a leghatékonyabb. Ezzel egyidőben azt a jelölésrendszert is, amellyel könnyedén nyomonkövethető mindhármuk viselkedése és "gyenge" pontjaik.

    @entry: //
    mov eax,[esi-04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    mov ebx,[esp+__TMP0] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    or ecx,-1 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    mov ebx,[ebx+eax*04h] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    mov ebp,[esi+edi*04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    cmp eax,[esp+__ARGUMENT0] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    jz @finish // 1/0.33 ALU 0/1 --5--- 6(1) 0/4 0--- BRANCH
    sub edi,ecx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    jg @finish // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov [esp+__TMP1],eax // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    jz @label2 // 1/0.33 ALU 0/1 --5--- (1) 0/1 0--- BRANCH
    prefetchnta [ebx] // 1/0.5 AGU 1/1 ---2-- 6(1) 1/1 --2- LOAD
    mov [esi+__TMP2],ebx // 4/0.5 AGU 3/1 ----34 (1) 1/2 0--- STORE
    @movedown: //
    {0} mov edx,[esi+ecx*08h+00h+__PRIO] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    {1} mov ebx,ecx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {2} add ecx,ecx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {0} cmp ecx,edi // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} jl @label1 // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    {2} mov eax,[esi+edx*08h+__DIST] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {0} jz @label0 // 1/0.33 ALU 0/1 --5--- 6(1) 0/4 0--- BRANCH
    {1} mov edx,[esi+ecx*04h-04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {2} mov ecx,eax // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {0} neg eax // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    {1} add eax,[esi+edx*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} cdq // 1/0.33 ALU 1/1 0-5--- 6(1) 1/d 01-- ALU
    {0} and eax,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    {1} add eax,ecx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {2} lea ecx,[edx+ebx*02h] // 2/0.33 AGU 1/1 0----- (2) 2/1 01-- ALU
    {0} mov edx,[esi+ecx*04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    @label0: //
    {1} cmp [esi+ebp*08h+__DIST],eax // 4/0.5 AGU ALU 3/1 0152-- 5(2) 5/1 012- ALU+LOAD
    @label1: //
    {2} cmovbe edx,ebp // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    {0} mov [esi+edx*08h+__CONN],ebx // 4/0.5 AGU 3/1 ----34 5(2) 1/2 0--3 STORE+STA
    {1} mov [esi+ebx*04h+__PRIO],edx // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    {2} jnbe @movedown // 1/2 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov ebx,[esi+__TMP2] // 1/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    @label2: //
    movzx eax,byte ptr [ebx+STRUCT0.FIELD0] // 1/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    movzx ecx,[ebx+STRUCT0.FIELD1] // 1/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    cmp byte ptr [esp+__ARGUMENT1+eax],00h // 4/0.5 AGU ALU 1/1 0152-- (2) 5/1 012- ALU+LOAD
    jz @entry // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov [esi+__TMP2],ecx // 4/0.5 AGU 3/1 ----34 (1) 1/2 0--- STORE
    @label3: //
    {0} sub dword ptr [esi+__TMP2],01h // 7/2.5 AGU ALU *6/1 015234 6(3) 5/2 012- LOAD+ALU+STORE
    {1} js @entry // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    {2} add ebx,STRUCT1SIZE // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {0} movzx ecx,byte ptr [ebx+STRUCT1.FIELD0] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {1} mov ebp,[ebx+STRUCT1.FIELD1] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    {2} mov edx,10000*1000 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {0} cmp ecx,11 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} cmovnz edx,ebp // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    {2} mov al,[ebx+STRUCT1.FIELD2] // 3/0.5 AGU 2/1 ---2-- 6(1) 5/1 --2- LOAD
    {0} add edx,ebp // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} or al,[ebx+STRUCT1.FIELD3] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 0-2- LOGIC+LOAD
    {2} and al,[esp+__ARGUMENT2+ecx] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 0-2- LOGIC+LOAD
    {0} movzx eax,byte ptr [ebx+STRUCT1.FIELD4] // 3/0.5 AGU 2/1 ---2-- 6(1) 4/1 --2- LOAD
    {1} mov ecx,[ebx+STRUCT1.FIELD5] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {2} cmovnz ebp,edx // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    {0} cmp al,0FFh // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {1} jnz @label4 // 1/0.33 ALU 0/1 --5--- 6(1) 0/4 0--- BRANCH
    @label5: //
    {2} mov al,[ebx+STRUCT1.FIELD6] // 3/0.3 AGU 2/1 ---2-- (1) 5/1 --2- LOAD
    {0} lea edx,[ebp+1000*1000] // 2/0.33 AGU 1/1 0----- (1) 1/d 01-- ALU
    {1} cmp al,[esp+__ARGUMENT3] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} mov eax,[esp+__TMP1] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {0} cmova edx,ebp // 1/0.33 ALU *2/2 015--- 5(3) 10/d 01-- ALU
    {1} cmp dword ptr [esi+ecx*08h+__CONN],01h // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} sbb ebp,ebp // 1/0.33 ALU *2/2 015--- 6(3) 10/10 -1-- ALU 1
    {0} add edx,[esi+eax*08h+__DIST] // 4/0.4 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {1} or ebp,edx // 1/0.33 ALU 1/0.33 015--- (1) 1/d 0--- LOGIC
    {2} cmp ebp,[esi+ecx*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- 6(2) 5/1 012- ALU+LOAD
    {0} jge @label3 // 1/0.33 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    {1} mov ebp,[esp+__ARGUMENT4] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {2} mov [ebp+ecx*04h],eax // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    lea eax,[edi-01h] // 1/0.33 ALU 1/1 0----- 5(1) 1/d 01-- ALU
    cmovc eax,[esi+ecx*08h+__CONN] // 4/0.5 AGU ALU *4/2 0152-- (4) 10/3 012- ALU+LOAD
    adc edi,-1 // 1/0.33 ALU *2/2 015--- (3) 10/10 -1-- ALU 1
    @moveup: //
    {0} mov ebp,eax // 1/0.33 ALU 1/0.33 015--- 6(1) 1/d 01-- ALU
    {1} add eax,01h // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    {2} sar eax,01h // 1/0.33 ALU 1/0.5 0-5--- (1) 1/d -1-- SHIFT
    {0} mov ecx,[esi+eax*04h+__PRIO] // 3/0.5 AGU 2/1 ---2-- (1) 4/1 --2- LOAD
    {1} cmp edx,[esi+ecx*08h+__DIST] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    {2} cmovae ecx,[ebx+STRUCT1.FIELD5] // 4/0.5 AGU ALU *4/2 0152-- 6(4) 10/3 012- ALU+LOAD
    {0} mov [esi+ebp*04h+__PRIO],ecx // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    {1} mov [esi+ecx*08h+__CONN],ebp // 4/0.5 AGU 3/1 ----34 3(2) 1/2 0--3 STORE+STA
    {2} jnae @moveup // 1/2 ALU 0/1 --5--- (1) 0/4 0--- BRANCH
    mov [esi+ecx*08h+__DIST],edx // 4/0.5 AGU 3/1 ----34 (2) 1/2 0--3 STORE+STA
    jmp @label3 // 1/2 ALU 0/1 --5--- (1) 0/1 0--- BRANCH
    @label4: //
    lea edx,[eax+eax*04h] // 2/0.33 AGU 1/1 0----- (2) 2/1 01-- ALU
    add edx,edx // 1/0.33 ALU 1/0.33 015--- (1) d/d 01-- ALU
    sub eax,100 // 1/0.33 ALU 1/0.33 015--- (1) 1/d 01-- ALU
    cmovbe eax,edx // 1/0.33 ALU *2/2 015--- (3) 10/3 01-- ALU
    cmp eax,[esp+__ARGUMENT5] // 4/0.5 AGU ALU 3/1 0152-- (2) 5/1 012- ALU+LOAD
    lea edx,[ebp+1000*1000] // 2/0.5 AGU 1/1 0----- (1) 1/d 01-- ALU
    cmovna ebp,edx // 1/0.33 ALU *2/2 015--- (3) 10/d 01-- ALU
    jmp @label5 // 1/2 ALU 0/1 --5--- (1) 0/1 0--- BRANCH

  • P.H.

    senior tag

    A Carry Flag a programozó legjobb barátja; utána jön a sorban az SBB same_reg és az ADC. 1-2% is valami, főleg ~3 másodperces lefutás mellett.
    Az utasítás-alignment AMD CPU-k számára talán még csiszolható kicsit.

  • P.H.

    senior tag

    A téma ugyanaz, a fejlesztés "látszólag" kicsi, valójában több 10%-os. A CPU így látja a kódot:
    cím - gép kód - disassembly; a fekete nyíl ciklusugrás, a halványabb feltételes (ami itt szinte sosem irányít át, viszont a helyességhez kell), a leghalványabb a feltétel nélküli ugrás.
    280 byte, 92 utasítás: 3.03 byte átlagos utasításhossz.

  • P.H.

    senior tag

    válasz P.H. #63 üzenetére

    Még pár 10 millió órajelnyi csökkentés benne volt Netburst-ön, a @down ciklus kisebbre vételének (20 » 16 utasítás) köszönhetően.

    Utasításadatok a 2 konkrét gépre immár az AIDA64 Instruction Dump-nak megfelelően (Northwood és Prescott):

    mov eax,[esi-08h+__PRIO] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    mov ebx,[esi+__PACKADAT2] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    or edx,-1 // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    cmp eax,[esp+__STOPINDEX] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    mov ebp,[esi+edi*08h+__PRIO] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    mov ebx,[ebx+eax*04h] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    jz @finish // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov [esi+eax*08h+__CONN],eax // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    sub edi,edx // (1) d/d p01 ALU (1) 1/d p01 ALU
    jg @finish // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov [esi+__RELAXED],eax // (1) 1/2 p0 STORE (1) 1/2 p0 STORE
    jz @block // (1) 0/1 p0 BRANCH (1) 0/1 p0 BRANCH
    prefetchnta [ebx] // (6) 6/6 p2 LOAD (1) 1/1 p2 LOAD
    mov ebp,[esi+ebp*08h+__DIST] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    mov [esi+__HEADER],ebx // (1) 1/2 p0 STORE (1) 1/2 p0 STORE
    @down: //
    lea eax,[edx+edx] // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov ecx,[esi+eax*08h-08h+__PRIO] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    cmp eax,edi // (1) d/d p01 ALU (1) 1/d p01 ALU
    jl @insertdown // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ebx,[esi+eax*08h+00h+__PRIO] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    mov ecx,[esi+ecx*08h+__DIST] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    jz @child // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    cmp ecx,[esi+ebx*08h+__DIST] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    sbb eax,00h // (3) 7/7 p1 ALU 1 (3) 10/10 p1 ALU 1
    mov ebx,[esi+eax*08h+__PRIO] // {1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    @child: //
    cmp ebp,[esi+ebx*08h+__DIST] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    @insertdown: //
    cmovbe ebx,[esi+edi*08h-08h+__PRIO] // (4) 6/1 p01+2 ALU+LOAD (4) 10/3 p01+2 ALU+LOAD
    mov [esi+edx*08h+__PRIO],ebx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    mov [esi+ebx*08h+__CONN],edx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    mov edx,eax // (1) d/d p01 ALU (1) 1/d p01 ALU
    jnbe @down // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ebx,[esi+__HEADER] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    @block: //
    movzx eax,byte ptr [ebx+STRUCT0.FIELD0] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    movzx ecx,byte ptr [ebx+STRUCT0.FIELD1] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    add ebx,STRUCT0SIZE-STRUCT1SIZE // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmp byte ptr [esp+WORKAREA0+eax],00h // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    jz @entry // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov [esi+__HEADER],ecx // (1) 1/2 p0 STORE (2) 1/2 p0 STORE
    @connects: //
    sub dword ptr [esi+__HEADER],01h // (3) 9/2 p01+2 ALU+LOAD+STORE (3) 5/2 p01+2 ALU+LOAD+STO
    js @entry // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ecx,[ebx+STRUCT1SIZE+STRUCT1.FIELD0] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    add ebx,STRUCT1SIZE // (1) d/d p01 ALU (1) 1/d p01 ALU
    movzx edx,byte ptr [ebx+STRUCT1.FIELD1] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    cmp dword ptr [esi+ecx*08h+__CONN],00h // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    jg @connects // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    @label1: //
    mov al,[ebx+STRUCT1.FIELD2] // (1) 3/1 p2 LOAD (1) 5/1 p2 LOAD
    mov ebp,[ebx+STRUCT1.FIELD3] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    or al,[ebx+STRUCT1.FIELD4] // (2) 3/1 p0+2 LOGIC+LOAD (2) 5/1 p0+2 LOGIC+LOAD
    and al,[esp+WORKAREA1+edx] // (2) 3/1 p0+2 LOGIC+LOAD (2) 5/1 p0+2 LOGIC+LOAD
    cmp edx,11 // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov edx,10000*1000 // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmovnz edx,ebp // (3) 6/1 p01 ALU (3) 10/d p01 ALU
    add edx,ebp // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmp al,00h // (1) d/d p01 ALU (1) 1/d p01 ALU
    movzx eax,byte ptr [ebx+STRUCT1.FIELD5] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    cmovnz ebp,edx // (3) 6/1 p01 ALU (3) 10/d p01 ALU
    @label2: //
    cmp al,0FFh // (1) d/d p01 ALU (1) 1/d p01 ALU
    jnz @label4 // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    @label3: //
    mov al,[ebx+STRUCT1.FIELD6] // (1) 2/1 p2 LOAD (1) 5/1 p2 LOAD
    lea edx,[ebp+1000*1000] // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmp al,[esp+ARGUMENT1] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    mov eax,[esi+__RELAXED] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    cmova edx,ebp // (3) 6/1 p01 ALU (3) 10/d p01 ALU
    sub ebp,ebp // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmp ebp,[esi+ecx*08h+__CONN] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    rcl ebp,01h // (1) 4/4 p1 ALU 1 (1) 7/7 p1 ALU 1
    sub ebp,01h // (1) d/d p01 ALU (1) 1/d p01 ALU
    add edx,[esi+eax*08h+__DIST] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    or ebp,edx // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    cmp [esi+ecx*08h+__DIST],ebp // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    jle @connects // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ebp,[esi+ecx*08h+__CONN] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    mov [esi+ecx*08h+__DIST],edx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    neg ecx // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    cmp ebp,00h // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov [esi+ecx*08h+__PREV],eax // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    jnz @moveup // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    sub edi,01h // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov ebp,edi // (1) d/d p01 ALU (1) 1/d p01 ALU
    @moveup: //
    mov eax,ebp // (1) d/d p01 ALU (1) 1/d p01 ALU
    sar ebp,01h // (1) 4/1 p1 MMX_SHIFT (1) 1/d p1 SHIFT
    mov ecx,[esi+ebp*08h+__PRIO] // (1) 2/1 p2 LOAD (1) 4/1 p2 LOAD
    cmp eax,-2 // (1) d/d p01 ALU (1) 1/d p01 ALU
    ja @insertup // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    cmp edx,[esi+ecx*08h+__DIST] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    @insertup: //
    cmovae ecx,[ebx+STRUCT1.FIELD0] // (4) 6/1 p01+2 ALU+LOAD (4) 10/3 p01+2 ALU+LOAD
    mov [esi+eax*08h+__PRIO],ecx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    mov [esi+ecx*08h+__CONN],eax // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    jnae @moveup // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    jmp @connects // (1) 0/1 p0 BRANCH (1) 0/1 p0 BRANCH
    @label4: //
    lea edx,[eax+eax*04h] // (2) 4/1 p01 ALU (2) 2/1 p01 ALU
    add edx,edx // (1) d/d p01 ALU (1) d/d p01 ALU
    sub eax,100 // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmovbe eax,edx // (3) 6/1 p01 ALU (3) 10/3 p01 ALU
    cmp eax,[esp+ARGUMENT1] // (2) 3/1 p01+2 ALU+LOAD (2) 5/1 p01+2 ALU+LOAD
    lea edx,[ebp+1000*1000] // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmovna ebp,edx // (3) 6/1 p01 ALU (3) 10/d p01 ALU
    jmp @label3 // (1) 0/1 p0 BRANCH (1) 0/1 p0 BRANCH

  • P.H.

    senior tag

    Néhány 10 millió órajellel (~1-2%) csökkenthető a milliárd órajel nagyságrendű Netburst-lefutás úgy, hogy a módosítások (egyszerűbb címzések; port 0-ra kötött test reg,reg helyett általánosabb, port 0/1-es cmp reg,00h használata; a __QUEUESIZE marad végig register-ben, más érték jellemzően csak olvasott és ritkábban van rá szükség) a fejlettebbek mikroarch-okat sem hátráltatják.

    @entry:
    mov eax,[esi-08h+__PRIO]
    mov ebx,[esi+__PACKADAT2]
    mov edx,0FFFFFFF8h
    cmp edi,[esp+__STOPINDEX]
    mov ebp,[esi+edi+__PRIO]
    mov ebx,[ebx+eax*04h]
    jz @finish
    sub edi,edx
    mov [esi+eax*08h+__CONN],eax
    jg @finish
    mov [esi+__RELAXED],eax
    jz @block
    prefetchnta [ebx]
    mov [esi+__HEADER],ebx
    @down:
    mov ecx,edx
    add edx,edx
    mov ebx,ebp
    cmp edx,edi
    jl @insertdown
    mov eax,[esi+edx+00h+__PRIO]
    mov ebx,[esi+edx-08h+__PRIO]
    mov eax,[esi+eax*08h+__DIST]
    jz @child
    mov ebx,[esi+ebx*08h+__DIST]
    cmp eax,ebx
    cmovnbe eax,ebx
    lea ebx,[edx-08h]
    cmovnbe edx,ebx
    @child:
    cmp [esi+ebp*08h+__DIST],eax
    mov ebx,[esi+edx+__PRIO]
    cmovbe ebx,ebp
    @insertdown:
    mov [esi+ecx+__PRIO],ebx
    mov [esi+ebx*08h+__CONN],ecx
    jnbe @down
    mov ebx,[esi+__HEADER]
    @block:
    movzx eax,byte ptr [ebx+STRUCT0.FIELD0]
    movzx ecx,byte ptr [ebx+STRUCTO.FIELD1]
    add ebx,STRUCT0SIZE-STRUCT1SIZE
    cmp byte ptr [esp+WORKAREA0+eax],00h
    jz @entry
    mov [esi+__HEADER],ecx
    @connects:
    sub dword ptr [esi+__HEADER],01h
    js @entry
    add ebx,STRUCT1SIZE
    mov eax,[ebx+STRUCT1.FIELD0]
    movzx edx,byte ptr [ebx+STRUCT1.FIELD1]
    cmp dword ptr [esi+eax*08h+__CONN],00h
    jg @connects
    @label1:
    mov al,[ebx+STRUCT1.FIELD2]
    mov ebp,[ebx+STRUCT1.FIELD3]
    or al,[ebx+STRUCT1.FIELD4]
    and al,[esp+WORKAREA1+edx]
    cmp edx,11
    mov edx,10000*1000
    cmovnz edx,ebp
    add edx,ebp
    cmp al,00h
    movzx eax,byte ptr [ebx+STRUCT1.FIELD5]
    cmovnz ebp,edx
    @label2:
    cmp al,0FFh
    jz @label3
    lea edx,[eax+eax*04h]
    add edx,edx
    sub eax,100
    cmovbe eax,edx
    cmp eax,[esp+ARGUMENT0]
    lea edx,[ebp+1000*1000]
    cmovna ebp,edx
    @label3:
    mov al,[ebx+STRUCT1.FIELD6]
    lea edx,[ebp+1000*1000]
    cmp al,[esp+ARGUMENT1]
    mov eax,[esi+__RELAXED]
    cmova edx,ebp
    sub ebp,ebp
    cmp ebp,[esi+ecx*08h+__CONN]
    rcl ebp,01h
    sub ebp,01h
    add edx,[esi+edi*08h+__DIST]
    or ebp,edx
    cmp [esi+ecx*08h+__DIST],ebp
    jle @connects
    mov ebp,[esi+ecx*08h+__CONN]
    mov [esi+ecx*08h+__DIST],edx
    neg ecx
    cmp ebp,00h
    mov [esi+ecx*08h+__PREV],eax
    jnz @moveup
    sub edi,08h
    mov ebp,edi
    @moveup:
    mov eax,ebp
    sar ebp,04h
    cmp eax,-2*8
    mov ecx,[esi+ebp*08h+__PRIO]
    ja @insertup
    sal ebp,03h
    cmp edx,[esi+ecx*08h+__DIST]
    @insertup:
    cmovae ebp,[ebx+STRUCT1.FIELD0]
    mov [esi+eax+__PRIO],ebp
    mov [esi+ebp*08h+__CONN],eax
    jnae @moveup
    jmp @connects

  • P.H.

    senior tag

    Eddig sosem sikerült igazán hatékonyan kihasználnom a prefetch-utasításokat, most viszont a legjobbkor, a megfelelő algoritmusnál sikerült ráérezni: az egész kód elejére (amikor még nem függ tőle semmi egy ideig) áttéve a legvéletlenszerűbb betöltést és előbetöltve az az által címzett adatot kb. 20% gyorsulást eredményezett a teljes lefutási időt tekintve.

    Így, ameddig a @down ciklus (előre meg nem jósolható számú, de biztosan 1-21 közötti) lefutása megtörténik, addig az esetek egy nem elhanyagolható részében kényelmesen megérkezik az utána következő @block-rész és @connects-ciklus által feldolgozott adat az L1D-be.

    Így a program mostantól legalább Pentium3-at igényel az SSE miatt.

    @entry:
    mov edi,[esi-08h+__PRIO]
    mov ecx,[esi+__QUEUESIZE]
    ---> mov ebx,[esi+__PACKADAT2]
    or edx,-1
    mov ebp,[esi+ecx*08h+__PRIO]
    ---> mov ebx,[ebx+edi*04h]
    cmp edi,[esp+__STOPINDEX]
    jz @finish
    sub ecx,edx
    mov [esi+edi*08h+__CONN],edi
    jg @finish
    mov [esi+__QUEUESIZE],ecx
    jz @block
    mov [esi+__HEADER],ebx
    ---> prefetchnta [ebx]
    @down:
    mov ecx,edx
    add edx,edx
    mov ebx,ebp
    cmp edx,[esi+__QUEUESIZE]
    jl @insertdown
    mov eax,[esi+edx*08h+00h+__PRIO]
    mov ebx,[esi+edx*08h-08h+__PRIO]
    mov eax,[esi+eax*08h+__DIST]
    jz @child
    mov ebx,[esi+ebx*08h+__DIST]
    cmp eax,ebx
    cmovnbe eax,ebx
    lea ebx,[edx-01h]
    cmovnbe edx,ebx
    @child:
    cmp [esi+ebp*08h+__DIST],eax
    mov ebx,[esi+edx*08h+__PRIO]
    cmovbe ebx,ebp
    @insertdown:
    mov [esi+ecx*08h+__PRIO],ebx
    mov [esi+ebx*08h+__CONN],ecx
    jnbe @down
    mov ebx,[esi+__HEADER]
    @block:
    movzx eax,byte ptr [ebx+STRUCT0.FIELD0]
    movzx ecx,byte ptr [ebx+STRUCTO.FIELD1]
    add ebx,STRUCT0SIZE-STRUCT1SIZE
    cmp byte ptr [esp+WORKAREA0+eax],00h
    jz @entry
    mov [esi+__HEADER],ecx
    @connects:
    sub dword ptr [esi+__HEADER],01h
    js @entry
    add ebx,STRUCT1SIZE
    mov eax,[ebx+STRUCT1.FIELD0]
    movzx edx,byte ptr [ebx+STRUCT1.FIELD1]
    mov ecx,[esi+eax*08h+__CONN]
    test ecx,ecx
    jg @connects
    @label1:
    mov al,[ebx+STRUCT1.FIELD2]
    mov ebp,[ebx+STRUCT1.FIELD3]
    or al,[ebx+STRUCT1.FIELD4]
    and al,[esp+WORKAREA1+edx]
    cmp edx,11
    mov edx,10000*1000
    cmovnz edx,ebp
    add edx,ebp
    test al,al
    movzx eax,byte ptr [ebx+STRUCT1.FIELD5]
    cmovnz ebp,edx
    @label2:
    cmp al,0FFh
    jz @label3
    lea edx,[eax+eax*04h]
    add edx,edx
    sub eax,100
    cmovbe eax,edx
    cmp eax,[esp+ARGUMENT0]
    lea edx,[ebp+1000*1000]
    cmovna ebp,edx
    @label3:
    mov al,[ebx+STRUCT1.FIELD6]
    cmp al,[esp+ARGUMENT1]
    lea edx,[ebp+1000*1000]
    mov eax,[ebx+STRUCT1.FIELD0]
    cmova edx,ebp
    sub ebp,ebp
    cmp ecx,01h
    rcl ebp,01h
    neg ebp
    add edx,[esi+edi*08h+__DIST]
    or ebp,edx
    cmp [esi+eax*08h+__DIST],ebp
    jle @connects
    mov [esi+eax*08h+__DIST],edx
    neg eax
    cmp ecx,00h
    mov [esi+eax*08h+__PREV],edi
    jnz @moveup
    mov ecx,[esi+__QUEUESIZE]
    sub ecx,01h
    mov [esi+__QUEUESIZE],ecx
    @moveup:
    mov eax,ecx
    sar ecx,01h
    mov ebp,[esi+ecx*08h+__PRIO]
    cmp eax,-2
    ja @insertup
    cmp edx,[esi+ebp*08h+__DIST]
    @insertup:
    cmovae ebp,[ebx+STRUCT1.FIELD0]
    mov [esi+eax*08h+__PRIO],ebp
    mov [esi+ebp*08h+__CONN],eax
    jnae @moveup
    jmp @connects

  • P.H.

    senior tag

    Egy, az eredeti irodalmihoz képest szinte teljesen átfogalmazott, egy szálas algoritmus; régi fejlesztés legfrissebb állomása.
    Ennél randomabb és nagyobb mennyiségű adattal dolgozó algoritmust nehéz elképzelni: ideiglenes munkaterülete és forrásadata is 100 MB nagyságrendű, cache-éhsége nem ismer határokat (2.6 GHz-es, 6 MB L3-mal ellátott K10.5 Opteronon közel 2x gyorsabb, mint 2.9 GHz-es X2 245-ön).

    Az egész ~200 byte, futásideje bemeneti paraméterektől függően mégis hosszú másodpercekben mérhető; pedig van itt minden:
    - a végletekig kiegyenesített kód (a megmaradt feltételes ugrások előre kiszámíthatóan "always not taken" vagy "always taken" kategóriájúak
    - 4, több millió 32 bites elemből álló tömb címzése egyetlen bázisregiszterrel (pozitív és negatív oldalon egyaránt 2-2 egymás mellett, elemenként váltva)
    - cache-optimalizáció 2 tömbre: az egyik olvasása/írása általában maga után vonja a másik tömb azonos elemének hozzáférését
    - függőségek és decode-limitációk figyelembevételével utasítássorrend-optimalizálás AMD-re, Netburst-re és Core2-re (nem külön-külön, hanem mindenen a lehető legjobb megoldás)

    Így K10.5-ön produkál X2 245-ön 0.2-0.3 IPC-t. Ennél jobbat nem is lehet elvárni tőle 32 biten; +5 register-rel még tovább lehetne gyorsítani.

    (Northwood és Prescott)
    @entry: //
    mov edi,[esi+(-1*08h)+__PRIO] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov ebx,[esi+__QUEUESIZE] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    or edx,-1 // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    cmp edi,[esp+__STOPINDEX] // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    jz @finish // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ebp,[esi+ebx*08h+__PRIO] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov [esi+edi*08h+__CONN],edi // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    sub ebx,edx // (1) d/d p01 ALU (1) 1/d p01 ALU
    jg @finish // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov [esi+__QUEUESIZE],ebx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    jz @block // (1) 0/1 p0 BRANCH (1) 0/1 p0 BRANCH
    @down: //
    mov ecx,edx // (1) d/d p01 ALU (1) 1/d p01 ALU
    add edx,edx // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov ebx,ebp // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmp edx,[esi+__QUEUESIZE] // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    jl @insertdown // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov eax,[esi+edx*08h+00h+__PRIO] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov ebx,[esi+edx*08h-08h+__PRIO] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov eax,[esi+eax*08h+__DIST] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    jz @child // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ebx,[esi+ebx*08h+__DIST] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    cmp eax,ebx // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmovnbe eax,ebx // (3) 6/3 (3) 10/3
    lea ebx,[edx-01h] // (1) 2/d p01 ALU (1) 3/d p01 ALU
    cmovnbe edx,ebx // (3) 6/3 (3) 10/3
    @child: //
    cmp [esi+ebp*08h+__DIST],eax // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    mov ebx,[esi+edx*08h+__PRIO] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    cmovbe ebx,ebp // (3) 6/3 (3) 10/3
    @insertdown: // -POS < -QSIZE -> UNSIGNED(-POS) < UNSIGNED(-QSIZE)
    mov [esi+ecx*08h+__PRIO],ebx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    mov [esi+ebx*08h+__CONN],ecx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    jnbe @down // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    @block: //
    mov ebx,[_POINTERARRAY] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov ebx,[ebx+edi*04h] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    movzx eax,byte ptr [ebx+STRUCT0.KOD] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov cl,[ebx+STRUCT0.COUNT] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    add ebx,STRUCT0SIZE-STRUCT1SIZE // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmp byte ptr [esp+__WORKAREA1+eax],00h // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    jz @entry // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov [esi+__STRUCT1COUNT],cl // (1) 1/2 p0 STORE (1) 1/2 p0 STORE
    @connects: //
    sub byte ptr [esi+__STRUCT1COUNT],01h // (3) 8/4 p01+2 ALU+LOAD+STORE (3) 5/2 p01+2 ALU+LOAD+STORE
    js @entry // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    add ebx,STRUCT1SIZE // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov eax,[ebx+STRUCT1SIZE.FIELD1] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    movzx edx,byte ptr [ebx+STRUCT1.FIELD2] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov ecx,[esi+eax*08h+__CONN] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    test ecx,ecx // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    jg @connects // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    @label1: //
    mov al,[ebx+STRUCT1.FIELD3] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    mov ebp,[ebx+STRUCT1.FIELD4] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    or al,[ebx+STRUCT1.FIELD5] // (2) 2/1 p0+2 LOGIC+LOAD (2) 1/1 p0+2 LOGIC+LOAD
    and al,[esp+__WORKAREA2+edx] // (2) 2/1 p0+2 LOGIC+LOAD (2) 1/1 p0+2 LOGIC+LOAD
    cmp edx,11 // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov edx,10000*1000 // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmovnz edx,ebp // (3) 6/3 (3) 10/3
    add edx,ebp // (1) d/d p01 ALU (1) 1/d p01 ALU
    test al,al // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    cmovnz ebp,edx // (3) 6/3 (3) 10/3
    @label2: //
    movzx eax,byte ptr [ebx+STRUCT1.FIELD6] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    cmp al,0FFh // (1) d/d p01 ALU (1) 1/d p01 ALU
    jz @label3 // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    lea edx,[eax+eax*04h] // (2) 5/1 p01 ALU (2) 4/1 p01 ALU
    add edx,edx // (1) d/d p01 ALU (1) d/d p01 ALU
    sub eax,100 // (1) d/d p01 ALU (1) 1/d p01 ALU
    cmovbe eax,edx // (3) 6/3 (3) 10/3
    cmp eax,[esp+ARGUMENT0] // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    lea edx,[ebp+1000*1000] // (1) 2/d p01 ALU (1) 3/d p01 ALU
    cmovna ebp,edx // (3) 6/3 (3) 10/3
    @label3: //
    mov al,[ebx+STRUCT1.FIELD7] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    cmp al,[esp+__ARGUMENT1] // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    lea edx,[ebp+1000*1000] // (1) 2/d p01 ALU (1) 3/d p01 ALU
    mov eax,[ebx+STRUCT2SIZE.FIELD1] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    cmova edx,ebp // (3) 6/3 (3) 10/3
    cmp ecx,01h // (1) d/d p01 ALU (1) 1/d p01 ALU
    sbb ebp,ebp // (8) 6/6 p1 ALU 1 (3) 10/10 p1 ALU 1
    add edx,[esi+edi*08h+__DIST] // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    or ebp,edx // (1) d/d p0 LOGIC (1) 1/d p0 LOGIC
    cmp [esi+eax*08h+__DIST],ebp // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    jle @connects // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov [esi+eax*08h+__DIST],edx // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    neg eax // (1) 2/d p0 LOGIC (1) 1/d p0 LOGIC
    cmp ecx,00h // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov [esi+eax*08h+__PREV],edi // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    jnz @moveup // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    mov ecx,[esi+__QUEUESIZE] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    sub ecx,01h // (1) d/d p01 ALU (1) 1/d p01 ALU
    mov [esi+__QUEUESIZE],ecx // (1) 1/2 p0 STORE (2) 1/2 p0+3 STORE+STA
    @moveup: //
    mov eax,ecx // (1) d/d p01 ALU (1) 1/d p01 ALU
    sar ecx,01h // (1) 4/1 p1 MMX_SHIFT (1) 1/d p1 ALU 1
    mov ebp,[esi+ecx*08h+__PRIO] // (1) 2/1 p2 LOAD (1) 2/1 p2 LOAD
    cmp eax,-2 // (1) d/d p01 ALU (1) 1/d p01 ALU
    ja @insertup // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    cmp edx,[esi+ebp*08h+__DIST] // (2) 2/1 p01+2 ALU+LOAD (2) 1/1 p01+2 ALU+LOAD
    @insertup: //
    cmovae ebp,[ebx+STRUCT1.FIELD1] // (4) 6/3 p01+2 ALU+LOAD (4) 10/3 p01+2 ALU+LOAD
    mov [esi+eax*08h+__PRIO],ebp // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    mov [esi+ebp*08h+__CONN],eax // (2) 1/2 p0+3 STORE+STA (2) 1/2 p0+3 STORE+STA
    jnae @moveup // (1) 0/4 p0 BRANCH (1) 0/4 p0 BRANCH
    jmp @connects // (1) 0/1 p0 BRANCH (1) 0/1 p0 BRANCH

  • P.H.

    senior tag

    Kép forgatása a saját középpontja körül megadott szöggel. Itt már mindenképpen ügyelni kell arra, hogy a forrásképen kapott koordináta nem legyen a képen kívül. Az x87 megvalósítás régóta kész, a főciklus (az inicializáslás nem publikus :) ):

    @rotaterowX87:
    mov ecx,ebx
    fld st(2)
    fsub st,st(2)
    not ecx
    fxch st(3)
    lea eax,[eax+ebx*04h]
    fld st(4)
    sal ecx,02h
    fsub st,st(2)
    fxch st(5)
    @destX87:
    add ecx,04h
    fist dword ptr [esp]
    mov ebp,ebx
    fadd st,st(3)
    jns @nxrotateX87
    fxch
    imul ebp,[esp]
    fist dword ptr [esp]
    fsub st,st(2)
    cmp edx,ebp
    fxch
    jbe @destX87
    cmp ebx,[esp]
    jbe @destX87
    add ebp,[esp]
    mov ebp,[esi+ebp*04h]
    mov [eax+ecx],ebp
    jmp @destX87
    @nxrotateX87:
    sub dword ptr [edi+_ESP],01h
    fcompp
    jg @rotaterowX87
    jmp @returnROTATE

    SSE2-variációban most ugyanez:

    @rotateSSE2:
    sub dword ptr [edi+_ESP],01h
    mov ecx,ebx
    js @returnROTATE
    movapd xmm0,xmm5
    not ecx
    subpd xmm5,xmm4
    lea eax,[eax+ebx*04h]
    sal ecx,02h
    @destSSE2:
    cvtpd2dq xmm1,xmm0
    add ecx,04h
    movd ebp,xmm1
    pshuflw xmm1,xmm1,10001000b
    jns @rotateSSE2
    pmaddwd xmm1,xmm7
    addpd xmm0,xmm6
    cmp ebx,ebp
    jbe @destSSE2
    movd ebp,xmm1
    cmp edx,ebp
    jbe @destSSE2
    mov ebp,[esi+ebp*04h]
    mov [eax+ecx],ebp
    jmp @destSSE2

    Prescott Celeron-on futtatva 1100*1100-as képre az x87-megoldás 55M órajel alatt fut le, az SSE2-es 49M órajel alatt.
    Mindkét kód hátránya, hogy nem színhelyesek: a forrásképen a tört koordinátához legközelebbi pixelt teszik rá a célképre. Az SSE2-es program kibővíthető úgy, hogy teljesen színhelyes legyen:

    uop latency/throughput subunit

    @rotateSSE2: // --- NORTHWOOD --- --- K8 ---
    sub dword ptr [edi+_ESP],01h // 3 8/4
    mov ecx,ebx // 1 d/d p0/1 ALU 0/1 1 1/1 p012 ALU 012
    js @returnROTATE // 1 -/4 p0 BRANCH 1 1/1 p012 ALU 012
    movapd xmm0,xmm5 // 1 6/1 p0 MOV 2 2/1 p34 FA/M
    not ecx // 1 d/d p0/1 ALU 0/1 1 1/1 p012 ALU 012
    subpd xmm5,xmm4 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    lea eax,[eax+ebx*04h] // 2 4/1 p1 ALU 1
    sal ecx,02h // 1 4/1 p1 MMX_SHIFT 1 1/1 p012 ALU 012
    @destSSE2: //
    cvttpd2dq xmm1,xmm0 // 2 9/2 p1 FP_MMX 4 8/3 p5 FMISC
    add ecx,04h // 1 d/d p0/1 ALU 0/1 1 1/1 p012 ALU 012
    movd ebp,xmm1 // 2 11/1 p0+1 MOV+FP_MISC 3 2/2 p5 FMISC+ALU
    movapd xmm3,xmm1 // 1 6/1 p0 MOV 2 2/1 p34 FA/M
    pshuflw xmm1,xmm1,10001000b // 1 3/2 p1 MMX_SHIFT 2 2/1 p45 FA/M
    jns @rotateSSE2 // 1 -/4 p0 BRANCH 1 1/1 p012 ALU 012
    pmaddwd xmm1,xmm7 // 1 7/2 p1 FP_MUL 2 3/2 p4 FMUL
    movapd xmm2,xmm0 // 1 6/1 p0 MOV 2 2/1 p34 FA/M
    addpd xmm0,xmm6 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    cmp ebx,ebp // 1 d/d p0/1 ALU 0/1 1 1/1 p012 ALU 012
    jbe @destSSE2 // 1 -/4 p0 BRANCH 1 1/1 p012 ALU 012
    movd ebp,xmm1 // 2 11/1 p0+1 MOV+FP_MISC 3 2/2 p5 FMISC+ALU
    cmp edx,ebp // 1 d/d p0/1 ALU 0/1 1 1/1 p012 ALU 012
    jbe @destSSE2 // 1 -/4 p0 BRANCH 1 1/1 p012 ALU 012
    mov ebp,[esi+ebp*04h] // 1 2/1 p2 LOAD 1 3/1 p012 AGU 0/1/2
    mov [eax+ecx],ebp // 1 1/2 p0 STORE 1 3/1 p012 AGU 0/1/2
    @4squareSSE2: //
    cvtdq2pd xmm1,xmm3 // 3 10/4 p1 FP_MMX 2 5/2 p5 FMISC
    lea ebp,[esi+ebp*04h] // 2 4/2 p1 ALU 1 1 2/1 p012 AGU 0/1/2
    subpd xmm2,xmm1 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    cvtpd2ps xmm2,xmm2 // 2 11/2 p1 FP_MMX 2 5/2 p5 FMISC
    movaps xmm3,[esp+00h] // 1 7/1 p2 LOAD 2 -/2 FMISC
    movaps xmm1,xmm2 // 1 6/1 p0 MOV 2 2/1 p34 FA/M
    shufps xmm2,xmm2,11000000b // 1 5/2 p1 MMX_SHIFT 3 3/2 p4 FMUL
    shufps xmm1,xmm1,11010101b // 1 5/2 p1 MMX_SHIFT 3 3/2 p4 FMUL
    movaps [esp+10h],xmm2 // 2 7/1 p0 STORE 2 -/2 FMISC
    subps xmm3,xmm2 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    movaps [esp+20h],xmm1 // 2 7/1 p0 STORE 2 -/2 FMISC
    movaps xmm2,[esp+00h] // 1 7/1 p2 LOAD 2 -/2 FMISC
    movaps [esp+30h],xmm3 // 2 7/1 p0 STORE 2 -/2 FMISC
    subps xmm2,xmm1 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    pxor xmm3,xmm3 // 1 3/2 p1 MMX_ALU 2 2/1 p34 FA/M
    movaps [esp+40h],xmm2 // 2 7/1 p0 STORE 2 -/2 FMISC
    @toprowSSE2: //
    movd xmm2,[ebp+00h] // 1 8/1 p2 LOAD 2 -/1 p345 FANY
    movd xmm1,[ebp+04h] // 1 8/1 p2 LOAD 2 -/1 p345 FANY
    punpcklbw xmm2,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    punpcklbw xmm1,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    punpcklwd xmm2,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    punpcklwd xmm1,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    cvtdq2ps xmm2,xmm2 // 1 5/2 p1 FP 2 5/2 p5 FMISC
    cvtdq2ps xmm1,xmm1 // 1 5/2 p1 FP 2 5/2 p5 FMISC
    mulps xmm2,[esp+30h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    mulps xmm1,[esp+10h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    mulps xmm2,[esp+40h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    mulps xmm1,[esp+40h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    addps xmm2,xmm1 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    @leftbottomSSE2: //
    movd xmm1,[ebp+ebx*04h] // 1 8/1 p2 LOAD 2 -/1 p345 FANY
    punpcklbw xmm1,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    punpcklwd xmm1,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    cvtdq2ps xmm1,xmm1 // 1 5/2 p1 FP 2 5/2 p5 FMISC
    mulps xmm1,[esp+30h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    mulps xmm1,[esp+20h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    addps xmm2,xmm1 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    @rightbottomSSE2: //
    movd xmm1,[ebp+ebx*04h+04h] // 1 8/1 p2 LOAD 2 -/1 p345 FANY
    punpcklbw xmm1,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    punpcklwd xmm1,xmm3 // 1 3/2 p1 MMX_SHIFT 2 2/2 p34 FA/M
    cvtdq2ps xmm1,xmm1 // 1 5/2 p1 FP 2 5/2 p5 FMISC
    mulps xmm1,[esp+10h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    mulps xmm1,[esp+20h] // 2 13/2 p1+2 FP_MUL+LOAD 2 4/2 p3 FMUL
    addps xmm2,xmm1 // 1 5/2 p1 FP_ADD 2 4/2 p3 FADD
    @sumSSE2: //
    cvtps2dq xmm2,xmm2 // 1 5/2 p1 FP 2 5/2 p5 FMISC
    packssdw xmm2,xmm2 // 1 5/2 p1 MMX_SHIFT 3 3/2 p34 FA/M
    packuswb xmm2,xmm2 // 1 5/2 p1 MMX_SHIFT 3 3/2 p34 FA/M
    movd [eax+ecx],xmm2 // 2 8/2 p0+1 1 -/1 p5 FMISC
    jmp @destSSE2 // 1 0/1 p0 BRANCH 1 -/2 p012 ALU 0/1/2

    Így színhelyesen ugyan 48 utasítás fut le a korábbi 3 helyett pixelenként (mindezt 3 XMM register-ből megoldva), viszont a korábbi 49M órajel csak 2.5x-ére (120M órajel) nőtt.
    A kis Prescott villantott egyet, SSE2-kódban nehéz (volt) megverni: a K8-on a 128 bites műveletek dekódolása limitált 1/órajelre, mivel mindegyik DirectPath Double (2 uop), míg a P4 22 órajel alatt lekéri az 1 pixelre vonatkozó összes uop-ot a trace cache-ből úgy is, hogy csak 2 órajelenként kap 6-ot.
    Mind a 4 pixelre a színcsatornánkénti int8->int16->int32->single konvertálási utat be kell járni a számításhoz, ezt nagyon jól kezeli a Netburst.

  • P.H.

    senior tag

    Az SSE2 egyetlen IMAC utasítást tartalmaz, 16 bites számokra használható SIMD PMADDWD-t. Mivel ez képeknél bőven elég (hacsak nem akarunk 32767x32767-nél nagyobb méretű képekkel dolgozni), ezért az előző algoritmus minden további nélkül átírható hozzá.
    Azért nem csak mindegy a használata, mivel az összes Pentium 4 generáció sokkal lassabban szoroz a MUL/IMUL párossal (Nortwood: 15 órajel, Prescott: 10 órajel), mint SIMD vagy FP szinten (7-8 órajel). XMM register-ből kinyerni adatot integer register-be (pl. címzéshez) elég lassú metódus (MOVD), viszont még igy is megéri.

    fcom st(2)
    pushad
    mov esi,eax
    fnstsw ax
    fld1
    sub esp,_ARCSTACK
    fld st(2)
    fist dword ptr [esp]
    fpatan
    mov ecx,esp
    fld1
    fxch st(5)
    fstp qword ptr [esp+_ARCCX]
    fld st(2)
    fmul st,st(0)
    fadd st,st(5)
    fsqrt
    sahf
    fdivp st(5),st
    fst qword ptr [ecx+_ALPHACHG]
    fld st(4)
    fst qword ptr [ecx+00h]
    fmul st,st(3)
    fst qword ptr [ecx+08h]
    fxch st(6)
    fstp qword ptr [ecx+_ARCCY]
    fxch st(3)
    fst qword ptr [ecx+_ARCERAD]
    jbe @initARC
    fxch
    @initARC:
    fld st(1)
    fsincos
    mov edi,offset(IDATA-_IDATASTART)
    cmp byte ptr [WDATA+_INSSET+__SSE2],0
    fxch
    mov al,-1
    fmul st,st(4)
    fst qword ptr [ecx+10h]
    fxch st(4)
    fst qword ptr [ecx+_ARCRADIUS]
    fmul
    fst qword ptr [ecx+18h]
    fxch st(2)
    jz @initX87
    nop; nop; nop
    @initSSE2:
    mov edx,[edi+_DX]
    movupd xmm6,[ecx+00h]
    movsd xmm5,[ecx+10h]
    movupd xmm0,[ecx+_ARCCY]
    movapd xmm3,xmm6
    movsd xmm4,[ecx+18h]
    mov [ecx+04h],offset(@arcSSE2)
    shufpd xmm3,xmm6,0001b
    unpcklpd xmm5,xmm4
    movapd xmm7,xmm0
    shl edx,12h
    xorpd xmm3,[SSE2SIGN]
    add edx,04h
    mov ecx,ebp
    movd xmm4,edx
    @arcSSE2:
    addpd xmm0,xmm5
    test al,01h
    fadd st,st(4)
    pshufd xmm1,xmm5,01000100b
    cvtpd2dq xmm0,xmm0
    jz @returnARC
    pshuflw xmm0,xmm0,00100010b
    movd ebp,xmm0
    fcomi st,st(1)
    shufpd xmm5,xmm5,11b
    pmaddwd xmm0,xmm4
    rcl al,01h
    movd edx,xmm0
    mulpd xmm1,xmm3
    mulpd xmm5,xmm6
    movapd xmm0,xmm7
    addpd xmm5,xmm1
    jmp ecx

    @returnARC:
    fninit
    popad
    add esp,_ARCSTACK
    ret

    Prescott Celeronon a váz lefutása ugyanarra a tesztadatra 60000 órajel helyett 52000 (13% gyorsulás), K10.5-ön 33000 órajel helyett 30000 órajel (9% gyorsulás).

  • P.H.

    senior tag

    Egy adott középpontú, adott sugarú körív összes koordinátájának (32 bites registerben 16 bit x + 16 bit y koordináta) és 32 bites képen a pixelek címeinek SSE2 kiszámítása.

    bemenet:

    EBP: az eljárás címe, amit minden koordinátára "meghív"
    EAX: a paraméter, amit átad a meghívott eljárásnak
    ST(0): kiindulási szög
    ST(1): sugár
    ST(2): befejezési szög
    ST(3): a középpont x koordinátája
    ST(4): a középpont y koordinátája

    Az eljárás callback helyett "jumpbank", hívás és visszatérés helyett ugrás történik, az @@ARCSSE2 címre visszaugrással.

    fcom st(2)
    pushad
    mov esi,eax
    fnstsw ax
    fld1
    sub esp,_ARCSTACK
    fld st(2)
    fpatan
    mov ecx,esp
    fld1
    fxch st(5)
    fstp qword ptr [esp+_ARCCX]
    fld st(2)
    fmul st,st(0)
    fadd st,st(5)
    fsqrt
    sahf
    fdivp st(5),st
    fst qword ptr [ecx+_ALPHACHG]
    fld st(4)
    fst qword ptr [ecx+00h]
    fmul st,st(3)
    fst qword ptr [ecx+08h]
    fxch st(6)
    fstp qword ptr [ecx+_ARCCY]
    fxch st(3)
    fst qword ptr [ecx+_ARCERAD]
    jbe @initARC
    fxch
    @initARC:
    fld st(1)
    fsincos
    mov edi,offset(IDATA-_IDATASTART)
    cmp byte ptr [WDATA+_INSSET+__SSE2],0
    fxch
    mov ah,-1
    fmul st,st(4)
    fst qword ptr [ecx+10h]
    fxch st(4)
    fst qword ptr [ecx+_ARCRADIUS]
    fmul
    fst qword ptr [ecx+18h]
    fxch st(2)
    jz @initX87
    @initSSE2:
    movupd xmm6,[ecx+00h]
    movsd xmm5,[ecx+10h]
    movupd xmm0,[ecx+_ARCCY]
    movapd xmm3,xmm6
    movsd xmm4,[ecx+18h]
    mov [ecx+04h],offset(@arcSSE2)
    shufpd xmm3,xmm6,0001b
    unpcklpd xmm5,xmm4
    movapd xmm7,xmm0
    xorpd xmm3,[SSE2SIGN]
    @arcSSE2:
    addpd xmm0,xmm5
    test ah,41h
    fadd st,st(4)
    pshufd xmm1,xmm5,01000100b
    cvtsd2si ebp,xmm0
    mov edx,[edi+_DX]
    jz @returnARC
    unpckhpd xmm0,xmm0
    fcomi st,st(1)
    unpckhpd xmm5,xmm5
    cvtsd2si ecx,xmm0
    lahf
    imul edx,ebp
    shl ebp,10h
    mulpd xmm5,xmm6
    add edx,ecx
    mulpd xmm1,xmm3
    or ebp,ecx
    movapd xmm0,xmm7
    shl edx,02h
    addpd xmm5,xmm1
    jmp dword ptr [esp+_ARCSTACK+_EBP]

    @returnARC:
    fninit
    popad
    add esp,_ARCSTACK
    ret

    A váz időigénye K10.5-ön 340 sugarú körre TSC-vel mérve 33000 órajel, Prescott-on 60000 órajel, ehhez jön még a jumpback eljárás lefutása.
    Az @ARCSSE2 ciklus 22 utasításból áll, a 340 sugarú körön ~2150 lefutás.

    Az eljárás 255000-szer kerül meghívásra különböző középpontokkal és sugarakkal egy-egy futtáskor, így összesen kb. 25 másodpercet igényel nagyon random jumpback-eljárással (ami rá is olvas a képre pixeleire).

  • P.H.

    senior tag

    válasz P.H. #56 üzenetére

    Mindez a gyakorlatban:

    @new:
    mov ecx,00FFFFDFh
    sub esp,DESTINATIONSIZE
    sub ebp,01h
    and ecx,dword ptr [esi+SRC.JOB]
    xor eax,eax
    xor ebx,ebx
    mov [esp+DESTINATION.FIELD1],edi
    mov [esp+DESTINATION.FIELD2],esi
    mov [esp+DESTINATION.FIELD3],eax
    @next: <<<========================================
    mov edx,ecx |
    and cl,0DFh |
    and edx,03h |
    cmp eax,edx |
    rcl eax,01h |
    xor edx,edx |
    neg eax |
    cmp edx,[esp+DESTINATION.FIELD3] |
    rcl edx,01h |
    and eax,edi |
    sub edx,01h |
    and edx,eax |
    xor eax,eax |
    or [esp+DESTINATION.FIELD3],edx |
    sub eax,esi |
    @same: <<<=============================== |
    mov [esi+SRC.FIELD2],bp | |
    mov edx,dword ptr [esi+SRCSIZE+SRC.FIELD1] | |
    add esi,SRCSIZE | |
    and edx,00FFFFDFh | |
    xor edx,ecx | |
    jz @same =================================| |
    or dl,cl | |
    jz @same ================================= |
    add eax,esi |
    mov dl,00h |
    cmp eax,60*x*SRCSIZE |
    rcl cl,01h |
    imul eax,xxx |
    cmp cl,01h |
    rcl dl,01h |
    and cl,(00000011b shl 1) |
    add edi,eax |
    xor eax,eax |
    cmp cl,01h |
    rcl eax,01h |
    mov cl,[esi+SRC.FIELD1] |
    neg eax |
    and ebx,eax |
    not eax |
    and eax,edi |
    or ebx,eax |
    xor eax,eax |
    test edx,edx |
    jz @next =======================================
    mov [esp+DESTINATION.FIELD5],edi
    cmp dword ptr [esi+SRC.FIELD1],-1
    mov [esp+DESTINATION.FIELD4],ebx
    jnz @new

  • P.H.

    senior tag

    Netburst integer optimization:

    - 2 órajelenként 6 uop küldhető a Trace Cache-ből a végrehajtó egységekhez: ezt a 6 uop-ot kell a lehető legtöbb valós x86 utasításnak megfeleltetni: olyan utasításokat kell alkalmazni, amelyek 1 uop-ot generálnak. Így sem éri el a PIII szintjét sem az "utasításdekódolás" sebessége, de 1-nél magasabb uop/utasítás átlagnal nagyon esik a végrehajtás sebessége.

    - ugrásmentesíteni kell mindent, amit lehet: nem csak a ciklusokat, hanem a köztük levő IF-ELSE elágazokat is, akkor is, ha ez sokkal több utasítás árán kivitelezhető; csak így lehet minimalizásni a 128 elemű (OoO-előrelátást biztosító) ROB törlésének számát.

    - az ugrásmentesítéshez nem lehet használni az ADC/SBB (3-4+microcode uop, 6-10 órajel), SETcc (3 uop, 5-9 órajel) , CMOVcc (3 uop, 6-9.5 órajel) utasításokat, túl sok uop-ot (és akár microcode-kérést is) generálnak, hanem:

    - az EFLAGS-hez csakis RCL reg,1 utastással szabad hozzáférni, mert a Carry Flag-et ezzel Northwood-on (4 órajel) és Prescott-on is (7 órajel) 1 uop-pal lehet előzőleg nullázott register-be írni:
    xor reg,reg // clear register
    cmp xxx, 1 // compare values
    rcl reg,1 // reg <- (xxx = 0) : 1 ? 0

    xor reg,reg // clear register
    cmp xxx, yyy // compare values
    rcl reg,1 // reg <- (xxx < yyy) : 1 ? 0

    Ezekből egy neg vagy sub utasítással lehet FFFFFFFFh vagy 00000000h and-maskot létrehozni a további feldolgozáshoz.

    - Minden memóriaírási írási művelet legalább L2 írási késleltéssel történik, mivel az L1D write-through, a módosítás »azonnal« megjelenik az L2-ben is (nincs olyan egység, ami kiszűri az azonos 64 byte-os L1D cache-line többszöri írását; ); azaz azonos adat sokszori felülírásának esélyénél érdemes tesztelni, hogy az adott terület nem tartalmazza-e már az kiírandó értéket.
    Ha egy aligned 64 byte-os tartományt byte-onként írunk, akkor 64x fog kikerülni az L2-be, így érdemes a lehető legnagyobb méretben írni.

    - LEA utasítások kerülendők, hacsak nem LEA reg, [reg+reg] vagy LEA reg,[reg+imm] formájúak; de inkább alkalmazandóak, mint:

    - Az MUL/IMUL egész szorzások (valami x 6 érték pl.): Northwood esetén 15, Prescott esetén 10 órajelbe kerülnek ... FP-szorzás 6-8 órajel.

  • P.H.

    senior tag

    How to write 3.0 IPC code on AMD K10, avagy mit rejtenek a micro-arch leírásokban az "egyéb IPC-növelő módosítások".

    A példakód (nem átfedő) memóriamásolás, ennek okáról később. A kiindulási kód:
    // ESI: forráscím
    // EDI: célcím
    // ECX: a memória mérete byte-ban
    sub ecx,04h
    @copy:
    mov eax,[esi+ecx]
    mov [edi+ecx],eax
    sub ecx,04h
    jns @copy

    Maximális IPC-t kizárólag akkor érhetünk el, ha csak az L1D-ben dolgozunk, ez nem kérdés. Ezt vagy azzal érhetjük el, hogy kellően kicsi a munkaterület, vagy a prefetch-re hagyatkozunk.

    Ugyancsak akkor elérhető az elméleti maximum, ha csak egyszerű utasítások vagy double (itt már fontos az utasítássorrend: 1 double - 1 egyszerű - 1 double - 1 egyszerű a minta) vannak a ciklusban, semmi microcode.

    Lemérve a kód K10-en 2.0 IPC. Olyan ciklusokban, ahol a következő lefutás minimálisan függ az előző eredményétől (számolt - for - ciklus), a retirementen mért IPC megegyezik az órajelenként elindított utasítások átlagával. A K10 képes órajelenként 2 load és 1 store utasításra, itt 1 load + 1 store van, miért mégis épp 2.0 az IPC? Azaz miért 2 byte/cycle a másolás sebessége?
    Igen súlyos decode bottleneck van jelen: egy 3 utasítás széles microrch órajelenként 3 szekvenciális utasítást tud küldeni végrehajtásra, ezért az 1. órajelben a load+store+sub kerül küldésre, a 2. órajelben önmagában a js ugrás... és más semmi, ezzel párhuzamosan az elágazásbecslés átirányítja a végrehajtást a ciklus elejére, azaz a 3. órajelben megint a load+store+sub triót dekódolja a CPU, a 4. órajelben megint a js ugrást magában, és így tovább. Általánosságban: a rövid ciklusoknak mindig 3-mal oszható számú utasításból kell állnia , különben az elméletileg elérhető maximális IPC csökken (bármely 4 utasításos ciklusnál (3+1)/2 = 2.0 IPC-re).
    Ha 4 utasításra szélesítjük a felépítést, akkor a fenti gond elfelejthető, az Intel a Core2-től kezdve nem véletlenül alkalmazza ezt (és érdemes végiggondolni, hogy a 4-ről 5-re szélesítés mennyivel kevesebb kézzelfogható előnnyel járna a befektetett bonyolultsághoz képest).

    Meg kell tehát próbálni +2 hasznos utasítást belepasszírozni a ciklusba, amitől nő a teljesítőképessége. Ha pl. ilyenre írjuk át, akkor nem fog nőni, ugyanúgy 4 byte/2 órajel lesz, hiába értük el a 3.0 IPC mostmár:
    sub ecx,04h
    add esi,ecx
    add edi,ecx
    @copy:
    mov eax,[esi]
    sub esi,04h
    mov [edi],eax
    sub edi,04h
    sub ecx,04h
    jns @copy

    Viszont írjuk át erre:
    sub ecx,04h
    and ecx,-8
    @copy:
    mov eax,[esi+ecx]
    mov [edi+ecx],eax
    mov eax,[esi+ecx+04h]
    mov [edi+ecx+04h],eax
    sub ecx,08h
    jns @copy

    1. órajelben a load+store+load kerül dekódolásra, a 2. órajelben a store+sub+js. Ugyancsak 3.0 IPC-nél vagyunk, viszont megnőtt a teljesítmény 8 byte/2 órajelre, duplájára.
    Elvileg, mert gyakorlatilag megintcsak 2.0 IPC-t mérünk...

    Ennek okáért tovább kell lapozni az opt. manualban, de még maradunk a decode-nál: a K10 aligned 32 byte-os csomagokat olvas be az L1I-ből: abban az esetben, ha az utolsó utasítás átlóg a következő 32 byte-os csomagban, akkor a decode 1 órajel késleltetést szenved el. A fenti ciklus 3+3+4+4+3+2 = 19 byte hosszú. Bármit teszünk a kóddal, akárhogy egyszerűsítjük az utasításokat, legalább 17 byte-os lesz a ciklus.
    Ha a kódot nem pad-oltuk vagy nem oly módon, hogy teljesen beleférjen egy aligned 32 byte-os csomagba, akkor a dekódolás 2 helyett 3 órajelet vesz igénybe, azaz a 6 utasítás 3 órajel alatt kerül le a végrehajtó egységekhez, azaz 2.0 az elméleti maximális IPC-nk megint. Ez akár 16 byte-nál nagyobb pad-ot is jelent egy-egy ciklus előtt.
    A Core2-ben egy 64 byte-os, utasításokat tartalmazó Loop Stream Detector-t alkalmaztak ezen jelenség megszüntetésére, a Nehalemben már dekódolt micro-opokat tartalmaz ugyanez az egység (ezzel onnantól megszűnik a 4-1-1-1 fused micro-op/cycle decode-megkötés is, de ez most itt nem fontos), Sandy Bridge-ben pedig nagyméretű micro-op cache van.
    Mivel a K7/K8, a P3 és a PentiumM felépítés aligned 16 byte-os csomagokat olvas az L1I cache-ből, és a fenti(vel akármilyen egyenértékű) kód legalább 17 byte-os, ezért ezeken nagyon beszűkült azon algoritmusok köre, amelyek kihasználhatják az elméleti maximális 3.0 IPC végrehajtást: mindenképp bele kell férnie a ciklusnak 16 byte-be és 3 többszöröse egyszerű utasítást kell tartalmazzon; tehát a K10-nél a 32 byte-ra növelt L1I-betöltés kifejezetten ezt az IPC-növelési célt szolgálta (mindemellett csökkentette az is L1I-hozzáférések számát, azaz egy kezdetleges LSD-nek is felfoghatjuk).

    Ha padding-gel megfelelően elhelyezzük a kódot, akkor K10-en a következő eredményt kapjuk:

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Retired instructions
    Counter 2 : Instructions per cycle (IPC)
    Counter 3 : L1 Data cache accesses
    50 2593.7 7746.2 3.0 5169.7
    100 2564.7 7616.0 3.0 5079.9
    150 2580.3 7673.6 3.0 5119.1
    200 2571.2 7631.9 3.0 5090.3
    250 2571.0 7649.8 3.0 5103.2
    300 2571.0 7649.8 3.0 5103.2
    350 2595.4 7751.0 3.0 5172.8
    400 2583.2 7687.8 3.0 5128.5
    450 2578.5 7671.7 3.0 5117.8
    500 2582.9 7685.7 3.0 5127.1
    550 2582.9 7685.7 3.0 5127.1
    600 2598.1 7759.2 3.0 5178.3
    650 2581.1 7681.4 3.0 5124.2
    700 2587.1 7699.6 3.0 5136.3
    750 2582.4 7685.6 3.0 5127.0
    800 2582.4 7685.6 3.0 5127.0
    850 2596.6 7754.7 3.0 5175.3
    900 2528.1 7516.7 3.0 5014.3
    950 2570.9 7640.2 3.0 5096.8
    1000 2584.0 7689.7 3.0 5129.7
    1050 2579.8 7677.3 3.0 5121.5
    1100 2579.8 7677.3 3.0 5121.5
    1150 2596.5 7754.4 3.0 5175.1
    1200 2575.8 7665.4 3.0 5113.5
    1250 2576.7 7664.7 3.0 5113.1
    1300 2584.2 7691.2 3.0 5130.8
    1350 2584.2 7691.2 3.0 5130.8
    1400 2600.4 7765.7 3.0 5182.6
    1450 2581.1 7680.9 3.0 5123.9
    1500 2586.0 7696.8 3.0 5134.5
    1550 2579.2 7676.2 3.0 5120.7
    1600 2579.2 7676.2 3.0 5120.7
    1650 2596.0 7751.1 3.0 5172.8
    1700 2586.1 7698.7 3.0 5135.9
    1750 2434.3 7218.5 3.0 4815.4
    1800 2575.1 7652.8 3.0 5105.2
    1850 2574.7 7659.2 3.0 5109.5
    1900 2574.7 7659.2 3.0 5109.5
    1950 2597.0 7755.8 3.0 5176.1
    2000 2584.3 7690.7 3.0 5130.4

    Ha a forrás és a cél memóriaterület címe 8- vagy 16-aligned, akkor alkalmazható MMX (MOVQ) vagy SSE (MOVAPS) utasítás is memóriahozzáférésre, így 8 vagy 16 byte/órajel sebesség érhető el, de ezzel még tovább nő a ciklus mérete, így még kényesebb a pad-olásra.

    Igen, a fenti sima x86 ciklusban is legfejlebb 8 byte-tal többet másolunk, mint amennyi valójában a megadott méret, ezért elsősorban dinamikusan allokált memóriára alkalmazható, a stack-ből/-be másolás körülményesebb: a saját megírt memóriafoglaló eljárásunkban viszont lehetőség van minden esetben +8 dummy byte-ot foglalni; illetve akkor már 8, 16 vagy 32 byte-ra is igazítani a lefoglalt tömb címét bármely OS alatt.

  • P.H.

    senior tag

    Igencsak amatőr, soha többé el nem követendő hiba: a bt dword ptr [mem32],imm utasítás a a megadott címtől kezdve olvas be négy byte-ot, semmi esetre sem a befoglaló aligned 32 bitet.

    Azaz tilos vele byte-ot címezni: pl. egy 32 bites szám előjelének Carry Flag-be másolásához a bt dword ptr [mem32+03h],07h helyett csakis a bt dword ptr [mem32],1Fh alkalmazható. Az előbbi akár 0.2-0-3 IPC-vel is visszavetheti tömör kód végrehajtását (a cachevonal-határ keresztezésekből adódó dupla L1-olvasások miatt).

  • P.H.

    senior tag

    Kissé módosítva: a verembeli változókat a hívó algoritmus kezeli/tölti fel, és némi dummy store-ral a kód is egyen(let)esebb.

    lea edx,[ebp+ebp*02h-04h]
    xor ecx,ecx
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    mov [ebx+edx],ecx
    sub edx,04h
    jns @mark0
    mov byte ptr [edi+00h],01h
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add eax,04h
    add ecx,04h
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    add eax,04h
    sub ecx,04h
    jnz @subrow
    add ebx,04h
    jnz @rowmin
    jmp @@RECUDE_COLUMNS
    @specific:
    cmp byte ptr [edi+edx],00h
    mov byte ptr [edi+edx],01h
    jnz @@ABNORMAL_EXIT
    add ecx,ebx
    sub dword ptr [esp+__SYS0],04h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp esi,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp [eax+03h],dl
    cmovz edx,esi
    sub [eax],edx
    jnz @subcol
    mov dl,[edi+ecx+02h]
    or dl,[edi+ebx]
    mov edx,ecx
    jnz @subcol
    mov byte ptr [edi+ebx],01h
    sub edx,ebp
    mov byte ptr [edi+ecx+02h],01h
    sub dword ptr [esp+__SYS0],04h
    mov [edi+edx*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@ABNORMAL_EXIT:
    mov ebx,[esp+__MARKS]
    stc
    ret

    @@2ND_STEP:
    xor ebx,ebx
    xor edx,edx
    xor eax,eax
    @@3RD_STEP:
    mov byte ptr [edi+ebx],0FFh
    xor ebx,ebx
    mov byte ptr [edi+edx],00h
    mov edx,00FFFFFFh
    mov [edi+eax*02h+__COLON],ecx
    lea ecx,[ebp-04h]
    @chk2mtx:
    mov esi,eax
    sub eax,ebp
    sub ebx,ebp
    imul eax,ebx
    add ebx,ecx
    test esi,esi
    lea eax,[eax+ebx]
    cmovns eax,esi
    mov esi,[esp+__MTX]
    @check2col:
    add ecx,04h
    jz @@5TH_STEP
    cmp byte ptr [edi+ecx],00h
    jnz @check2col
    add esi,ecx
    sal ecx,08h
    mov ebx,ebp
    @zeroincol:
    sub esi,ebp
    mov cl,[edi+ebx+03h]
    cmp edx,[esi]
    sbb cl,00h
    cmovz edx,[esi]
    cmovz eax,ebx
    add ebx,04h
    jnz @zeroincol
    sar ecx,08h
    test edx,edx
    jnz @chk2mtx
    lea ebx,[eax+03h]
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    sub edx,ebp
    jmp @newstar
    @@5TH_STEP:
    lea ebx,[ebp+03h]
    mov [esp+__FREE0],eax
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx-03h]
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add esi,04h
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    js @nx5row
    mov eax,[esp+__FREE0]
    xor edx,edx
    sub ecx,ebp
    div ecx
    lea ecx,[edx+ebp]
    xor edx,edx
    lea ebx,[ebp+eax+03h]
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    sub edx,ebp
    jmp @newstar
    @0_star:
    mov [edi+ebx*02h+__0STAR],ecx
    mov ecx,[edi+eax*02h+__COLON]
    @newstar:
    mov ebx,eax
    lea eax,[edx-04h]
    @starincol:
    cmp [edi+eax*02h+__0STAR],ecx
    jz @0_star
    sub eax,04h
    jns @starincol
    mov [edi+ebx*02h+__0STAR],ecx
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],04h
    lea ebx,[edi+__0STAR]
    mov ecx,ebp
    jz @count_result_STACK
    @restructure:
    mov esi,[ebx]
    mov byte ptr [edi+ecx+03h],00h
    add ebx,08h
    mov byte ptr [edi+esi],01h
    add ecx,04h
    jnz @restructure
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    mov esi,[esp+__SAVE]
    xor eax,eax
    mov ebx,[esp+__MARKS]
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Naívan feltételeztem, hogy itt a

    "Sandy Bridge also improves performance for certain security primitives, such as the microcoded AES instructions that were added with Westmere and large number arithmetic. Sandy Bridge improves SHLD (shift left double) performance, which is used for SHA-1 hashing. The throughput for ADC (add with carry) doubled, which is used for large number routines calculations such as RSA."

    félmondat azt jelenti, hogy a Physical Register File (Netburst utáni) újraélesztésével az Intel a Sandy Bridge-nél szakít a végre a (Pentium Pro óta létező) 2-forrás/uop megkötéssel, kiterjesztik 3-forrásúra őket. Sajnos nem így történt, ráadásul az összes ilyen jellegű utasításnál (ADC, SBB, SETcc, CMOVcc) majdnem ugyanúgy szenved, mint a Core2, már a decode-ot is limitálva (akár órajelenként 1 utasításra).

    "Use the SETCC and CMOV instructions to eliminate unpredictable conditional branches where possible. Do not do this for predictable branches. Do not use these instructions to eliminate all unpredictable conditional branches (because using these instructions will incur execution overhead due to the requirement for executing both paths of a conditional branch). In addition, converting a conditional branch to SETCC or CMOV trades off control flow dependence for data dependence and restricts the capability of the out-of-order engine. When tuning, note that all Intel 64 and IA-32 processors usually have very high branch prediction rates. Consistently mispredicted branches are generally rare. Use these instructions only if the increase in computation time is less than the expected cost of a mispredicted branch."

    "Software should follow these additional decoder guidelines:
    • If you need to use multiple μop, non-microsequenced instructions, try to separate by a few single μop instructions. The following instructions are examples of multiple-μop instruction not requiring micro-sequencer:
    - ADC/SBB
    - CMOVcc
    - Read-modify-write instructions
    • If a series of multiple-μop instructions cannot be separated, try breaking the series into a different equivalent instruction sequence. For example, a series of read-modify-write instructions may go faster if sequenced as a series of readmodify + store instructions. This strategy could improve performance even if the new code sequence is larger than the original one."

    A megelőző kód (63 mátrix/ezredmásodperc @ 2640 MHz) AMD-s teljesítménye ellen mutatott gyenge Intel (44 mátrix/ezredmásodperc @ 2500 MHz Core2; korábbi, még "ugrálós" kódnál ez 55 mátrix/ezredmásodperc volt) hátterében egyértelműen ez áll; és ez a Sandy Bridge-dzsel sem fog alapvetően változni (bár sokat segíthet az add/sub-macrofusion és a decode-limitet eltörlő uop-cache).
    Ilyen kódoknál felértékelődik az AMD (remélhetőleg a jövőben is megtartott) "single-cycle execution" integer-felépítése.

  • P.H.

    senior tag

    mov eax,edi
    pushad
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    mov byte ptr [edi+00h],01h
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add eax,04h
    add ecx,04h
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    add eax,04h
    sub ecx,04h
    jnz @subrow
    add ebx,04h
    jnz @rowmin
    jmp @@RECUDE_COLUMNS
    @specific:
    cmp byte ptr [edi+edx],00h
    mov byte ptr [edi+edx],01h
    jnz @@ABNORMAL_EXIT
    add ecx,ebx
    sub dword ptr [esp+__SYS0],04h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp esi,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp [eax+03h],dl
    cmovz edx,esi
    sub [eax],edx
    jnz @subcol
    mov dl,[edi+ecx+02h]
    or dl,[edi+ebx]
    mov edx,ecx
    jnz @subcol
    mov byte ptr [edi+ebx],01h
    sub edx,ebp
    mov byte ptr [edi+ecx+02h],01h
    sub dword ptr [esp+__SYS0],04h
    mov [edi+edx*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret

    @@3RD_STEP:
    mov byte ptr [edi+ebx],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    lea ecx,[ebp-04h]
    xor ebx,ebx
    mov edx,00FFFFFFh
    @chk2mtx:
    mov esi,eax
    sub eax,ebp
    sub ebx,ebp
    imul eax,ebx
    add ebx,ecx
    test esi,esi
    lea eax,[eax+ebx]
    cmovns eax,esi
    mov esi,[esp+__MTX]
    @check2col:
    add ecx,04h
    jz @@5TH_STEP
    cmp byte ptr [edi+ecx],00h
    jnz @check2col
    add esi,ecx
    sal ecx,08h
    mov ebx,ebp
    @zeroincol:
    sub esi,ebp
    mov cl,[edi+ebx+03h]
    cmp edx,[esi]
    sbb cl,00h
    cmovz edx,[esi]
    cmovz eax,ebx
    add ebx,04h
    jnz @zeroincol
    sar ecx,08h
    test edx,edx
    jnz @chk2mtx
    lea ebx,[eax+03h]
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    sub edx,ebp
    jmp @newstar
    @@5TH_STEP:
    lea ebx,[ebp+03h]
    mov [esp+__FREE0],eax
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx-03h]
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add esi,04h
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    js @nx5row
    mov eax,[esp+__FREE0]
    xor edx,edx
    sub ecx,ebp
    div ecx
    lea ecx,[edx+ebp]
    xor edx,edx
    lea ebx,[ebp+eax+03h]
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    sub edx,ebp
    jmp @newstar
    @0_star:
    mov [edi+ebx*02h+__0STAR],ecx
    mov ecx,[edi+eax*02h+__COLON]
    @newstar:
    mov ebx,eax
    lea eax,[edx-04h]
    @starincol:
    cmp [edi+eax*02h+__0STAR],ecx
    jz @0_star
    sub eax,04h
    jns @starincol
    mov [edi+ebx*02h+__0STAR],ecx
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],04h
    mov ebx,edi
    mov ecx,ebp
    jz @count_result_STACK
    @restructure:
    mov esi,[ebx+__0STAR]
    mov byte ptr [edi+ecx+03h],00h
    add ebx,08h
    mov byte ptr [edi+esi],01h
    add ecx,04h
    jnz @restructure
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Két kódrészt az utolsó kódból - ellátva a megfelelő code-padding-gal - lemértem, a következők adódtak:

    2ND_STEP: 2.0 IPC
    @@2ND_STEP:
    lea ecx,[ebp-04h]
    mov edx,00FFFFFFh
    jmp @c2col
    @zeroincol:
    cmp edx,[esi]
    mov bl,[edi+eax+03h]
    sbb bl,00h
    jz @@DECIDE_NEXT_STEP
    @nx2mtx:
    sub esi,ebp
    add eax,04h
    jnz @zeroincol
    @c2col:
    mov esi,ecx
    add esi,[esp+__MTX]
    sub esi,ebp
    @check2col:
    add esi,04h
    add ecx,04h
    jz @@5TH_STEP
    cmp byte ptr [edi+ecx],00h
    mov eax,ebp
    jnz @check2col
    jmp @zeroincol

    5TH_STEP: 2.7 IPC
    @@5TH_STEP:
    lea ebx,[ebp+03h]
    mov esi,[esp+__MTX]
    @nx5row:
    mov eax,[edi+ebx-03h]
    sub ecx,edx
    xor eax,edx
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add esi,04h
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    js @nx5row

    Az elsőben elég gyakoriak az (ki)ugrások, a második szinte folyamatos lefutású (mátrixsoronként 1 elágazás-tévesztés van csak)
    K10.5-ön mérve:
    - az overall IPC 2.4 (nem végtelen ciklusban, ezért az tartalmazza a hívó algoritmus kb. 3x ekkora kódját is), ami 80% kihasználtsága a lehetséges maximumnak
    - a @@2ND_STEP 2.0 IPC, ami 66%-os kihasználtság
    - a @@5TH_STEP 2.7 IPC, ez 90% kihasználtság
    (Vajon ezeket az értékeket mennyiben befolyásolja, hogy a @@2ND_STEP sszámolós ciklusa 7 utasításos, a @@5TH:STEP-é pedig 9, ami passzol a K10.5 3 pipe-jához?)

    A @@2ND_STEP-en lehetne javítani, de ahhoz még +1 32 bites regiszter kellene, az meg nincs; 64 biten lesz :)

  • P.H.

    senior tag

    Küzdök a 2 GB/32-bit thread kihasználásával régóta: pár KB-énti (egyszerre 1 struktúra) lefoglalással lassú az algoritmus (16 GB memória mellett, x64 OS alatt is), 1000-3000 db struktúra egyszerre lefoglalása esetén 1.0-1.1 GB-ig lehet elmennem (XP x64 alatt), aztán annyira menthetetlenül defragmentálódik a címtér, hogy nem lehet több ilyet egyben lefoglalni. Vajon ezen javítottak Vista/Win7 alatt?

    Megoldás lehet:
    - unlock-olt (movable) memóriafoglalás, de ennek túl sok költsége lesz minden hozzáféréskor lockolni (és az algoritmus olyan, hogy nem is lehet előre kiszámolni, hogy mit lehet lockolni egyszerre, tehát lock/unlock kellene elemenként)
    - külön x64 process-re átírni a programrészt, de ennek felhasználhatósága korlátozott, és nem is elegáns
    - egyre csökkenő struktúranagyságú memóriát lefoglalni egyszerre

    Valószínűleg a legutolsó az általánosan célravezető. Meglátjuk.

  • P.H.

    senior tag

    Macro-op fusion

    The Sandy Bridge can fuse two instructions into one µop in more cases than previous processors can [...].

    The decoders will fuse an arithmetic or logic instruction and a subsequent conditional jump instruction into a single compute-and-branch µop in certain cases. The compute-and-branch µop is not split in two at the execution units but executed as a single µop by the branch unit at execution port 5.
    The CMP, ADD and SUB instructions can fuse with signed and unsigned branch instructions. INC and DEC can fuse with signed branch instructions, and TEST and AND instructions can fuse with all branch instructions (including useless combinations), [...]
    The first instruction can have an immediate operand or a memory source operand, but not both. It cannot have memory destination operand.

    Megcsillagoztam azokat az utasításpárokat, amelyek elméletileg egysíthetők, nem véve figyelembe a szükséges 3 utasításos teret köztük (egyrészt az elágazás-tévesztések miatt, másrészt nem nagyon lehet előre kiszámolni, mi tartozik decode-nál ugyanabba a 4-es utasításcsoportba):

    The programmer should keep fuseable arithmetic instructions together with a subsequent conditional jump rather than scheduling other instructions in-between; and there should preferably be at least three other instructions between one fuseable pair and the next fuseable pair in order to take advantage of macro-op fusion.

    Az ADD és SUB bevonása a Sandy Bridge-nél a macro-op fusion-be igen hatékony lépés volt az Intel-től.

    mov eax,edi
    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    mov byte ptr [edi+00h],01h
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add eax,04h
    * add ecx,04h
    * jnz @findrowmin
    sub ecx,ebp
    * cmp esi,02000000h
    * jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    add eax,04h
    * sub ecx,04h
    * jnz @subrow
    * add ebx,04h
    * jnz @rowmin
    jmp @columns
    @specific:
    cmp byte ptr [edi+edx],00h
    mov byte ptr [edi+edx],01h
    jnz @@ABNORMAL_EXIT
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    * add ebx,04h
    * jnz @rowmin
    @columns:
    mov [edi+00h],bl
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    * cmp ebx,ebp
    * jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    * add ecx,04h
    * jnz @findcolmin
    cmp esi,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    * add ecx,04h
    * jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp [eax+03h],dl
    cmovz edx,esi
    * sub [eax],edx
    * jnz @subcol
    mov dl,[edi+ecx+02h]
    mov byte ptr [edi+ecx+02h],01h
    or dl,[edi+ebx]
    mov edx,ecx
    jnz @subcol
    mov byte ptr [edi+ebx],01h
    sub edx,ebp
    mov byte ptr [edi+ecx+02h],01h
    sub dword ptr [esp+__SYS0],01h
    mov [edi+edx*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret

    @@3RD_STEP:
    mov byte ptr [edi+ebx+03h],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    lea ecx,[ebp-04h]
    mov edx,00FFFFFFh
    jmp @c2col
    @zeroincol:
    cmp edx,[esi]
    mov bl,[edi+eax+03h]
    sbb bl,00h
    jz @@DECIDE_NEXT_STEP
    @nx2mtx:
    sub esi,ebp
    * add eax,04h
    * jnz @zeroincol
    @c2col:
    mov esi,ecx
    add esi,[esp+__MTX]
    sub esi,ebp
    @check2col:
    add esi,04h
    * add ecx,04h
    * jz @@5TH_STEP
    cmp byte ptr [edi+ecx],00h
    mov eax,ebp
    jnz @check2col
    jmp @zeroincol
    @@5TH_STEP:
    lea ebx,[ebp+03h]
    mov esi,[esp+__MTX]
    @nx5row:
    mov eax,[edi+ebx-03h]
    sub ecx,edx
    xor eax,edx
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add esi,04h
    * add ecx,04h
    * jnz @decrease_row_free
    * add ebx,04h
    * js @nx5row
    mov eax,[esp+__FREE0]
    xor edx,edx
    mov esi,eax
    sub eax,[esp+__MTX]
    idiv ebp
    neg eax
    lea ecx,[ebp+edx]
    lea eax,[ebp+eax*04h]
    @@DECIDE_NEXT_STEP:
    xor edx,edx
    mov [esp+__FREE0],esi
    * add edx,[esi]
    * jnz @nx2mtx
    mov ebx,eax
    sub eax,ebp
    * add edx,[edi+eax*02h+__0STAR]
    * jnz @@3RD_STEP
    @@4TH_STEP:
    sub edx,ebp
    jmp @newstar
    @0_star:
    mov [edi+ebx*02h+__0STAR],ecx
    mov ecx,[edi+eax*02h+__COLON]
    @newstar:
    mov ebx,eax
    lea eax,[edx-04h]
    @starincol:
    * cmp [edi+eax*02h+__0STAR],ecx
    * jz @0_star
    * sub eax,04h
    * jns @starincol
    mov [edi+ebx*02h+__0STAR],ecx
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    mov ebx,edi
    mov ecx,ebp
    jz @count_result_STACK
    mov edx,[edi]
    @restructure:
    mov esi,[ebx+__0STAR]
    mov byte ptr [edi+ecx+03h],00h
    add ebx,08h
    mov byte ptr [edi+esi],01h
    * add ecx,04h
    * jnz @restructure
    mov [edi],edx
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    válasz P.H. #46 üzenetére

    Némi módosítással mostmár az elvárható szintet hozza a kód, folyamatosan tartja a 2.4 IPC-t.

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Retired instructions
    Counter 2 : Instructions per cycle (IPC)
    Counter 3 : L1 Data cache refill from RAM

    1000 2602.3 6239.3 2.4 0.0
    1050 2625.0 6279.9 2.4 0.0
    1100 2622.7 6217.2 2.4 0.0
    1150 2624.9 6212.2 2.4 0.0
    1200 2607.5 6200.2 2.4 0.1
    1250 2626.4 6246.8 2.4 0.0
    1300 2621.9 6223.3 2.4 0.0
    1350 2625.4 6207.1 2.4 0.0
    1400 2607.3 6176.2 2.4 0.1
    1450 2624.8 6223.7 2.4 0.1
    1500 2593.0 6160.8 2.4 0.1
    1550 2625.6 6257.4 2.4 0.1
    1600 2610.2 6214.2 2.4 0.0
    1650 2621.0 6224.5 2.4 0.1
    1700 2621.6 6254.4 2.4 0.0
    1750 2624.4 6201.1 2.4 0.0
    1800 2610.4 6156.3 2.4 0.0
    1850 2625.9 6208.6 2.4 0.0
    1900 2622.2 6224.9 2.4 0.0
    1950 2626.3 6263.7 2.4 0.0
    2000 2610.2 6255.1 2.4 0.1
    2050 2625.3 6284.7 2.4 0.0
    2100 2618.1 6281.4 2.4 0.0
    2150 2601.0 6225.6 2.4 0.1
    2200 2620.6 6289.6 2.4 0.1

    Mivel korábban nem vettem figyelembe, hogy bár a LEA utasítás K10-en és Core2/Nehalem/Sandy Bridge-en 1 órajel, viszont K7/K8-on 2 órajel, Atom-on 4, Prescott-on 2.5, így ezeken nagyon nem egyenértékű a sima összeadással, ezért kivettem a felesleges LEA utasításokat; Prescott-on 10%-kal gyorsult.
    Ennek további hozadéka, hogy mivel a Sandy Bridge már az ADD/SUB + Jcc párokat is tudja egyesíteni (macro-fusion), az Atom szintén tudja párosítani ezeket (én pedig korábban minden ilyen pár közé tettem a LEA utasításokat, mert nem szeretem az egymást közvetlenül követő függő integer-kódokat), ezért szinte minden ciklus profitál ebből mindkettőn.

    Érdekes lesz a Bulldozer, mivel ahhoz, hogy ez a kód 2.4 IPC felett tudjon futni, a következők kellenek:
    1. 3 ALU
    2. legalább 2 load/cycle/thread (pl. a @@5ST_STEP 9 utasításos ciklusában 3 load, 1 load+store, 1 ugrás és 4 regiszter-utasítás van)
    3. CMOVcc, ADC és SBB utasítások végrehajtása 1 órajel alatt
    3. a cikluszáró ADD+Jcc párosok fúziója igencsak gyorsít (szinte minden ciklus így zárul)
    4. a teljes kód elfér egy pár 100 elemű uop cache-ben

    Jelen pillanatban úgy tudni, az első kettővel a Sandy Bridge és a K7-K10 sorozat rendelkezik, a harmadikkal csak a K7-K10, az utolsó 2 pedig a Sandy Bridge sajátja.
    (Elvileg a kód az első 754/939 K8-as generációkon gyorsabb is, mint K10-en, mivel akkor az L1-latency csak 2 órajel volt.)
    A Bulldozer 1. generációjában az első kettő kizárt, a 3. szinte biztos, az utolsó kettő lehetséges, de az eddigi információk nem említik őket. Persze ha a maximum 2.0 IPC/thread megfelelő órajellel párosul, akkor nem lehet gond.

    mov eax,edi
    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    mov byte ptr [edi+00h],01h
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add eax,04h
    add ecx,04h
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    add eax,04h
    sub ecx,04h
    jnz @subrow
    add ebx,04h
    jnz @rowmin
    jmp @columns
    @specific:
    cmp byte ptr [edi+edx],00h
    mov byte ptr [edi+edx],01h
    jnz @@ABNORMAL_EXIT
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    add ebx,04h
    jnz @rowmin
    @columns:
    mov [edi+00h],bl
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp esi,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp [eax+03h],dl
    cmovz edx,esi
    sub [eax],edx
    jnz @subcol
    mov dl,[edi+ecx+02h]
    or dl,[edi+ebx]
    mov edx,ecx
    jnz @subcol
    mov byte ptr [edi+ebx],01h
    sub edx,ebp
    mov byte ptr [edi+ecx+02h],01h
    sub dword ptr [esp+__SYS0],01h
    mov [edi+edx*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret

    { CODE PADDING }

    @@3RD_STEP:
    mov byte ptr [edi+ebx+03h],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    {0} lea ecx,[ebp-04h]
    {1} mov edx,00FFFFFFh
    {2} jmp @c2col
    @zeroincol:
    {0} cmp edx,[esi]
    {1} mov bl,[edi+eax+03h]
    {2} sbb bl,00h
    {0} jz @@DECIDE_NEXT_STEP
    @nx2mtx:
    {1} sub esi,ebp
    {2} add eax,04h
    {0} jnz @zeroincol
    @c2col:
    {0} mov esi,ecx
    {1} add esi,[esp+__MTX]
    {2} sub esi,ebp
    @check2col:
    {0} add esi,04h
    {1} add ecx,04h
    {2} jz @@5TH_STEP
    {0} cmp byte ptr [edi+ecx],00h
    {1} mov eax,ebp
    {2} jnz @check2col
    {0} jmp @zeroincol
    @@5TH_STEP:
    lea ebx,[ebp+03h]
    mov esi,[esp+__MTX]
    @nx5row:
    mov eax,[edi+ebx-03h]
    sub ecx,edx
    xor eax,edx
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    {0} bt dword ptr [edi+ecx],00h
    {1} mov al,[esi+03h]
    {2} adc al,[edi+ebx]
    {0} mov eax,00000000h
    {1} cmovz eax,edx
    {2} sub [esi],eax
    {0} add esi,04h
    {1} add ecx,04h
    {2} jnz @decrease_row_free
    add ebx,04h
    js @nx5row
    mov eax,[esp+__FREE0]
    xor edx,edx
    mov esi,eax
    sub eax,[esp+__MTX]
    idiv ebp
    neg eax
    lea ecx,[ebp+edx]
    lea eax,[ebp+eax*04h]
    @@DECIDE_NEXT_STEP:
    xor edx,edx
    mov [esp+__FREE0],esi
    add edx,[esi]
    jnz @nx2mtx
    mov ebx,eax
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    sub edx,ebp
    jmp @newstar
    @0_star:
    mov [edi+ebx*02h+__0STAR],ecx
    mov ecx,[edi+eax*02h+__COLON]
    @newstar:
    mov ebx,eax
    lea eax,[edx-04h]
    @starincol:
    cmp [edi+eax*02h+__0STAR],ecx
    jz @0_star
    sub eax,04h
    jns @starincol
    mov [edi+ebx*02h+__0STAR],ecx
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    mov ebx,edi
    mov ecx,ebp
    jz @count_result_STACK
    mov edx,[edi]
    @restructure:
    {0} mov esi,[ebx+__0STAR]
    {1} mov byte ptr [edi+ecx+03h],00h
    {2} add ebx,08h
    {0} mov byte ptr [edi+esi],01h
    {1} add ecx,04h
    {2} jnz @restructure
    mov [edi],edx
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    {0} mov edx,[edi+ecx*02h+__0STAR]
    {1} add ecx,04h
    {2} add edx,ebp
    {0} add eax,[esi+edx]
    {1} shr edx,02h
    {2} add esi,ebp
    {0} cmp ecx,ebp
    {1} mov [ebx],dl
    {2} lea ebx,[ebx+01h]
    {0} jnz @results

  • P.H.

    senior tag

    Szinte minden lépésben többé-kevésbé módosított, működő kód, de még nem végleges.

    60 db 25x25 mátrix-ot old meg ezredmásodpercenként.
    60x60-as bemeneti mátrixméretnél átlagos 2.4 IPC is mérhető tartósan, ilyen méretnél legalább 2-3x a gyorsulás az előző kódhoz képest..

    mov eax,edi
    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    mov byte ptr [edi+00h],01h
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,04h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,04h
    lea eax,[eax+04h]
    jnz @subrow
    add ebx,04h
    jnz @rowmin
    jmp @columns
    @specific:
    cmp byte ptr [edi+edx],00h
    mov byte ptr [edi+edx],01h
    jnz @@ABNORMAL_EXIT
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    add ebx,04h
    jnz @rowmin
    @columns:
    mov [edi+00h],bl
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov esi,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp esi,[eax]
    cmova esi,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp esi,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor edx,edx
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp [eax+03h],dl
    cmovz edx,esi
    sub [eax],edx
    jnz @subcol
    mov dl,[edi+ecx+02h]
    mov byte ptr [edi+ecx+02h],01h
    or dl,[edi+ebx]
    mov edx,ecx
    jnz @subcol
    mov byte ptr [edi+ebx],01h
    sub edx,ebp
    mov byte ptr [edi+ecx+02h],01h
    sub dword ptr [esp+__SYS0],01h
    mov [edi+edx*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret

    @@3RD_STEP:
    mov byte ptr [edi+ebx+03h],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    mov ecx,ebp
    mov esi,[esp+__MTX]
    mov edx,00FFFFFFh
    @nxcol:
    cmp byte ptr [edi+ecx],00h
    mov eax,ebp
    jnz @check
    @zeroinrow:
    cmp edx,[esi]
    mov bl,[edi+eax+03h]
    sbb bl,00h
    jz @minimum
    @nx2col:
    sub esi,ebp
    add eax,04h
    jnz @zeroinrow
    mov esi,ecx
    add esi,[esp+__MTX]
    sub esi,ebp
    @check:
    add ecx,04h
    lea esi,[esi+04h]
    jnz @nxcol
    @@5TH_STEP:
    lea ebx,[ebp+03h]
    mov esi,[esp+__MTX]
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx-03h]
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add ecx,04h
    lea esi,[esi+04h]
    jnz @decrease_row_free
    add ebx,04h
    js @nx5row
    mov eax,[esp+__FREE0]
    xor edx,edx
    mov esi,eax
    sub eax,[esp+__MTX]
    idiv ebp
    neg eax
    lea ecx,[ebp+edx]
    lea eax,[ebp+eax*04h]
    @minimum:
    xor edx,edx
    mov [esp+__FREE0],esi
    add edx,[esi]
    jnz @nx2col
    @@DECIDE_NEXT_STEP:
    mov ebx,eax
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    sub edx,ebp
    jmp @newstar
    @0_star:
    mov [edi+ebx*02h+__0STAR],ecx
    mov ecx,[edi+eax*02h+__COLON]
    @newstar:
    mov ebx,eax
    lea eax,[edx-04h]
    @starincol:
    cmp [edi+eax*02h+__0STAR],ecx
    jz @0_star
    sub eax,04h
    jns @starincol
    mov [edi+ebx*02h+__0STAR],ecx
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    mov ebx,edi
    mov ecx,ebp
    jz @count_result_STACK
    mov edx,[edi]
    @restructure:
    mov esi,[ebx+__0STAR]
    mov byte ptr [edi+ecx+03h],00h
    add ecx,04h
    lea ebx,[ebx+08h]
    mov byte ptr [edi+esi],01h
    jnz @restructure
    mov [edi],edx
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Critital path kitakarítva, avagy egy DIV sok store-t győz.

    Counter 0 : Non-halted clock cycles
    Counter 1 : Retired instructions
    Counter 2 : Instructions per cycle (IPC)
    Counter 3 : L1 Data cache refill from RAM

    223800 2616.4 5604.4 2.1 0.0
    223850 2625.1 5869.5 2.2 0.0
    223900 2607.2 5824.5 2.2 0.0
    223950 2624.8 5906.3 2.3 0.0
    224000 2621.1 5887.6 2.2 0.0
    224050 2625.6 5880.5 2.2 0.0
    224100 2605.2 5845.0 2.2 0.0
    224150 2625.5 5871.4 2.2 0.0
    224200 2621.6 5850.6 2.2 0.0
    224250 2625.0 5846.2 2.2 0.0
    224300 2605.7 5783.7 2.2 0.0
    224350 2626.4 5367.4 2.0 0.0
    224400 2607.9 5825.7 2.2 0.0
    224450 2625.3 5696.0 2.2 0.0
    224500 2611.4 5796.3 2.2 0.0
    224550 2623.1 5902.6 2.3 0.0
    224600 2621.8 5889.7 2.2 0.0
    224650 2625.6 5879.4 2.2 0.0
    224700 2612.9 5871.2 2.2 0.0
    224750 2620.6 5908.6 2.3 0.0
    224800 2622.8 5893.5 2.2 0.0

    A kód, zárójelben a critical path-ok AMD-s integer port-leosztásával:

    mov eax,edi
    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,04h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,04h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    bts dword ptr [edi+edx],00h
    jnc @mark
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @mark:
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    @reducenxrow:
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov edx,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp edx,[eax]
    cmova edx,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp edx,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor esi,esi
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp byte ptr [eax+03h],00h
    cmovz esi,edx
    sub [eax],esi
    jnz @subcol
    bts dword ptr [edi+ecx],10h
    jc @subcol
    bts dword ptr [edi+ebx],00h
    mov esi,ecx
    jc @subcol
    sub esi,ebp
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [eax+03h],02h
    mov [edi+esi*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK

    @@3RD_STEP:
    mov byte ptr [esi+03h],08h
    mov byte ptr [edi+ebx+03h],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    mov eax,ebp
    mov esi,[esp+__MTX]
    mov edx,00FFFFFFh
    @nx2row:
    mov bh,[edi+eax+03h]
    mov ecx,ebp
    @zeroinrow:
    {0} cmp edx,[esi]
    {1} mov bl,bh
    {2} sbb bl,[edi+ecx]
    {0} jz @minimum
    @nx2col:
    {1} add ecx,04h
    {2} lea esi,[esi+04h]
    {0} jnz @zeroinrow
    add eax,04h
    jnz @nx2row
    @@5TH_STEP:
    mov ebx,ebp
    mov esi,[esp+__MTX]
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx]
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    {0} bt dword ptr [edi+ecx],00h
    {1} mov al,[esi+03h]
    {2} adc al,[edi+ebx+03h]
    {0} mov eax,00000000h
    {1} cmovz eax,edx
    {2} sub [esi],eax
    {0} add ecx,04h
    {1} lea esi,[esi+04h]
    {2} jnz @decrease_row_free
    add ebx,04h
    jnz @nx5row
    mov eax,[esp+__FREE0]
    xor edx,edx
    mov esi,eax
    sub eax,[esp+__MTX]
    idiv ebp
    neg eax
    lea ecx,[ebp+edx]
    lea eax,[ebp+eax*04h]
    @minimum:
    xor edx,edx
    mov [esp+__FREE0],esi
    add edx,[esi]
    jnz @nx2col
    @@DECIDE_NEXT_STEP:
    mov ebx,eax
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+__MTX]
    jmp @colon_to_star
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    sub esi,ecx
    sub eax,ebp
    sub esi,ebp
    mov ecx,[edi+eax*02h+__COLON]
    lea esi,[esi+ecx]
    @colon_to_star:
    mov [edi+eax*02h+__0STAR],ecx
    sub ecx,ebp
    mov byte ptr [esi+03h],02h
    lea esi,[edx+ecx]
    mov eax,ebp
    @search_star_in_column:
    cmp eax,ebx
    jz @nxstar
    test byte ptr [esi+03h],02h
    jnz @0_star
    @nxstar:
    sub esi,ebp
    add eax,04h
    jnz @search_star_in_column
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    mov ecx,ebp
    mov ebx,edi
    jz @count_result_STACK
    push dword ptr [edi]
    @restructure:
    {0} mov esi,[ebx+__COLON]
    {1} sub edx,ebp
    {2} mov [edi+ecx+03h],al
    {0} and byte ptr [edx+esi+03h],11110111b
    {1} mov esi,[ebx+__0STAR]
    {2} add ecx,04h
    {0} mov [ebx+__COLON],eax
    {1} lea ebx,[ebx+08h]
    {2} mov byte ptr [edi+esi],01h
    {0} jnz @restructure
    pop dword ptr [edi]
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    {0} mov edx,[edi+ecx*02h+__0STAR]
    {1} add ecx,04h
    {2} add edx,ebp
    {0} add eax,[esi+edx]
    {1} shr edx,02h
    {2} add esi,ebp
    {0} cmp ecx,ebp
    {1} mov [ebx],dl
    {2} lea ebx,[ebx+01h]
    {0} jnz @results

  • P.H.

    senior tag

    Ha ilyen nehéz 1.2 IPC fölé menni K10-en (és K10-5-ön is) FPU-ban ([link]) és integerban se nagyon könnyű olyan hasznos kódot írni, ami 2.0 IPC felett van ([link]), ésszerű döntésnek tűnik szálanként ("magonként"?) 2.0 IPC-re maximalizálni az amúgy 4 IPC-re feelkészített hardvert.

    Kérdés, hogy ez mennyire használja ki a kész, meglevő software-eket. Hiszen igazán nagyot villlantani kétféleképpen lehet:
    - ugyanazt a teljesítményt hozni kisebb termáis kereten belül
    - jóval nagyobb terljesítményt mutatni az adott termális keretek közt
    Mivel a butított Brazos-on az 1.5 IPC elérhető integerben a korábbi optimalizációs irányvonalak mentén, a minimális elvárás az 1.5 IPC a Bulldozeren is meglevő kódok esetén.

    (v.ö. korábbi FPU kódok pl. itt).

  • P.H.

    senior tag

    válasz P.H. #39 üzenetére

    a #39-beli összehasonlításban használt vonalankénti x87 kód:

    sub ebp,edx
    sub ecx,eax
    pushad
    lea edi,[esi+...+DATA2]
    fild dword ptr [esp+_ECX]
    shl eax,10h
    fild dword ptr [esp+_EBP]
    mov esi,[esi+...DEST]
    fld st(1)
    mov ebx,[edi-..._DATA1]
    fabs
    fld st(1)
    fabs
    fcompp
    sub edi,ebx
    fnstsw ax
    sahf
    ja @inlineMOVEX
    mov ebp,ecx
    fxch
    @inlineMOVEX:
    test ebp,ebp
    fdiv
    fld1
    jz @return
    jns @inlineSETDIR
    neg ebp
    fchs
    @inlineSETDIR:
    sahf
    fmul st(1),st
    jbe @inlineCOORDINATES
    fxch
    @inlineCOORDINATES:
    fild dword ptr [esp+_EDX]
    sar eax,10h
    fild dword ptr [esp+_EAX]
    @setpixel:
    cmp edx,[edi-...+_TOPLEFT]
    fadd st,st(2)
    setl cl
    cmp edx,[edi-...+_BOTTOM]
    setge ch
    imul edx,[edi-...+_DX]
    or ch,cl
    cmp eax,[edi-...+_RIGHT]
    setge cl
    add edx,eax
    or ch,cl
    cmp eax,[edi-...+_TOPLEFT]
    mov [esp+_ECX],ebx
    setl cl
    mov al,[edi+ebx-_ADDER+_DRAWCOLOR]
    or cl,ch
    jnz @continueLINE
    @round:
    add edx,[edi+ebx]
    add ebx,04h
    mov [esi+edx],al
    js @round
    mov ebx,[esp+_ECX]
    @continueLINE:
    fxch
    fadd st,st(3)
    sub ebp,01h
    fist dword ptr [esp+_ECX]
    fxch
    mov edx,[esp+_ECX]
    fist dword ptr [esp+_ECX]
    mov eax,[esp+_ECX]
    jge @setpixel
    fcompp
    @return:
    popad
    fcompp

  • P.H.

    senior tag

    Gyors o(log n) rendezési algoritmus 64 bites lebegőpontos számokra:

    inicializálás:
    kimenet:
    ESI: az ideiglenes,32 bites elemekből álló munkatömb címe
    EDI: a 32 bites munkatömb mérete
    bemenet:
    EAX: a 64 bites számok tömbjére mutató pointer
    EDX: az értékek száma a tömbben
    ESI: az ideiglenes,32 bites elemekből álló munkatömb címe
    lea edx,[eax+edx*08h]
    fldz
    mov ecx,esi
    xor edi,edi
    @insert:
    mov [ecx],edx
    sub edx,08h
    lea ebp,[edi+01h]
    cmp edx,[esp+_EAX]
    fstp st(0)
    jbe @return
    add edi,01h
    fld qword ptr [edx]
    @moveup:
    lea ecx,[esi+ebp*04h]
    shr ebp,01h
    mov ebx,[esi+ebp*04h]
    jz @insert
    fcom qword ptr [ebx]; fnstsw ax; sahf
    jae @insert
    mov [ecx],ebx
    jmp @moveup
    @return:

    A következő legkisebb elem lehívása:
    kimenet:
    EDX: a legkisebb elem pozíciója az eredeti tömmben
    EDI: a 32 bites munkatömb új mérete
    bemenet:
    EAX: a 64 bites számok tömbjére mutató pointer
    EDI: a 32 bites munkatömb jelenlegi mérete
    ESI: az ideiglenes,32 bites elemekből álló munkatömb címe
    or edx,-1
    sub edi,01h
    js @invalid
    pushad
    mov edx,[esi+01h*04h]
    mov ebp,00000001h
    mov ecx,[esi+edi*04h+04h]
    fld qword ptr [edx]
    sub edx,eax
    fld qword ptr [ecx]
    mov [esp+_EDX],edx
    @down:
    mov edx,ebp
    lea eax,[esi+ebp*(04h*2)]
    add ebp,ebp
    cmp ebp,edi
    ja @insertdown
    mov ebx,[eax+00h]
    mov edx,[eax+04h]
    jz @child
    fld qword ptr [edx]
    fcomp qword ptr [ebx]; fnstsw ax; sahf
    cmovb ebx,edx {cmovb = cmovc}
    adc ebp,00h
    @child:
    fcom qword ptr [ebx]
    mov edx,ebp
    fnstsw ax
    shr edx,01h
    sahf
    mov [esi+edx*04h],ebx
    ja @down
    @insertdown:
    fstp st(0)
    mov [esi+edx*04h],ecx
    popad
    sar edx,03h
    @invalid:
    popad

    A rendezés végét a negatív (-1) visszaadott pozíció jelzi, nem szükséges tesztelni a lépések számát.

  • P.H.

    senior tag

    SSE1 line algoritmus azonos stílusú vonalak láncolt listájára + 1st gen. Nerburst és K10 port elemzés:
    (»port latency (uops) subunit« formában)

    K10-en kb. 10%-kal gyorsabb, mint az x87-es megvalósítás, Prescott-on a sebességnövekedés több, mint kétszeres az x87-hez képest.
    K10-en 1.6 IPC mérhető (kb. 30000 vonalas tesztadaton 10,5M órajel), Netburst-re visszaszámolva (ugyanazon a tesztadaton 26M órajel) 0.65 IPC.

    mov ecx,[esi+_DATA1] // p2 2 (1) load p012 3 (1) AGU
    pushad // -vector- -vector-
    xorps xmm0,xmm0 // p1 2 (1) mmxalu p34 2 (1) FA/M
    lea edi,[esi+DATA2] // p0/1 d (1) alu p012 3 (1) AGU
    pcmpeqw xmm7,xmm7 // p1 2 (1) mmxalu p34 2 (1) FA/M
    cvtpi2ps xmm3,[edi-...+_TOPLEFT] // p1+2 10 (4) mmx+load 7 (2)
    xorps xmm1,xmm1 // p1 2 (1) mmxalu p34 2 (1) FA/M
    mov esi,[esi+...DEST] // p2 2 (1) load p012 3 (1) AGU
    pslld xmm7,1Fh // p1 2 (1) mmxshf p34 3 (1) FA/M
    cvtpi2ps xmm2,[edi-...+_RIGHTBOTTOM] // p1+2 10 (4) mmx+load 7 (2)
    xorps xmm5,xmm5 // p1 2 (1) mmxalu p34 2 (1) FA/M
    shufps xmm3,xmm2,01000000b // p1 4 (1) mmxshf p34 3 (1) FA/M
    sub edi,ecx // p0/1 d (1) alu p012 1 (1) ALU
    xorps xmm6,xmm6 // p1 2 (1) mmxalu p34 2 (1) FA/M
    shufps xmm3,xmm3,11011000b // p1 4 (1) mmxshf p34 3 (1) FA/M
    @nxline:
    test ebx,ebx // p0/1 d (1) alu p012 1 (1) ALU
    jz @return // p0 2 (1) alu p012 1 (1) ALU
    mov eax,[ebx+TRECORD.REF] // p2 2 (1) load p012 3 (1) AGU
    pcmpeqw xmm2,xmm2 // p1 2 (1) mmxalu p34 2 (1) FA/M
    mov ecx,[ebx+TRECORD.SELF] // p2 2 (1) load p012 3 (1) AGU
    mov ebp,[eax+THEADER.YCOOR] // p2 2 (1) load p012 3 (1) AGU
    pcmpeqw xmm4,xmm4 // p1 2 (1) mmxalu p34 2 (1) FA/M
    mov edx,[ecx+THEADER.YCOOR] // p2 2 (1) load p012 3 (1) AGU
    psrld xmm2,01h // p1 2 (1) mmxshf p34 3 (1) FA/M
    mov eax,[eax+THEADER.XCOOR] // p2 2 (1) load p012 3 (1) AGU
    mov ecx,[ecx+THEADER.XCOOR] // p2 2 (1) load p012 3 (1) AGU
    sub ebp,edx // p0/1 d (1) alu p012 1 (1) ALU
    movaps xmm6,xmm2 // p0 6 (1) mov p345 3 (1) FANY
    sub eax,ecx // p0/1 d (1) alu p012 1 (1) ALU
    pslld xmm4,25 // p1 2 (1) mmxshf p34 3 (1) FA/M
    cvtsi2ss xmm1,ebp // p1 10 (3) fpmmx 14 (3)
    mov ebx,[ebx+TRECORD.NX] // p2 2 (1) load p012 3 (1) AGU
    cvtsi2ss xmm0,eax // p1 10 (3) fpmmx 14 (3)
    andps xmm6,xmm1 // p1 2 (1) mmxalu p34 2 (1) FA/M
    andps xmm2,xmm0 // p1 2 (1) mmxalu p34 2 (1) FA/M
    psrld xmm4,02h // p1 2 (1) mmxshf p34 3 (1) FA/M
    comiss xmm6,xmm2 // p1 6 (2) fpadd p3 (1) FADD
    mov [esp+_EBX],ebx // p0+3 2 (3) alu+store p012 3 (1) AGU
    cmovbe ebp,eax // 6 (3) p012 1 (1) ALU
    cvtsi2ss xmm6,edx // p1 10 (3) fpmmx 14 (3)
    setbe al // p1 5 (3) alu p012 1 (1) ALU
    jae @inlineMOVEX // p0 2 (1) alu p012 1 (1) ALU
    movaps xmm2,xmm0 // p0 6 (1) mov p345 3 (1) FANY
    movaps xmm0,xmm1 // p0 6 (1) mov p345 3 (1) FANY
    movaps xmm1,xmm2 // p0 6 (1) mov p345 3 (1) FANY
    @inlineMOVEX:
    test ebp,ebp // p0/1 d (1) alu p012 1 (1) ALU
    cvtsi2ss xmm5,ecx // p1 10 (3) fpmmx 14 (3)
    jz @nxline // p0 2 (1) alu p012 1 (1) ALU
    divss xmm0,xmm1 // p1 23 (1) fpdiv p4 16 (1) FMUL
    mov ebx,[esp+_ECX] // p2 2 (1) load p012 3 (1) AGU
    shufps xmm4,xmm0,00000000b // p1 4 (1) mmxshf p34 3 (1) FA/M
    jns @inlineSETDIR // p0 2 (1) alu p012 1 (1) ALU
    neg ebp // p0 d (1) alu p012 1 (1) ALU
    xorps xmm4,xmm7 // p1 2 (1) mmxalu p34 2 (1) FA/M
    @inlineSETDIR:
    test al,al // p0/1 d (1) alu p012 1 (1) ALU
    mov al,[edi+ebx-_ADDER+_DRAWCOLOR] // p2 2 (1) load p012 3 (1) AGU
    shufps xmm5,xmm6,00000000h // p1 4 (1) mmxshf p34 3 (1) FA/M
    jnz @setpixel // p0 2 (1) alu p012 1 (1) ALU
    shufps xmm4,xmm4,00001010b // p1 4 (1) mmxshf p34 3 (1) FA/M
    @setpixel:
    movaps xmm2,xmm3 // p0 6 (1) mov p345 3 (1) FANY
    imul edx,[edi+ebx-_ADDER+_DX] // p1+2 15 (4) fpmul+load p0 6 (1) ALU0+AGU
    cmpltps xmm2,xmm5 // p1 4 (1) fpadd p3 (1) FADD
    add edx,ecx // p0/1 d (1) alu p012 1 (1) ALU
    addps xmm5,xmm4 // p1 4 (1) fpadd p3 4 (1) FADD
    movmskps ecx,xmm2 // p1 6 (2) fp p34 3 (1) FA/M
    movhlps xmm0,xmm5 // p1 4 (1) mmxshf
    cmp cl,05h // p0/1 d (1) alu p012 1 (1) ALU
    cvtss2si ecx,xmm5 // p1 8 (2) fp p3+5 8 (2) FADD+FMISC
    jnz @continueLINE // p0 2 (1) alu p012 1 (1) ALU
    @round:
    add edx,[edi+ebx] // p1+2 d (2) alu+load p012 4 (2) ALU+AGU
    add ebx,04h // p0/1 d (1) alu p012 1 (1) ALU
    mov [esi+edx],al // p0+3 2 (3) store p012 3 (1) AGU
    js @round // p0 2 (1) alu p012 1 (1) ALU
    mov ebx,[esp+_ECX] // p2 2 (1) load p012 3 (1) AGU
    @continueLINE:
    sub ebp,01h // p01 d (1) alu p012 1 (1) ALU
    cvtss2si edx,xmm0 // p1 8 (2) fp p3+5 8 (2) FADD+FMISC
    jge @setpixel // p0 2 (1) alu p012 1 (1) ALU
    mov ebx,[esp+_EBX] // p2 2 (1) load p012 3 (1) AGU
    jmp @nxline // p1 0 (1) alu p012 1 (2) ALU
    @return:
    popad // -vector- -vector-

  • P.H.

    senior tag

    1 GHz-es Brazos (max. 2 utasítás/órajel micro-arch) az utoljára írt kóddal: átlagosan 1.5 IPC

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Retired uops
    Counter 2 : Instructions per cycle (IPC)
    Counter 3 : L1 Data cache misses

    65950 881.3 1379.8 1.6 0.2
    66000 821.5 1163.5 1.4 0.5
    66050 820.2 1261.3 1.5 0.3
    66100 737.5 994.7 1.3 0.8
    66150 737.5 994.7 1.3 0.8
    66200 842.2 1192.9 1.4 0.7
    66250 801.5 1210.0 1.5 0.3
    66300 767.6 994.4 1.3 1.1
    66350 840.1 1273.6 1.5 0.3
    66400 855.2 1334.0 1.6 0.3
    66450 823.4 1196.1 1.4 0.7
    66500 733.6 1016.0 1.4 0.7
    66550 787.5 1134.9 1.4 0.6
    66600 828.6 1204.5 1.4 0.5
    66650 909.5 1380.5 1.5 0.4
    66700 781.3 1157.5 1.5 0.5
    66750 816.6 1163.7 1.4 0.6
    66800 805.0 1149.6 1.4 0.6
    66850 777.0 1089.3 1.4 0.6
    66900 815.3 1205.9 1.5 0.5
    66950 804.8 1222.9 1.5 0.4
    67000 790.1 1026.5 1.3 0.7
    67050 737.5 983.0 1.3 0.8
    67100 826.8 1275.2 1.5 0.3
    67150 795.9 1153.1 1.4 0.6
    67200 760.8 1068.4 1.4 0.6
    67250 822.5 1218.7 1.5 0.5
    67300 828.5 1223.5 1.5 0.5
    67350 817.5 1150.6 1.4 0.4
    67400 811.8 1214.2 1.5 0.4
    67450 755.6 1051.2 1.4 0.7
    67500 858.5 1315.3 1.5 0.4
    67550 754.6 1080.0 1.4 0.6
    67600 863.4 1195.5 1.4 0.6
    67650 750.7 1065.4 1.4 0.6

  • P.H.

    senior tag

    Az 5. és az 1. lépés finomhangolása után, valamint a munkaterület címe bemeneti paraméter lett (a hívó algoritmus többszálúsítása okán):

    2.0 IPC-vel, 38 25x25 mátrix-ot old meg ezredmásodpercenként.

    pushad
    shl ebp,02h
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,04h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,04h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    bts dword ptr [edi+edx],00h
    jnc @mark
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @mark:
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    @reducenxrow:
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov edx,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp edx,[eax]
    cmova edx,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp edx,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor esi,esi
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp byte ptr [eax+03h],00h
    cmovz esi,edx
    sub [eax],esi
    jnz @subcol
    bts dword ptr [edi+ecx],10h
    jc @subcol
    bts dword ptr [edi+ebx],00h
    mov esi,ecx
    jc @subcol
    sub esi,ebp
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [eax+03h],02h
    mov [edi+esi*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK

    @@3RD_STEP:
    mov byte ptr [esi+03h],08h
    mov byte ptr [edi+ebx+03h],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    mov eax,ebp
    mov esi,[esp+__MTX]
    mov edx,00FFFFFFh
    @nx2row:
    mov bh,[edi+eax+03h]
    mov ecx,ebp
    @zeroinrow:
    cmp edx,[esi]
    mov bl,bh
    sbb bl,[edi+ecx]
    jz @minimum
    @nx2col:
    add ecx,04h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add eax,04h
    jnz @nx2row
    @@5TH_STEP:
    mov ebx,ebp
    mov esi,[esp+__MTX]
    @nx5row:
    mov eax,edx
    sub ecx,edx
    xor eax,[edi+ebx]
    cmovs edx,ecx
    mov ecx,ebp
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx+03h]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add esi,04h
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    jnz @nx5row
    mov eax,[esp+__FREE0ROW]
    xor edx,edx
    mov ecx,[esp+__FREE0COL]
    mov esi,[esp+__FREE0]
    jmp @@DECIDE_NEXT_STEP
    @minimum:
    xor edx,edx
    mov [esp+__FREE0ROW],eax
    add edx,[esi]
    mov [esp+__FREE0COL],ecx
    mov [esp+__FREE0],esi
    jnz @nx2col
    @@DECIDE_NEXT_STEP:
    mov ebx,eax
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+__MTX]
    jmp @colon_to_star
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    sub esi,ecx
    sub eax,ebp
    sub esi,ebp
    mov ecx,[edi+eax*02h+__COLON]
    lea esi,[esi+ecx]
    @colon_to_star:
    mov [edi+eax*02h+__0STAR],ecx
    sub ecx,ebp
    mov byte ptr [esi+03h],02h
    lea esi,[edx+ecx]
    mov eax,ebp
    @search_star_in_column:
    cmp eax,ebx
    jz @nxstar
    test byte ptr [esi+03h],02h
    jnz @0_star
    @nxstar:
    sub esi,ebp
    add eax,04h
    jnz @search_star_in_column
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    mov ecx,ebp
    mov ebx,edi
    jz @count_result_STACK
    push dword ptr [edi]
    @restructure:
    mov esi,[ebx+__COLON]
    sub edx,ebp
    mov [edi+ecx+03h],al
    and byte ptr [edx+esi+03h],11110111b
    mov esi,[ebx+__0STAR]
    add ecx,04h
    mov [ebx+__COLON],eax
    lea ebx,[ebx+08h]
    mov byte ptr [edi+esi],01h
    jnz @restructure
    pop dword ptr [edi]
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    - a VectorPath PUSHAD kiváltható 3 tárolással
    - a @@2ND_STEP-ben levő, körülugrált kicsi valószínűségű ág máshová került
    - plusz 2 utasítás többletadminisztációval 2 keresőciklus feleslegessé vált
    - a sorok és oszlopok, valamint a speciális mátrixelemek jelölő byte-értékeinek összehangolása után (mely érték 1, azaz közvetlenül másoható Carry Flag-be BT-vel regiszterhasználat nélkül; mely jelölések összege milyen esetekben pontosan 0) a @@5TH_STEP fele feleslegessé vált

    2.0 IPC-vel, 36 25x25 mátrix-ot old meg ezredmásodpercenként.

    pushad
    shl ebp,02h
    mov ebx,offset(MARKS)
    xor ecx,ecx
    lea edx,[ebp+ebp*02h]
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,02000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,04h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,02000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,04h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    bts dword ptr [edi+edx],00h
    jnc @mark
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @mark:
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx*02h+__0STAR],edx
    jz @count_result_STACK
    @reducenxrow:
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov edx,02000000h
    mov ecx,ebp
    @findcolmin:
    cmp edx,[eax]
    cmova edx,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp edx,02000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor esi,esi
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp byte ptr [eax+03h],00h
    cmovz esi,edx
    sub [eax],esi
    jnz @subcol
    bts dword ptr [edi+ecx],10h
    jc @subcol
    bts dword ptr [edi+ebx],00h
    mov esi,ecx
    jc @subcol
    sub esi,ebp
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [eax+03h],02h
    mov [edi+esi*02h+__0STAR],ebx
    jnz @subcol
    jmp @count_result_STACK

    @@3RD_STEP:
    mov byte ptr [esi+03h],08h
    mov byte ptr [edi+ebx+01h],0FFh
    mov byte ptr [edi+edx],00h
    mov [edi+eax*02h+__COLON],ecx
    @@2ND_STEP:
    mov eax,ebp
    mov edx,00FFFFFFh
    mov esi,[esp+__MTX]
    @nx2row:
    mov ecx,ebp
    mov bh,[edi+eax+01h]
    @zeroinrow:
    cmp edx,[esi]
    mov bl,bh
    sbb bl,[edi+ecx]
    jz @minimum
    @nx2col:
    add ecx,04h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add eax,04h
    jnz @nx2row
    @@5TH_STEP:
    mov ebx,ebp
    mov esi,[esp+__MTX]
    @nx5row:
    movsx eax,byte ptr [edi+ebx+01h]
    mov ecx,ebp
    xor eax,edx
    jns @decrease_row_free
    neg edx
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,[edi+ebx+01h]
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add esi,04h
    add ecx,04h
    jnz @decrease_row_free
    add ebx,04h
    jnz @nx5row
    mov eax,[esp+__FREE0ROW]
    xor edx,edx
    mov ecx,[esp+__FREE0COL]
    mov esi,[esp+__FREE0]
    jmp @@DECIDE_NEXT_STEP
    @minimum:
    xor edx,edx
    mov [esp+__FREE0ROW],eax
    add edx,[esi]
    mov [esp+__FREE0COL],ecx
    mov [esp+__FREE0],esi
    jnz @nx2col
    @@DECIDE_NEXT_STEP:
    mov ebx,eax
    sub eax,ebp
    add edx,[edi+eax*02h+__0STAR]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+__MTX]
    jmp @colon_to_star
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    sub esi,ecx
    sub eax,ebp
    sub esi,ebp
    mov ecx,[edi+eax*02h+__COLON]
    lea esi,[esi+ecx]
    @colon_to_star:
    mov [edi+eax*02h+__0STAR],ecx
    sub ecx,ebp
    mov byte ptr [esi+03h],02h
    lea esi,[edx+ecx]
    mov eax,ebp
    @search_star_in_column:
    test byte ptr [esi+03h],02h
    jz @nxstar
    cmp eax,ebx
    jnz @0_star
    @nxstar:
    sub esi,ebp
    add eax,04h
    jnz @search_star_in_column
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    lea ebx,[edi+__COLON]
    mov ecx,ebp
    jz @count_result_STACK
    @restructure:
    mov esi,[ebx]
    sub edx,ebp
    mov [edi+ecx],eax
    and byte ptr [edx+esi+03h],11110111b
    add ecx,04h
    mov [ebx],eax
    lea ebx,[ebx+08h]
    jnz @restructure
    mov ebx,edi
    mov eax,ebp
    mov ecx,[edi+00h]
    @markcol:
    mov edx,[ebx+__0STAR]
    add eax,04h
    lea ebx,[ebx+08h]
    mov byte ptr [edi+edx],01h
    jnz @markcol
    mov [edi+00h],ecx
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx*02h+__0STAR]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Korrekció: benne maradt néhány letiltott utasítás.
    A @@2ND_STEP így néz ki:

    @@2ND_STEP:
    mov esi,[esp+__MTX]
    sub esp,20h
    mov eax,ebp
    mov edx,00FFFFFFh
    @nx2row:
    mov ecx,ebp
    @zeroinrow:
    mov bl,[edi+ecx]
    cmp edx,[esi]
    adc bl,[edi+eax+01h]
    jnz @nx2col
    xor edx,edx
    add esp,20h
    add edx,[esi]
    jz @@DECIDE_NEXT_STEP
    pushad
    @nx2col:
    add ecx,04h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add eax,04h
    jnz @nx2row

  • P.H.

    senior tag

    Nem hagy(ott) nyugodni a kisördög. A teljesen 32 bitesre átírással megnyílt pár lehetőség: külön jelölő byte az oszlopnak, külön a sornak, külön a bevezető sorjelölésnek, így sikerült drasztikusan csökkenteni a load-op-store utasításokat, sima store-ral helyettesítve őket.

    Kombinálva ezt az AMD 2 load/cycle felépítésével, sikerült elérni a 30 db 25x25-ös mátrix per ezredmásodperc teljesítményt, 2.6 GHz-es Shanghai-on.

    Csak Intel-en ne lenne fele ilyen gyors így, 2.5 GHz Core2-n tesztelve... (Sandy Bridge-ig, ami ugyancsak 2 load/cycle felépítésű - lesz -).

    Az algoritmuson látható, hogy egyetlen szorzáson kívül összeadás, kivonásnál és bitmanipulációknál bonyolultabb utasítás nincs benne benne (ADC, SBB és CMOVcc viszont elég sok van), a skálázott memóriahozzáférést sem használom már ki, viszont egy pointer-rel két adatterületet is címzek, egyet-egyet a pozitív és a negatív oldalán.

    pushad
    lea edx,[ebp*08h]
    mov ebx,offset(MARKS)
    xor ecx,ecx
    lea edi,[ebx+ebp*04h]
    imul ebp,BYTE(-4)
    @mark0:
    sub edx,04h
    mov [ebx+edx],ecx
    jg @mark0
    @@REDUCE_ROWS:
    mov ebx,ebp
    @rowmin:
    mov esi,01000000h
    mov ecx,ebp
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,04h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,01000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,04h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    bts dword ptr [edi+edx],00h
    jnc @mark
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @mark:
    add ecx,ebx
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [edi+ebx+02h],01h
    mov [edi+ecx],edx
    jz @count_result_STACK
    @reducenxrow:
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov edx,01000000h
    mov ecx,ebp
    @findcolmin:
    cmp edx,[eax]
    cmova edx,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp edx,01000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor esi,esi
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp byte ptr [eax+03h],00h
    cmovz esi,edx
    sub [eax],esi
    jnz @subcol
    bts dword ptr [edi+ecx],10h
    jc @subcol
    bts dword ptr [edi+ebx],00h
    mov esi,ecx
    jc @subcol
    sub esi,ebp
    sub dword ptr [esp+__SYS0],01h
    mov byte ptr [eax+03h],01h
    mov [edi+esi],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@3RD_STEP:
    mov byte ptr [esi+03h],02h
    mov byte ptr [edi+ebx+01h],01h
    mov byte ptr [edi+edx],00h
    @@2ND_STEP:
    mov esi,[esp+__MTX]
    sub esp,20h
    mov eax,ebp
    mov edx,00FFFFFFh
    @nx2row:
    mov bh,[edi+eax+01h]
    mov ecx,ebp
    @zeroinrow:
    mov bl,[edi+ecx]
    and bl,01h
    cmp edx,[esi]
    adc bl,[edi+eax+01h]
    jnz @nx2col
    xor edx,edx
    add esp,20h
    add edx,[esi]
    jz @@DECIDE_NEXT_STEP
    pushad
    @nx2col:
    add ecx,04h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add eax,04h
    jnz @nx2row
    @@5TH_STEP:
    mov ebx,ebp
    mov esi,[esp+_SAVE+__MTX]
    @nx5row:
    cmp byte ptr [edi+ebx+01h],00h
    mov ecx,ebp
    jnz @increase_double_markeds
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,00h
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add ecx,04h
    lea esi,[esi+04h]
    jnz @decrease_row_free
    jmp @step5row
    @increase_double_markeds:
    mov al,[esi+03h]
    and al,11111100b
    bt dword ptr [edi+ecx],00h
    sbb al,00h
    mov eax,00000000h
    cmovc eax,edx
    add [esi],eax
    add ecx,04h
    lea esi,[esi+04h]
    jnz @increase_double_markeds
    @step5row:
    add ebx,04h
    jnz @nx5row
    popad
    xor edx,edx
    @@DECIDE_NEXT_STEP:
    mov ebx,eax
    sub eax,ebp
    add edx,[edi+eax]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+__MTX]
    @colon_to_star:
    mov [edi+eax],ecx
    sub ecx,ebp
    mov byte ptr [esi+03h],01h
    lea esi,[edx+ecx]
    mov eax,ebp
    mov byte ptr [edi+ebx+01h],00h
    @search_star_in_column:
    test byte ptr [esi+03h],01h
    jz @nxstar
    cmp eax,ebx
    jnz @0_star
    @nxstar:
    sub esi,ebp
    add eax,04h
    jnz @search_star_in_column
    jmp @@1ST_STEP
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    sub eax,ebp
    sub esi,ecx
    mov dword ptr [edi+eax],00000000h
    mov ecx,ebp
    @search_colon_in_row:
    test byte ptr [esi+03h],02h
    jnz @colon_to_star
    add ecx,04h
    lea esi,[esi+04h]
    jnz @search_colon_in_row
    @error:
    nop
    @@1ST_STEP:
    sub dword ptr [esp+__SYS0],01h
    jz @count_result_STACK
    mov ebx,ebp
    mov ecx,[edi+00h]
    jmp @nxclear
    @clear_colon:
    and byte ptr [esi+03h],11111101b
    add eax,04h
    lea esi,[esi+04h]
    jnz @clear_colon
    @nxclear:
    mov eax,ebp
    @markedrow:
    cmp byte ptr [edi+ebx+01h],00h
    mov esi,edx
    mov dword ptr [edi+ebx],00000000h
    jnz @clear_colon
    sub edx,ebp
    add ebx,04h
    jnz @markedrow
    @markcol:
    mov edx,[edi+ebx]
    add eax,04h
    lea ebx,[ebx+04h]
    mov byte ptr [edi+edx],01h
    jnz @markcol
    mov [edi+00h],ecx
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Kissé átszerkesztve a teljes algoritmust (teljesen 32 bites adatokon dolgozik) az utasításszám csökkent.
    Generálisan AMD-re és Intel-re:

    pushad
    mov ebx,offset(MARKS)
    lea edx,[ebp+ebp]
    xor ecx,ecx
    lea edi,[ebx+ebp*04h]
    imul ebp,BYTE(-4)
    @mark0:
    sub edx,01h
    mov [ebx],ecx
    lea ebx,[ebx+04h]
    jg @mark0
    @@REDUCE_ROWS:
    mov [esp+__SYS0],ebp
    mov ebx,ebp
    @rowmin:
    mov ecx,ebp
    mov esi,01000000h
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,04h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,01000000h
    jz @specific
    add eax,ebp
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,04h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    test byte ptr [edi+edx],01h
    jz @mark
    @@ABNORMAL_EXIT:
    add esp,20h
    stc
    ret
    @mark:
    or byte ptr [edi+ebx],10h
    add ecx,ebx
    or byte ptr [edi+edx],01h
    add dword ptr [esp+__SYS0],04h
    mov [edi+ecx],edx
    jz @count_result_STACK
    @reducenxrow:
    add ebx,04h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    sub ebx,04h
    sub eax,04h
    cmp ebx,ebp
    jl @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @@RECUDE_COLUMNS
    mov edx,01000000h
    mov ecx,ebp
    @findcolmin:
    cmp edx,[eax]
    cmova edx,[eax]
    add eax,ebp
    add ecx,04h
    jnz @findcolmin
    cmp edx,01000000h
    lea ecx,[ebp-04h]
    jz @@ABNORMAL_EXIT
    @subcol:
    xor esi,esi
    add ecx,04h
    jz @@RECUDE_COLUMNS
    sub eax,ebp
    cmp byte ptr [eax+03h],00h
    cmovz esi,edx
    sub [eax],esi
    jnz @subcol
    bts dword ptr [edi+ecx],04h
    jc @subcol
    bts dword ptr [edi+ebx],00h
    mov esi,ecx
    jc @subcol
    sub esi,ebp
    add dword ptr [esp+__SYS0],04h
    mov byte ptr [eax+03h],01h
    mov [edi+esi],ebx
    jnz @subcol
    jmp @count_result_STACK
    @@3RD_STEP:
    or byte ptr [edi+ebx],02h
    mov byte ptr [esi+03h],02h
    and byte ptr [edi+edx],11111110b
    @@2ND_STEP:
    mov esi,[esp+__MTX]
    sub esp,20h
    mov ebx,ebp
    mov edx,00FFFFFFh
    @nx2row:
    bt dword ptr [edi+ebx],01h
    mov ecx,ebp
    setc ah
    @zeroinrow:
    mov al,[edi+ecx]
    and al,01h
    cmp edx,[esi]
    adc al,ah
    jnz @nx2col
    xor edx,edx
    add esp,20h
    add edx,[esi]
    jz @@DECIDE_NEXT_STEP
    pushad
    @nx2col:
    add ecx,04h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add ebx,04h
    jnz @nx2row
    @@5TH_STEP:
    mov esi,[esp+_SAVE+__MTX]
    mov ebx,ebp
    @nx5row:
    test byte ptr [edi+ebx],02h
    mov ecx,ebp
    jnz @increase_double_markeds
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,00h
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add ecx,04h
    lea esi,[esi+04h]
    jnz @decrease_row_free
    jmp @step5row
    @increase_double_markeds:
    mov al,[esi+03h]
    and al,11111100b
    bt dword ptr [edi+ecx],00h
    sbb al,00h
    mov eax,00000000h
    cmovc eax,edx
    add [esi],eax
    add ecx,04h
    lea esi,[esi+04h]
    jnz @increase_double_markeds
    @step5row:
    add ebx,04h
    jnz @nx5row
    popad
    xor edx,edx
    @@DECIDE_NEXT_STEP:
    mov eax,ebx
    sub eax,ebp
    add edx,[edi+eax]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+__MTX]
    @colon_to_star:
    mov [edi+eax],ecx
    sub ecx,ebp
    mov byte ptr [esi+03h],01h
    lea esi,[edx+ecx]
    mov eax,ebp
    and byte ptr [edi+ebx],11111101b
    @search_star_in_column:
    test byte ptr [esi+03h],01h
    jz @nxstar
    cmp eax,ebx
    jnz @0_star
    @nxstar:
    sub esi,ebp
    add eax,04h
    jnz @search_star_in_column
    jmp @@1ST_STEP
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    sub eax,ebp
    sub esi,ecx
    mov dword ptr [edi+eax],00000000h
    mov ecx,ebp
    @search_colon_in_row:
    test byte ptr [esi+03h],02h
    jnz @colon_to_star
    add ecx,04h
    lea esi,[esi+04h]
    jmp @search_colon_in_row
    @@1ST_STEP:
    add dword ptr [esp+__SYS0],04h
    jz @count_result_STACK
    mov ebx,ebp
    mov ecx,[edi+00h]
    jmp @nxclear
    @clear_colon:
    and byte ptr [esi+03h],11111101b
    add eax,04h
    lea esi,[esi+04h]
    jnz @clear_colon
    @nxclear:
    mov eax,ebp
    @markedrow:
    test byte ptr [edi+ebx],02h
    mov esi,edx
    mov byte ptr [edi+ebx],00h
    jnz @clear_colon
    sub edx,ebp
    add ebx,04h
    jnz @markedrow
    @markcol:
    mov edx,[edi+ebx]
    add eax,04h
    lea ebx,[ebx+04h]
    mov byte ptr [edi+edx],01h
    jnz @markcol
    mov [edi+00h],ecx
    jmp @@2ND_STEP
    @count_result_STACK:
    xor ecx,ecx
    neg ebp
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    mov edx,[edi+ecx]
    add ecx,04h
    add edx,ebp
    add eax,[esi+edx]
    shr edx,02h
    add esi,ebp
    cmp ecx,ebp
    mov [ebx],dl
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Kód, még jobban kiegyenesítve, mostmár a teljes mártix egy ciklus, egy-egy sora helyett. AMD-n 2.3 IPC.

    @@2ND_STEP:
    neg ebp
    mov esi,[esp+__MTX]
    sub esp,20h
    mov ebx,ebp
    mov edx,00FFFFFFh
    mov ecx,ebp
    @zeroinrow:
    bt dword ptr [edi+ebx],01h
    setc ah
    mov al,[edi+ecx]
    and al,01h
    cmp edx,[esi]
    adc al,ah
    jnz @nx2col
    xor edx,edx
    add esp,20h
    add edx,[esi]
    jz @@DECIDE_NEXT_STEP
    pushad
    @nx2col:
    add cl,01h
    lea esi,[esi+04h]
    cmovz ecx,ebp
    adc ebx,00h
    jnz @zeroinrow

    Most szembesültem először azzal igazán, hogy az AMD féle generális "single cycle execution" + a 2 loads/cycle felépítésre megírt program Intel-en (Core2) fájóan lassabb, mint AMD-n. No ekkor mit lehet csinálni? Az általános gyors vagy AMD-specializált (de az általánosan elterjedt CPU-kon lassabb) megoldás a jobb?

  • P.H.

    senior tag

    @@2ND_STEP újra módosítva, mostmár az Intel CPU-kon is hozza a 2.0 IPC-t, így a teljes algoritmus is (Intel esetében az ADC és SBB legalább Pentium Pro óta, a CMOVcc legalább Core2 óta 2 micro-op, egészen Nehalem-ig :(( , AMD-nél K7 óta 1 micro-op, 1 órajel lefutási idővel; pedig ezek az ugrásmentesítés és az ILP-kihasználás alapkövei a SETcc mellett).

    Mivel az utasításszám is csökkent és a belső ciklustörzsből is kiemelhető pár utasítás, így AMD-n is gyorsabb az előzőnél egy kicsivel.

    Az első adandó alkalommal lemér(et)em Bobcat-on is. Ha ott is tudja hozni a 2 körüli IPC-t, akkor mivel nagyon hasonlóak felépítésben - a Bulldozer az emelt órajeleivel valóban speed racer lesz integer-ben - ha marad a legtöbb integer utasítás 1 órajeles lefutási értéke.

    @@2ND_STEP:
    xor ebx,ebx
    xor ecx,ecx
    mov esi,[esp+_SAVE+__MTX]
    sub ebx,ebp
    mov edx,00FFFFFFh
    @free0:
    bt dword ptr [edi+ebx],01h
    setc ah
    sub ecx,ebp
    @zeroinrow:
    mov al,[edi+ecx]
    and al,01h
    cmp edx,[esi]
    adc al,ah
    jnz @nx2col
    xor edx,edx
    add esp,20h
    add edx,[esi]
    pushad
    jz @@DECIDE_NEXT_STEP
    @nx2col:
    add ecx,01h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add ebx,01h
    jnz @free0

  • P.H.

    senior tag

    válasz P.H. #29 üzenetére

    Lemérve.

    Előző:
    "Algoritmusban felhasználásra kihegyezve (több 100000 lefutás); Shanghai-on 1.4 IPC, ezredmásodpercenként legalább 20 db 25x25-ös mátrix megoldása."

    Az újjal:
    "Algoritmusban felhasználásra kihegyezve (több 100000 lefutás); Shanghai-on 1.9 IPC, ezredmásodpercenként legalább 28 db 25x25-ös mátrix megoldása."

  • P.H.

    senior tag

    válasz P.H. #28 üzenetére

    @@2ND_STEP lecserélve, "kiegyenesítve", így már 0.9 IPC helyett hozza a 2.0 IPC-t, kevesebb utasítással.
    A teljes, előzőekben említett algoritmus IPC-je így már (mivel a 2. step lefutása a leggyakoribb) 1.9 körüli.

    Carry Flag a programozó legjobb barátja ... legalábbis AMD-n

    @@2ND_STEP:
    xor ecx,ecx
    xor ebx,ebx
    mov esi,[esp+_SAVE+__MTX]
    mov edx,00FFFFFFh
    sub ebx,ebp
    @free0:
    sub ecx,ebp
    @zeroinrow:
    bt dword ptr [edi+ebx],01h
    setc al
    bt dword ptr [edi+ecx],00h
    adc al,00h
    cmp edx,[esi]
    adc al,00h
    jnz @nx2col
    xor edx,edx
    add esp,_SAVE
    add edx,[esi]
    pushad
    jz @@DECIDE_NEXT_STEP
    @nx2col:
    add ecx,01h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add ebx,01h
    jnz @free0

  • P.H.

    senior tag

    Utolsó felvonás, két bevezető ciklus összevonása után.

    Néhány IPC-mérés a lépések ciklusaira (végtelen ciklusban mérve):
    @@REDUCE_ROWS:1.8 IPC
    @@REDUCE_COLUMNS:1.6 IPC
    @@2ND_STEP: 0.9 IPC (ez a leggyakrabban lefutó ciklus)
    @@5TH_STEP: 2.2 IPC
    @@1ST_STEP: 1.5 IPC

    Úgy tűnik, az AMD-n (a Bulldozer-ig bezárólag) a legjobb stratégia az, ha a ciklusokban az utasítások fele [ ] referenciát tartalmaz, azaz a memóriahivatkozások mellett bizonyos ADD reg,imm és MOV reg,reg utasítások helyett azok LEA reg,[reg+imm] vagy LEA reg,[reg] megfelelőiket használom, ezek méretre ugyanakkorák, viszont a 3 AGU valamelyikében futnak az ALU-k helyett.

    pushad
    mov ebx,offset(MARKS)
    lea edx,[ebp+ebp]
    xor ecx,ecx
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub edx,04h
    mov [ebx],ecx
    lea ebx,[ebx+04h]
    jg @mark0
    @@REDUCE_ROWS:
    mov [esp+__SYS0],ebp
    mov ebx,ebp
    sub esp,_SAVE
    @rowmin:
    mov ecx,ebp
    mov esi,01000000h
    xor edx,edx
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,01h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,01000000h
    jz @specific
    lea eax,[eax+ebp*04h]
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,01h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    test byte ptr [edi+edx],01h
    jz @mark
    @@ABNORMAL_EXIT:
    add esp,40h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @mark:
    or byte ptr [edi+ebx],10h
    add ecx,ebx
    or byte ptr [edi+edx],01h
    add dword ptr [esp+_SAVE+__SYS0],01h
    mov [edi+ecx],dl
    jz @count_result_STACK
    @reducenxrow:
    add ebx,01h
    jnz @rowmin
    @@RECUDE_COLUMNS:
    neg ebp
    @nxcolmin:
    mov edx,ebp
    sub ebx,01h
    sub eax,04h
    add edx,ebx
    js @@2ND_STEP
    test byte ptr [edi+ebx],01h
    jnz @nxcolmin
    neg ebp
    mov edx,01000000h
    mov ecx,ebp
    @findcolmin:
    cmp edx,[eax]
    cmova edx,[eax]
    add ecx,01h
    lea eax,[eax+ebp*04h]
    jnz @findcolmin
    lea ecx,[ebp-01h]
    neg ebp
    cmp edx,01000000h
    jz @@ABNORMAL_EXIT
    @subcol:
    xor esi,esi
    add ecx,01h
    jz @nxcolmin
    lea eax,[eax+ebp*04h]
    cmp byte ptr [eax+03h],00h
    cmovz esi,edx
    sub [eax],esi
    jnz @subcol
    bts dword ptr [edi+ecx],04h
    jc @subcol
    bts dword ptr [edi+ebx],00h
    lea esi,[ecx+ebp]
    jc @subcol
    add dword ptr [esp+_SAVE+__SYS0],01h
    mov byte ptr [eax+03h],01h
    mov [edi+esi],bl
    jnz @subcol
    jmp @count_result_STACK
    @@3RD_STEP:
    or byte ptr [edi+ebx],02h
    mov byte ptr [esi+03h],02h
    and byte ptr [edi+edx],11111110b
    @@2ND_STEP:
    xor ebx,ebx
    mov esi,[esp+_SAVE+__MTX]
    xor ecx,ecx
    mov edx,00FFFFFFh
    sub ebx,ebp
    @free0:
    sub ecx,ebp
    @freerow:
    test byte ptr [edi+ebx],02h
    jz @zeroinrow
    add ebx,01h
    lea esi,[esi+ebp*04h]
    jnz @freerow
    jmp @@5TH_STEP
    @zeroinrow:
    xor eax,eax
    test byte ptr [edi+ecx],01h
    jnz @nx2col
    add eax,[esi]
    jz @@DECIDE_NEXT_STEP
    cmp edx,eax
    jbe @nx2col
    add esp,_SAVE
    lea edx,[eax] //mov edx,eax
    pushad
    @nx2col:
    add ecx,01h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add ebx,01h
    jnz @free0
    @@5TH_STEP:
    xor ecx,ecx
    mov esi,[esp+_SAVE+__MTX]
    sub ebx,ebp
    @nx5row:
    sub ecx,ebp
    test byte ptr [edi+ebx],02h
    jnz @increase_double_markeds
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,00h
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add ecx,01h
    lea esi,[esi+04h]
    jnz @decrease_row_free
    jmp @step5row
    @increase_double_markeds:
    mov al,[esi+03h]
    and al,11111100b
    bt dword ptr [edi+ecx],00h
    sbb al,00h
    mov eax,00000000h
    cmovc eax,edx
    add [esi],eax
    add ecx,01h
    lea esi,[esi+04h]
    jnz @increase_double_markeds
    @step5row:
    add ebx,01h
    jnz @nx5row
    jmp @@5TH_STEP
    popad
    sub esp,20h
    @@DECIDE_NEXT_STEP:
    mov edx,0FFFFFF00h
    lea eax,[ebx+ebp]
    add dl,[edi+eax]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+_SAVE+__MTX]
    @colon_to_star:
    mov [edi+eax],cl
    add ecx,ebp
    mov byte ptr [esi+03h],01h
    xor eax,eax
    lea esi,[edx+ecx*04h]
    shl ecx,02h
    and byte ptr [edi+ebx],11111101b
    sub eax,ebp
    @search_star_in_column:
    test byte ptr [esi+03h],01h
    jz @nxstar
    cmp eax,ebx
    jnz @0_star
    @nxstar:
    add eax,01h
    lea esi,[esi+ebp*04h]
    jnz @search_star_in_column
    jmp @@1ST_STEP
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    add eax,ebp
    sub esi,ecx
    xor ecx,ecx
    mov byte ptr [edi+eax],00h
    sub ecx,ebp
    @search_colon_in_row:
    test byte ptr [esi+03h],02h
    jnz @colon_to_star
    add ecx,01h
    lea esi,[esi+04h]
    jnz @search_colon_in_row
    @error:
    nop
    @@1ST_STEP:
    xor ebx,ebx
    xor eax,eax
    add dword ptr [esp+_SAVE+__SYS0],01h
    jz @count_result_STACK
    sub ebx,ebp
    mov cl,[edi+00h]
    jmp @nxclear
    @clear_colon:
    and byte ptr [esi+03h],11111101b
    add eax,01h
    lea esi,[esi+04h]
    jnz @clear_colon
    @nxclear:
    sub eax,ebp
    @markedrow:
    test byte ptr [edi+ebx],02h
    mov esi,edx
    mov byte ptr [edi+ebx],00h
    jnz @clear_colon
    add ebx,01h
    lea edx,[edx+ebp*04h]
    jnz @markedrow
    @markcol:
    movsx edx,byte ptr [edi+ebx]
    add eax,01h
    lea ebx,[ebx+01h]
    mov byte ptr [edi+edx],01h
    jnz @markcol
    mov [edi+00h],cl
    jmp @@2ND_STEP
    @count_result_STACK:
    { EDI -> MARKS memory end
    EBP: row/column quantity
    add esp,_SAVE
    xor ecx,ecx
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    movsx edx,byte ptr [edi+ecx]
    lea ecx,[ecx+01h]
    add edx,ebp
    add eax,[esi+edx*04h]
    cmp ecx,ebp
    mov [ebx],dl
    lea esi,[esi+ebp*04h]
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Algoritmusban felhasználásra kihegyezve (több 100000 lefutás); Shanghai-on 1.4 IPC, ezredmásodpercenként legalább 20 db 25x25-ös mátrix megoldása.

    pushad
    mov ebx,offset(MARKS)
    lea ecx,[ebp+ebp]
    xor edx,edx
    lea edi,[ebx+ebp]
    neg ebp
    @mark0:
    sub ecx,04h
    mov [ebx],edx
    lea ebx,[ebx+04h]
    jg @mark0
    @@REDUCE_ROWS:
    mov [esp+__SYS0],ebp
    mov ebx,ebp
    @rowmin:
    mov esi,01000000h
    xor edx,edx
    mov ecx,ebp
    @findrowmin:
    cmp esi,[eax]
    cmovz edx,ecx
    cmova esi,[eax]
    add ecx,01h
    lea eax,[eax+04h]
    jnz @findrowmin
    sub ecx,ebp
    cmp esi,01000000h
    jz @specific
    lea eax,[eax+ebp*04h]
    @subrow:
    xor edx,edx
    cmp byte ptr [eax+03h],00h
    cmovz edx,esi
    sub [eax],edx
    sub ecx,01h
    lea eax,[eax+04h]
    jnz @subrow
    jmp @reducenxrow
    @specific:
    test edx,edx
    jz @@ABNORMAL_EXIT
    test byte ptr [edi+edx],01h
    jz @mark
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @mark:
    or byte ptr [edi+ebx],10h
    add ecx,ebx
    or byte ptr [edi+edx],01h
    add dword ptr [esp+__SYS0],01h
    mov [edi+ecx],dl
    @reducenxrow:
    add ebx,01h
    jnz @rowmin
    @@REDUCE_COLUMNS:
    mov ebx,ebp
    mov esi,[esp+__MTX]
    @colmin:
    mov ecx,ebp
    xor eax,eax
    mov edx,01000000h
    neg ebp
    @findcolmin:
    cmp edx,[esi]
    cmovz eax,ecx
    cmova edx,[esi]
    add ecx,01h
    lea esi,[esi+ebp*04h]
    jnz @findcolmin
    neg ebp
    cmp edx,01000000h
    mov ecx,ebp
    jb @subcol
    test eax,eax
    jz @@ABNORMAL_EXIT
    @subcol:
    lea esi,[esi+ebp*04h]
    xor eax,eax
    cmp byte ptr [esi+03h],00h
    cmovz eax,edx
    sub [esi],eax
    add ecx,01h
    jnz @subcol
    add ebx,01h
    lea esi,[esi+04h]
    jnz @colmin
    mov eax,00000001h
    neg ebp
    @@START0_SYSTEM:
    xor ecx,ecx
    sub esi,04h
    sub ebx,eax
    sub ecx,ebp
    mov edx,esi
    @findfree0:
    cmp [esi],eax
    jb @markitem
    @nxrow:
    add ecx,eax
    lea esi,[esi+ebp*04h]
    jnz @findfree0
    jmp @nxcol
    @markitem:
    bts dword ptr [edi+ecx],04h
    jc @nxrow
    add ecx,ebp
    mov [esi+03h],al
    add [esp+__SYS0],eax
    mov [edi+ecx],bl
    or [edi+ebx],al
    @nxcol:
    lea ecx,[ebx+ebp]
    mov esi,edx
    test ecx,ecx
    jnz @@START0_SYSTEM
    cmp [esp+__SYS0],ecx
    jz @count_result_MTX
    sub esp,_SAVE
    jmp @@2ND_STEP
    @@3RD_STEP:
    mov byte ptr [esi+03h],02h
    and byte ptr [edi+edx],11111110b
    @@2ND_STEP:
    xor ebx,ebx
    mov esi,[esp+_SAVE+__MTX]
    xor ecx,ecx
    mov edx,00FFFFFFh
    sub ebx,ebp
    @free0:
    sub ecx,ebp
    @freerow:
    test byte ptr [edi+ebx],02h
    jz @zeroinrow
    add ebx,01h
    lea esi,[esi+ebp*04h]
    jnz @freerow
    jmp @@5TH_STEP
    @zeroinrow:
    xor eax,eax
    test byte ptr [edi+ecx],01h
    jnz @nx2col
    add eax,[esi]
    jz @@DECIDE_NEXT_STEP
    cmp edx,eax
    cmova edx,eax
    jbe @nx2col
    add esp,_SAVE
    pushad
    @nx2col:
    add ecx,01h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add ebx,01h
    jnz @free0
    @@5TH_STEP:
    xor ecx,ecx
    mov esi,[esp+_SAVE+__MTX]
    sub ebx,ebp
    @nx5row:
    sub ecx,ebp
    test byte ptr [edi+ebx],02h
    jz @decrease_row_free
    @increase_double_markeds:
    mov al,[esi+03h]
    and al,11111100b
    bt dword ptr [edi+ecx],00h
    sbb al,00h
    sbb eax,eax
    and eax,edx
    add [esi],eax
    add ecx,01h
    lea esi,[esi+04h]
    jnz @increase_double_markeds
    jmp @step5row
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,00h
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add ecx,01h
    lea esi,[esi+04h]
    jnz @decrease_row_free
    @step5row:
    add ebx,01h
    jnz @nx5row
    popad
    sub esp,20h
    @@DECIDE_NEXT_STEP:
    mov edx,0FFFFFF00h
    lea eax,[ebx+ebp]
    or byte ptr [edi+ebx],02h
    add dl,[edi+eax]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+_SAVE+__MTX]
    @colon_to_star:
    mov [edi+eax],cl
    add ecx,ebp
    mov byte ptr [esi+03h],01h
    xor eax,eax
    lea esi,[edx+ecx*04h]
    shl ecx,02h
    and byte ptr [edi+ebx],11111101b
    sub eax,ebp
    @search_star_in_column:
    test byte ptr [esi+03h],01h
    jz @nxstar
    cmp eax,ebx
    jnz @0_star
    @nxstar:
    add eax,01h
    lea esi,[esi+ebp*04h]
    jnz @search_star_in_column
    jmp @@1ST_STEP
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    add eax,ebp
    sub esi,ecx
    xor ecx,ecx
    mov byte ptr [edi+eax],00h
    sub ecx,ebp
    @search_colon_in_row:
    test byte ptr [esi+03h],02h
    jnz @colon_to_star
    add ecx,01h
    lea esi,[esi+04h]
    jnz @search_colon_in_row
    @error:
    nop
    @@1ST_STEP:
    xor ebx,ebx
    xor eax,eax
    add dword ptr [esp+_SAVE+__SYS0],01h
    jz @count_result_STACK
    sub ebx,ebp
    mov cl,[edi+00h]
    jmp @nxclear
    @clear_colon:
    and byte ptr [esi+03h],11111101b
    add eax,01h
    lea esi,[esi+04h]
    jnz @clear_colon
    @nxclear:
    sub eax,ebp
    @markedrow:
    test byte ptr [edi+ebx],02h
    mov esi,edx
    mov byte ptr [edi+ebx],00h
    jnz @clear_colon
    add ebx,01h
    lea edx,[edx+ebp*04h]
    jnz @markedrow
    @markcol:
    movsx edx,byte ptr [edi+ebx]
    add ebx,01h
    add eax,01h
    mov byte ptr [edi+edx],01h
    jnz @markcol
    mov [edi+00h],cl
    jmp @@2ND_STEP
    @count_result_STACK:
    add esp,_SAVE
    @count_result_MTX:
    xor ecx,ecx
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    add esp,20h
    @results:
    movsx edx,byte ptr [edi+ecx]
    add ecx,01h
    add edx,ebp
    add eax,[esi+edx*04h]
    cmp ecx,ebp
    mov [ebx],dl
    lea esi,[esi+ebp*04h]
    lea ebx,[ebx+01h]
    jnz @results

  • P.H.

    senior tag

    Magyar módszer, legfejlebb 126x126-os mátrixokra, a mátrixelemek nagysága legfeljebb 00FFFFFFh. A sebességkülönbség kb. 3-szoros az új kód javára úgy, hogy a mátrix teljesen belefér (és belefért régen is) az L1D-be.

    Jelenlegi kód:
    pushad
    @@REDUCE_ROWS:
    mov esi,00FFFFFFh
    mov edi,eax
    mov edx,ebp
    @rowmin:
    mov eax,esi
    mov ebx,edi
    mov ecx,ebp
    @findrowmin:
    cmp eax,[edi]
    cmova eax,[edi]
    sub ecx,01h
    lea edi,[edi+04h]
    jnz @findrowmin
    cmp eax,esi
    mov ecx,ebp
    jz @@ABNORMAL_EXIT
    @decrow:
    xor edi,edi
    cmp [ebx],esi
    cmovbe edi,eax
    sub [ebx],edi
    sub ecx,01h
    lea ebx,[ebx+04h]
    jnz @decrow
    sub edx,01h
    mov edi,ebx
    jnz @rowmin
    jmp @@REDUCE_COLUMNS
    @@ABNORMAL_EXIT:
    add esp,20h
    xor eax,eax
    mov edx,7FFFFFFFh
    stc
    ret
    @@REDUCE_COLUMNS:
    mov ebx,ebp
    mov edi,[esp+__MTX]
    @colmin:
    mov eax,esi
    mov ecx,ebp
    @findcolmin:
    cmp eax,[edi]
    cmova eax,[edi]
    sub ecx,01h
    lea edi,[edi+ebp*04h]
    jnz @findcolmin
    neg ebp
    cmp eax,esi
    mov ecx,ebp
    jz @@ABNORMAL_EXIT
    @deccol:
    lea edi,[edi+ebp*04]
    xor edx,edx
    cmp [edi],esi
    cmovbe edx,eax
    sub [edi],edx
    add ecx,01h
    jnz @deccol
    neg ebp
    sub ebx,01h
    lea edi,[edi+04h]
    jnz @colmin
    @@INITMARKS:
    mov ebx,offset(MARKS)
    lea ecx,[ebp+ebp]
    xor eax,eax
    lea edi,[ebx+ebp]
    mov esi,[esp+__MTX]
    @clrmark:
    sub ecx,04h
    mov [ebx],eax
    lea ebx,[ebx+04h]
    jg @clrmark
    @@START0_SYSTEM:
    xor ebx,ebx
    lea esi,[esi+ebp*04h]
    add eax,01h
    xor ecx,ecx
    @start0system:
    sub esi,04h
    xor edx,edx
    sub ebx,eax
    push esi
    sub edx,ebp
    @findfree0:
    cmp [esi],eax
    jb @markitem
    @nxrow:
    add edx,eax
    lea esi,[esi+ebp*04h]
    jnz @findfree0
    jmp @nxcol
    @markitem:
    bts dword ptr [edi+edx],01h
    jc @nxrow
    add edx,ebp
    mov [esi+03h],al
    add ecx,eax
    mov [edi+edx],bl
    or [edi+ebx],al
    @nxcol:
    lea edx,[ebx+ebp]
    pop esi
    test edx,edx
    jnz @start0system
    mov [esp+__SYS0],ecx
    @@CLEARROWMARKS:
    cmp ebp,ecx
    jz @count_result_MTX
    @clear_row_mark:
    and [edi+ebx],al
    add ebx,eax
    jnz @clear_row_mark
    sub esp,_SAVE
    jmp @@2ND_STEP
    @@3RD_STEP:
    mov byte ptr [esi+03h],02h
    and byte ptr [edi+edx],11111110b
    @@2ND_STEP:
    xor ebx,ebx
    mov esi,[esp+_SAVE+__MTX]
    xor ecx,ecx
    mov edx,00FFFFFFh
    sub ebx,ebp
    @free0:
    sub ecx,ebp
    @freerow:
    test byte ptr [edi+ebx],02h
    jz @zeroinrow
    add ebx,01h
    lea esi,[esi+ebp*04h]
    jnz @freerow
    jmp @@5TH_STEP
    @zeroinrow:
    test byte ptr [edi+ecx],01h
    jnz @handlecol
    cmp edx,[esi]
    jbe @handlecol
    mov edx,[esi]
    test edx,edx
    jz @@DECIDE_NEXT_STEP
    add esp,_SAVE
    pushad
    @handlecol:
    add ecx,01h
    lea esi,[esi+04h]
    jnz @zeroinrow
    add ebx,01h
    jnz @free0
    @@5TH_STEP:
    xor ecx,ecx
    mov esi,[esp+_SAVE+__MTX]
    sub ebx,ebp
    @nx5row:
    sub ecx,ebp
    test byte ptr [edi+ebx],02h
    jz @decrease_row_free
    @increase_double_markeds:
    mov al,[esi+03h]
    and al,11111100b
    bt dword ptr [edi+ecx],00h
    sbb al,00h
    sbb eax,eax
    and eax,edx
    add [esi],eax
    add ecx,01h
    lea esi,[esi+04h]
    jnz @increase_double_markeds
    jmp @step5row
    @decrease_row_free:
    bt dword ptr [edi+ecx],00h
    mov al,[esi+03h]
    adc al,00h
    mov eax,00000000h
    cmovz eax,edx
    sub [esi],eax
    add ecx,01h
    lea esi,[esi+04h]
    jnz @decrease_row_free
    @step5row:
    add ebx,01h
    jnz @nx5row
    popad
    sub esp,20h
    @@DECIDE_NEXT_STEP:
    mov edx,0FFFFFF00h
    lea eax,[ebx+ebp]
    or byte ptr [edi+ebx],02h
    add dl,[edi+eax]
    jnz @@3RD_STEP
    @@4TH_STEP:
    mov edx,[esp+_SAVE+__MTX]
    add dword ptr [esp+_SAVE+__SYS0],01h
    @0colon:
    mov [edi+eax],cl
    add ecx,ebp
    mov byte ptr [esi+03h],01h
    xor eax,eax
    lea esi,[edx+ecx*04h]
    shl ecx,02h
    sub eax,ebp
    @search_star_in_column:
    test byte ptr [esi+03h],01h
    jz @nxstar
    cmp eax,ebx
    jnz @0_star
    @nxstar:
    add eax,01h
    lea esi,[esi+ebp*04h]
    jnz @search_star_in_column
    jmp @@1ST_STEP
    @0_star:
    mov ebx,eax
    mov byte ptr [esi+03h],00h
    add eax,ebp
    sub esi,ecx
    xor ecx,ecx
    mov byte ptr [edi+eax],00h
    sub ecx,ebp
    @search_colon_in_row:
    test byte ptr [esi+03h],02h
    jnz @0colon
    add ecx,01h
    lea esi,[esi+04h]
    jnz @search_colon_in_row
    @error:
    nop
    @@1ST_STEP:
    cmp ebp,[esp+_SAVE+__SYS0]
    jz @count_result_STACK
    lea edx,[edx+ebp*04h]
    push ebp
    @remove_row_marks_set_cols:
    lea esi,[edx-04h]
    sub edi,01h
    xor bl,bl
    mov ecx,ebp
    sub edx,04h
    @chkstarmark:
    mov al,[esi+03h]
    and al,11111101b
    mov [esi+03h],al
    and al,01h
    or bl,al
    sub ecx,01h
    lea esi,[esi+ebp*04h]
    jnz @chkstarmark
    sub dword ptr [esp],01h
    mov [edi],bl
    jnz @remove_row_marks_set_cols
    pop ebx
    add edi,ebp
    jmp @@2ND_STEP
    @count_result_STACK:
    add esp,_SAVE
    @count_result_MTX:
    xor ecx,ecx
    xor eax,eax
    mov esi,[esp+__SAVE]
    mov ebx,[esp+__MARKS]
    @results:
    movsx edx,byte ptr [edi+ecx]
    mov byte ptr [edi+ecx],00h
    add ecx,01h
    add edx,ebp
    add eax,[esi+edx*04h]
    cmp ecx,ebp
    mov [ebx],dl
    lea esi,[esi+ebp*04h]
    lea ebx,[ebx+01h]
    jnz @results

    6-7 évvel ezelőtti kód:
    mov ecx,[mtxdblsize]
    mov edi,[marks]
    xor eax,eax
    mov ebp,[mtxsize]
    mov edx,ecx
    rep stosd
    lea edi,[tempmarks]
    mov ecx,edx
    rep stosd

    @reduce_rows_with_minimum:
    mov edi,[mtx]
    mov edx,ebp
    mov esi,00FFFFFFh
    @row_minimum:
    mov ecx,ebp
    mov ebx,edi
    mov eax,esi
    mov ch,cl
    @find_row_minimum:
    scasd
    jb @after_row_test
    mov eax,[edi-04h]
    @after_row_test:
    dec cl
    jnz @find_row_minimum
    @start_reduce_row:
    test eax,eax
    jnz @force_reduce_row
    dec edx
    jnz @row_minimum
    jmp @reduce_columns_with_m
    @force_reduce_row:
    cmp eax,esi
    jz @abnormal_exit
    @reduce_row_elements:
    cmp [ebx],esi
    ja @after_row_reduction
    sub [ebx],eax
    @after_row_reduction:
    add ebx,04h
    dec ch
    jnz @reduce_row_elements
    dec edx
    jnz @row_minimum

    @reduce_columns_with_minimum
    mov esi,[mtx]
    mov ebx,ebp
    lea edi,[ebp*04h]
    @column_minimum:
    mov ecx,ebp
    mov eax,00FFFFFFh
    mov edx,esi
    mov ch,cl
    @find_column_minimum:
    cmp [esi],eax
    ja @after_column_test
    mov eax,[esi]
    test eax,eax
    jz @next_decrease_column
    @after_column_test:
    add esi,edi
    dec cl
    jnz @find_column_minimum
    @start_reduce_column:
    cmp eax,00FFFFFFh
    jz @abnormal_exit
    mov esi,edx
    @reduce_column_elements:
    cmp dword ptr [esi],00FFFF
    ja @after_column_reduction
    sub [esi],eax
    @after_column_reduction:
    add esi,edi
    dec ch
    jnz @reduce_column_element
    @next_decrease_column:
    lea esi,[edx+04h]
    dec ebx
    jnz @column_minimum

    @determine_start0_system:
    mov [sys0],ebx
    mov edi,[marks]
    mov ebx,ebp
    mov eax,0102h
    mov esi,[mtx]
    xor ecx,ecx
    dec ebx
    push esi
    xor edx,edx
    @start_0system:
    lea esi,[esi+ebx*04h]
    @find_free0:
    test [edi+edx],al
    jnz @check_next_item
    cmp [esi],ecx
    jnz @check_next_item
    or [edi+edx],al
    or [edi+ebx],ah
    or [esi+03h],ah
    inc [sys0]
    jmp @next_column
    @check_next_item:
    inc edx
    lea esi,[esi+ebp*04h]
    cmp edx,ebp
    jnz @find_free0
    @next_column:
    mov esi,[esp]
    xor edx,edx
    dec ebx
    jns @start_0system
    pop ebx

    cmp ebp,[sys0]
    jz @count_result
    mov ecx,[mtxdblsize]
    mov eax,01010101h
    @clear_line_marks:
    and [edi],eax
    add edi,04h
    dec ecx
    jnz @clear_line_marks
    pushad
    jmp @@2nd_step
    @@1st_step:
    mov edi,[marks]
    cmp ebp,[sys0]
    jz @count_result_with_POPA
    mov ebx,ebp
    add edi,ebp
    mov al,0FDh
    lea edx,[edx+ebx*04h-01h]
    dec edi
    @remove_line_marks_set_cols:
    mov esi,edx
    mov [edi],bh
    mov ecx,ebp
    @check_star_mark:
    and [esi],al
    jz @marks_tested
    mov ah,[esi]
    and ah,01h
    or [edi],ah
    @marks_tested:
    lea esi,[esi+ebp*04h]
    dec ecx
    jnz @check_star_mark
    @star_next_column:
    sub edx,04h
    dec edi
    dec ebx
    jnz @remove_line_marks_set
    @@2nd_step:
    mov esi,[mtx]
    mov ecx,ebp
    mov ebx,[marks]
    mov edx,00FFFFFFh
    @search_free0:
    mov edi,[marks]
    xor eax,eax
    mov ch,byte ptr [mtxsize]
    @search_free0_prev_marked:
    test byte ptr [ebx],02h
    jz @look_for_zero
    inc ebx
    dec cl
    jz @@5th_step
    lea esi,[esi+ebp*04h]
    jmp @search_free0_prev_mar
    @look_for_zero:
    test byte ptr [edi],01h
    jnz @handle_column_counter
    cmp edx,[esi]
    jle @handle_column_counter
    mov edx,[esi]
    test edx,edx
    jz @decide_next_step
    add esp,20h
    pushad
    jmp @step_next_item
    @handle_column_counter:
    test byte ptr [esi+03h],01
    jz @step_next_item
    mov eax,edi
    @step_next_item:
    add esi,04h
    inc edi
    dec ch
    jnz @look_for_zero
    inc ebx
    dec cl
    jnz @search_free0
    jmp @@5th_step
    @decide_next_step:
    mov edx,0102h
    or [ebx],dl
    test eax,eax
    jz @continue_search
    @@3rd_step:
    and byte ptr [eax],0FEh
    mov [esi+03h],dl
    jmp @@2nd_step
    @continue_search:
    mov ebx,ecx
    lea eax,[esi+03h]
    dec ch
    jz @@4th_step
    add esi,07h
    inc edi
    @search_0star:
    test [esi],dh
    jz @next_0star_test
    and byte ptr [edi],0FEh
    or [eax],dl
    jmp @@2nd_step
    @next_0star_test:
    add esi,04h
    inc edi
    dec ch
    jnz @search_0star
    @@4th_step:
    or [eax],dh
    xor ecx,ecx
    xor edx,edx
    inc [sys0]
    mov cl,bl
    mov edi,ebp
    mov dl,bh
    sub edi,ecx
    mov ecx,ebp
    mov eax,[mtx]
    lea ebx,[ebp*04h]
    sub ecx,edx
    mov dl,01h
    push eax
    @check_column:
    shl ecx,02h
    lea esi,[eax+ecx+03h]
    xor eax,eax
    @search_star_in_column:
    test [esi],dl
    jz @prepare_for_next_item
    cmp eax,edi
    jnz @found_0_star
    @prepare_for_next_item:
    inc eax
    add esi,ebx
    cmp ebp,eax
    jnz @search_star_in_column
    pop edx
    jmp @@1st_step
    @found_0_star:
    mov byte ptr [esi],00h
    sub esi,ecx
    mov edi,eax
    xor ecx,ecx
    mov eax,0102h
    @search_colon_in_row:
    test [esi],al
    jnz @found_0_colon
    inc ecx
    add esi,04h
    cmp ecx,ebp
    jnz @search_colon_in_row
    @found_0_colon:
    mov [esi],ah
    mov eax,[esp]
    mov dl,01h
    jmp @check_column
    @@5th_step:
    mov esi,[mtx]
    sub ebx,ebp
    mov ecx,ebp
    mov al,01h
    mov ebp,ebx
    add esi,03h
    @decrease_next_row:
    mov ch,[esp+08h]
    mov edi,ebp
    test byte ptr [ebx],02h
    jz @start_decrease_current
    mov ah,0FCh
    @increase_double_markeds:
    test [edi],al
    jz @step_next_element
    test [esi],ah
    jnz @step_next_element
    add [esi-03h],edx
    @step_next_element:
    add esi,04h
    inc edi
    dec ch
    jnz @increase_double_marke
    inc ebx
    dec cl
    jnz @decrease_next_row
    popad
    pushad
    jmp @decide_next_step
    @start_decrease_current_row:
    mov ah,0FFh
    @decrease_current_row:
    test [edi],al
    jnz @jump_next_element
    test [esi],ah
    jnz @jump_next_element
    sub [esi-03h],edx
    @jump_next_element:
    add esi,04h
    inc edi
    dec ch
    jnz @decrease_current_row
    @step_on_next_row:
    inc ebx
    dec cl
    jnz @decrease_next_row
    popad
    pushad
    jmp @decide_next_step
    @count_result_with_POPAD:
    add esp,20h
    @count_result:
    mov esi,[save]
    shl ebp,02h
    mov ebx,edi
    xor ecx,ecx
    mov edi,[mtx]
    mov eax,01000000h
    push edi
    mov edx,[sys0]
    @count_optimum:
    @test_elements:
    scasd
    jnz @test_elements
    @increase_optimum:
    sub edi,04h
    sub edi,[esp]
    add [esp],ebp
    add ecx,[esi+edi]
    add esi,ebp
    shr edi,02h
    mov [ebx],edi
    inc ebx
    dec edx
    mov edi,[esp]
    jnz @count_optimum
    @store_optimum:
    pop eax
    shr ebp,02h
    mov eax,ecx

  • P.H.

    senior tag

    Közismert és általános algoritmushoz tartozó kód legalább 6-7 éve és ma

    Első rész, a főciklus előtti inicializációs részek:

    Régen:
    mov ecx,[MTXDBLSIZE]
    mov edi,[MARKS]
    xor eax,eax
    mov ebp,[MTXSIZE]
    mov edx,ecx
    rep stosd
    lea edi,[tempmarks]
    mov ecx,edx
    rep stosd

    @reduce_rows_with_minimum:
    mov edi,[mtx]
    mov edx,ebp
    mov esi,00FFFFFFh
    @row_minimum:
    mov ecx,ebp
    mov ebx,edi
    mov eax,esi
    mov ch,cl
    @find_row_minimum:
    scasd
    jb @after_row_test
    mov eax,[edi-04h]
    @after_row_test:
    dec cl
    jnz @find_row_minimum
    @start_reduce_row:
    test eax,eax
    jnz @force_reduce_row
    dec edx
    jnz @row_minimum
    jmp @reduce_columns_with_minimum
    @force_reduce_row:
    cmp eax,esi
    jz @abnormal_exit
    @reduce_row_elements:
    cmp [ebx],esi
    ja @after_row_reduction
    sub [ebx],eax
    @after_row_reduction:
    add ebx,04h
    dec ch
    jnz @reduce_row_elements
    dec edx
    jnz @row_minimum

    @reduce_columns_with_minimum:
    mov esi,[mtx]
    mov ebx,ebp
    lea edi,[ebp*04h]
    @column_minimum:
    mov ecx,ebp
    mov eax,00FFFFFFh
    mov edx,esi
    mov ch,cl
    @find_column_minimum:
    cmp [esi],eax
    ja @after_column_test
    mov eax,[esi]
    test eax,eax
    jz @next_decrease_column
    @after_column_test:
    add esi,edi
    dec cl
    jnz @find_column_minimum
    @start_reduce_column:
    cmp eax,00FFFFFFh
    jz @abnormal_exit
    mov esi,edx
    @reduce_column_elements:
    cmp dword ptr [esi],00FFFFFFh
    ja @after_column_reduction
    sub [esi],eax
    @after_column_reduction:
    add esi,edi
    dec ch
    jnz @reduce_column_elements
    @next_decrease_column:
    lea esi,[edx+04h]
    dec ebx
    jnz @column_minimum

    @determine_start0_system:
    mov [sys0],ebx
    mov edi,[marks]
    mov ebx,ebp
    mov eax,0102h
    mov esi,[mtx]
    xor ecx,ecx
    dec ebx
    push esi
    xor edx,edx
    @start_0system:
    lea esi,[esi+ebx*04h]
    @find_free0:
    test [edi+edx],al
    jnz @check_next_item
    cmp [esi],ecx
    jnz @check_next_item
    or [edi+edx],al
    or [edi+ebx],ah
    or [esi+03h],ah
    inc [sys0]
    jmp @next_column
    @check_next_item:
    inc edx
    lea esi,[esi+ebp*04h]
    cmp edx,ebp
    jnz @find_free0
    @next_column:
    mov esi,[esp]
    xor edx,edx
    dec ebx
    jns @start_0system
    pop ebx

    cmp ebp,[sys0]
    jz @count_result
    mov eax,01010101h
    mov ecx,[MTXDBLSIZE]
    @clearrowmark:
    and [edi],eax
    sub ecx,01h
    lea edi,[edi+04h]
    jnz @clearrowmark
    pushad
    jmp @@2nd_step

    Mai termés (kb. 10% gyorsulás a teljes lefutásra vetítve)
    mov ebp,[MTXSIZE]
    @reduce_rows_with_minimum:
    mov esi,00FFFFFFh
    mov edi,[MTX]
    mov edx,ebp
    @rowmin:
    mov eax,esi
    mov ebx,edi
    mov ecx,ebp
    @findrowmin:
    cmp eax,[ebx]
    jb @nxrowmin
    mov eax,[ebx]
    @nxrowmin:
    sub ecx,01h
    lea ebx,[ebx+04h]
    jnz @findrowmin
    cmp eax,esi
    mov ecx,ebp
    jz @abnormal_exit
    @decrow:
    cmp [edi],esi
    sbb ebx,ebx
    and ebx,eax
    sub [edi],ebx
    sub ecx,01h
    lea edi,[edi+04h]
    jnz @decrow
    sub edx,01h
    jnz @rowmin

    @reduce_columns_with_minimum:
    mov ebx,ebp
    shl ebp,02h
    mov edi,[MTX]
    @colmin:
    mov ecx,ebp
    mov eax,esi
    @findcolmin:
    cmp [edi],eax
    ja @nxcolmin
    mov eax,[edi]
    @nxcolmin:
    sub ecx,04h
    lea edi,[edi+ebp]
    jnz @findcolmin
    neg ebp
    cmp eax,esi
    mov ecx,ebp
    jz @abnormal_exit
    @deccol:
    add edi,ebp
    cmp [edi],esi
    sbb edx,edx
    and edx,eax
    sub [edi],edx
    add ecx,04h
    jnz @deccol
    neg ebp
    sub ebx,01h
    lea edi,[edi+04h]
    jnz @colmin
    shr ebp,02h

    imul ecx,[MTXDBLSIZE],BYTE(4)
    xor eax,eax
    mov edi,[MARKS]
    mov edx,offset(TEMPMARKS)
    mov esi,[MTX]
    @clrmark:
    sub ecx,04h
    mov [edi+ecx],eax
    mov [edx+ecx],eax
    jg @clrmark

    @determine_start0_system:
    lea ebx,[ebp-01h]
    add eax,01h
    push esi
    @start0system:
    lea esi,[esi+ebx*04h]
    xor edx,edx
    @findfree0:
    cmp dword ptr [esi],00h
    jz @markitem
    @nxrow:
    add edx,eax
    lea esi,[esi+ebp*04h]
    cmp edx,ebp
    jnz @findfree0
    jmp @nxcol
    @markitem:
    bts [edi+edx],eax
    jc @nxrow
    or [edi+ebx],al
    add ecx,eax
    or [esi+03h],al
    @nxcol:
    sub ebx,eax
    mov esi,[esp]
    jns @start0system
    pop ebx
    mov [SYS0],ecx

    cmp ebp,ecx
    mov eax,01010101h
    jz @count_result
    mov ecx,[MTXDBLSIZE]
    @clearrowmark:
    and [edi],eax
    sub ecx,01h
    lea edi,[edi+04h]
    jnz @clearrowmark
    pushad
    jmp @@2nd_step

  • P.H.

    senior tag

    Pufferenként 1-1 előre elindított végtelenített szál + pufferenként 2 event:
    - Erase: automatikusan resetelt, 0 kezdőértékkel
    - Ready: kézileg resetelt, 0 kezdőértékkel

    procedure _ZTHREAD;
    { [ESP+04h]: TBUFFER address
    asm mov edx,[esp+04h]
    pushad
    mov edi,[edx+TBUFFER.BIT]
    mov esi,edx
    mov ebp,[edx+TBUFFER.ERASE]
    mov ebx,offset(BUFFERS)
    xor edi,-1
    @loop:
    push INFINITE; push ebp; call WINDOWS.WAITFORSINGLEOBJECT
    mov eax,[esi+TBUFFER.ADDR]; mov edx,[esi+TBUFFER.SIZE]; call _ZEROMEM
    push dword ptr [esi+TBUFFER.READY]; call WINDOWS.SETEVENT
    lock and [ebx+_LOCKBITS],edi
    lock and [ebx+_PENDINGS],edi
    jmp @loop
    popad
    ret 04h end;
    procedure _FREEBUFFER(Value:pHGLOBAL);
    asm mov edx,eax
    xor ecx,ecx
    mov eax,[eax]
    mov [edx],ecx
    mov cl,cBUFFER
    test eax,eax
    mov edx,offset(BUFFERS)
    jz @return
    @search:
    sub cl,01h
    lea edx,[edx+TBUFFERSIZE]
    js @error
    cmp eax,[edx+TBUFFER.ADDR]
    jnz @search
    @freebuffer:
    cmp byte ptr [_INSSET+__CPUs],01h
    mov ecx,[edx+TBUFFER.BIT]
    jbe @oneCPU
    lock or dword ptr [BUFFERS+_PENDINGS],ecx
    push dword ptr [edx+TBUFFER.ERASE]; call WINDOWS.SETEVENT
    ret
    @oneCPU:
    xor ecx,-1
    mov eax,[edx+TBUFFER.ADDR]; mov edx,[edx+TBUFFER.SIZE]
    and dword ptr [BUFFERS+_LOCKBITS],ecx
    jmp _ZEROMEM
    @error:
    mov eax,[_NOFREE]
    jmp ERRORFORM
    @return: end;
    procedure _RESTARTBUFFERS;
    asm pushad
    mov edx,offset(BUFFERS); or ecx,-1
    xor edi,edi
    mov eax,[edx+_PENDINGS]; call _WAITFORBUFFER
    mov esi,edx
    mov ebp,[edx+_LOCKBITS]
    mov bl,cBUFFER
    mov [edx+_LOCKBITS],edi
    mov [edx+_PENDINGS],edi
    add edi,01h
    @search:
    sub bl,01h
    lea esi,[esi+TBUFFERSIZE]
    js @return
    test ebp,edi
    lea edi,[edi+edi]
    jz @search
    mov eax,[esi+TBUFFER.ADDR]; mov edx,[esi+TBUFFER.SIZE]; call _ZEROMEM
    jmp @search
    @return:
    popad end;
    function _WAITFORBUFFER: DWORD;
    asm test eax,eax
    pushad
    mov edi,ecx
    mov ebx,esp
    jz @return
    xor ebp,ebp
    @threadarray:
    shr eax,01h
    lea edx,[edx+TBUFFERSIZE]
    jnc @threadarray
    lea ebp,[ebp+01h]
    push dword ptr [edx+TBUFFER.READY]
    jnz @threadarray
    mov edx,esp
    push INFINITE; push edi; push edx; push ebp; call WINDOWS.WAITFORMULTIPLEOBJECTS
    mov esp,ebx
    @return:
    popad
    test eax,eax end;
    function _GETBUFFER(Dest:pHGLOBAL): HGLOBAL;
    asm pushad
    mov esi,offset(BUFFERS)
    mov edi,eax
    @testbuffers:
    mov ebp,[esi+_LOCKBITS]
    mov ebx,00000001h
    mov edx,esi
    mov cl,cBUFFER
    mov eax,[esi+_PENDINGS]
    @search:
    test ebp,ebx
    lea esi,[esi+TBUFFERSIZE]
    jz @lock
    sub cl,01h
    lea ebx,[ebx+ebx]
    jg @search
    cmp ebp,[edx+_LOCKBITS]
    mov esi,edx
    jnz @testbuffers
    xor ecx,ecx; call _WAITFORBUFFER
    jnz @testbuffers
    @error:
    mov eax,[_NOGET]; call ERRORFORM
    xor ebx,ebx
    mov edx,esi
    @lock:
    mov eax,[esi+TBUFFER.ADDR]
    lock or [edx+_LOCKBITS],ebx
    mov [edi],eax
    push dword ptr [esi+TBUFFER.READY]; call WINDOWS.RESETEVENT
    popad
    mov eax,[eax] end;

  • P.H.

    senior tag

    Többszálú pufferkezelési kód. Lehetne jobb is... (?)

    function _WAITTHREADS: DWORD;
    asm test eax,eax
    pushad
    mov ebx,esp
    jz @return
    xor ebp,ebp
    @threadarray:
    shr eax,01h
    lea edx,[edx+TBUFFERSIZE]
    jnc @threadarray
    lea ebp,[ebp+01h]
    push dword ptr [edx+TBUFFER.THREAD]
    jnz @threadarray
    mov edx,esp
    push INFINITE; push ecx; push edx; push ebp; call WINDOWS.WAITFORMULTIPLEOBJECTS
    mov esp,ebx
    @return:
    popad
    test eax,eax end;
    procedure _RESTARTBUFFERS;
    asm pushad
    mov edx,offset(BUFFERS)
    mov bl,cBUFFER
    xor ebp,ebp
    mov eax,[PENDINGS]; mov ecx,01h; sub edx,TBUFFERSIZE; call _WAITTHREADS
    mov esi,edx
    mov edi,eax
    @init:
    sub bl,cl
    lea esi,[esi+TBUFFERSIZE]
    js @return
    shr edi,cl
    jc @init
    mov edx,esi; call _BUF0
    jmp @init
    @return:
    mov [PENDINGS],ebp
    mov [LOCKBITS],ebp
    popad end;
    procedure _ZEROBUFFER(Blank,Buffer:pointer);
    asm cmp byte ptr [_INSSET+__CPUS],01h
    mov ecx,[edx+TBUFFER.BIT]
    ja @moreCPU
    xor ecx,-1
    and [LOCKBITS],ecx
    jmp _BUF0
    @moreCPU:
    push ebx
    lea ebx,[edx+TBUFFER.THREAD]
    lock or [PENDINGS],ecx
    push ebx; push 00h; push edx; push offset(@ZTHREAD); push 60h; push 00h; call CREATETHREAD
    mov [ebx],eax
    pop ebx
    ret
    @ZTHREAD:
    { ESP+04h: TBUFFER structure
    mov edx,[esp+04h]
    or ecx,-1
    xor ecx,[edx+TBUFFER.BIT]
    call _BUF0
    lock and [LOCKBITS],ecx
    lock and [PENDINGS],ecx
    ret 04h end;
    procedure _FREEBUFFER(Value:pHGLOBAL);
    asm mov edx,eax
    xor ecx,ecx
    mov eax,[eax]
    mov [edx],ecx
    test eax,eax
    mov edx,offset(BUFFERS)
    jz @return
    @search:
    cmp eax,[edx+TBUFFER.ADDR]
    jz _ZEROBUFFER
    add ecx,01h
    add edx,TBUFFERSIZE
    cmp ecx,cBUFFER
    jb @search
    mov eax,[_NOFREE]
    jmp ERRORFORM
    @return: end;
    function _GETBUFFER(Dest:pHGLOBAL): HGLOBAL;
    asm pushad
    mov esi,offset(BUFFERS)
    mov edi,_hINV
    sub esi,TBUFFERSIZE
    @testbuffers:
    mov ebp,[LOCKBITS]
    mov ebx,00000001h
    mov edx,esi
    mov cl,cBUFFER
    mov eax,[PENDINGS]
    @search:
    test ebp,ebx
    lea edx,[edx+TBUFFERSIZE]
    jz @lock
    sub cl,01h
    lea ebx,[ebx+ebx]
    jg @search
    xor ecx,ecx; call _WAITTHREADS
    jnz @testbuffers
    popad
    mov eax,[_NOGET]; call ERRORFORM
    xor eax,eax
    ret
    @lock:
    mov esi,[esp+_EAX]
    mov eax,[edx+TBUFFER.ADDR]
    mov ecx,[edx+TBUFFER.THREAD]
    mov [edx+TBUFFER.THREAD],edi
    mov [esi],eax
    lock or [LOCKBITS],ebx
    push ecx; call WINDOWS.CLOSEHANDLE
    popad
    mov eax,[eax] end;

  • P.H.

    senior tag

    Valamiért a K8 is jobban szereti, ha az utasítások konstans paramétere nem azonnali érték, hanem regiszter, az előforduló függőségek ellenére is; talán az utasításhossz-csökkenés miatt? (a Netburst-ön még jobban kijön a plusz, ennek a trace-cache felépítése lehet az oka)

    K8-on még 1% van benne, egy-egy felesleges, de csak ritkán lefutó utasítás eltávolításával és egy ugráscél áthelyezésével: 513M clock

    gépi kód:

    @copyarraySSE:
    movd xmm0,[eax+04h] 660F6E4004
    @zoomvertSSE:
    mov [esp],edi 893C24
    xor ebx,ebx 31DB
    mov esi,[esp+_STRROWS] 8B74242C
    and edi,-64 83E7C0
    sub edx,[esp+_STRLEFT] 2B542430
    movd ebp,mm7 0F7EFD
    pshufd xmm0,xmm0,00000000b 660F70C000
    movd ecx,mm6 0F7EF1
    lea edi,[edi+40h] 8D7F40
    mov esi,[esi] 8B36
    cmovge edx,ebx 0F4DD3
    movaps xmm1,[edi] 0F280F
    @sourceLEFT:
    mov bl,[esi] 8A1E
    add esi,02h 83C602
    add edx,ebx 01DA
    jle @sourceLEFT 7EF7
    mov bl,[esi-01h] 8A5EFF
    jmp @initpixelSSE EB09
    @newpixelSSE:
    movzx edx,word ptr [esi] 0FB716
    add esi,02h 83C602
    movzx ebx,dh 0FB6DE
    @initpixelSSE:
    movaps xmm3,xmm0 0F28D8
    shl ebx,04h C1E304
    add ebx,[esp+_STRCOLORS] 035C2428
    mulps xmm3,[ebx] 0F591B
    @prevHpixelSSE:
    sub dl,01h 80EA01
    jc @newpixelSSE 72E5
    pshufd xmm2,[ecx+00h],10010101b 660F701195
    movaps xmm4,xmm3 0F28E3
    mov ebx,[ecx+00h] 8B19
    @pixelSSE:
    mulps xmm4,xmm2 0E59E2
    sub ebx,01h 83EB01
    @1pixelSSE:
    addps xmm1,xmm4 0F58CC
    jz @nextHpixelSSE 7413
    movaps [edi],xmm1 0F290F
    js @stepHelementSSE 781A
    add edi,10h 83C710
    movaps xmm4,xmm3 0F28E3
    sub ebx,01h 83EB01
    movaps xmm1,[edi] 0F280F
    jnz @1pixelSSE 75E8
    @nextHpixelSSE:
    pshufd xmm2,xmm2,11111111b 660F70D2FF
    cmp ebx,[ecx+08h] 3B5908
    jnz @pixelSSE 75D8
    not ebx F7D3
    @stepHelementSSE:
    add ebp,ebx 01DD
    lea ecx,[ecx+10h] 8D4910
    jnz @prevHpixelSSE 75C0
    mov edi,[esp] 8B3C24
    xor edx,edx 31D2
    add [eax+00h],ebx 0118
    jg @cvtROW 7F26
    jl @stepVelementSSE 7C0F
    @moreVrowsSSE:
    mov [eax+00h],edx 8910
    add ebp,[eax+08h] 036808
    movd xmm0,ebp 660F6EC5
    jnz @zoomvertSSE 0F855CFFFFFF
    @stepVelementSSE:
    add dword ptr [esp+_STRROWS],04h 8344244C04
    add [esp+_VSIZE],ebx 015C2414
    lea eax,[eax+10h] 8D4010
    jnz @copyarraySSE 0F8545FFFFFF
    sub eax,10h 83E810
    @cvtROW:
    mov esi,edi 89FE
    mov ebp,[esp+_INCREASE] 8B6C2418
    and esi,-64 83E6C0
    sub edi,ebp 29EF
    @cvtRGB:
    add esi,40h 83C640
    cvtps2dq xmm1,[esi+00h] 660F5B0E
    cvtps2dq xmm2,[esi+10h] 660F5B5610
    cvtps2dq xmm3,[esi+20h] 660F5B5E20
    cvtps2dq xmm4,[esi+30h] 660F5B6630
    movaps [esi+00h],xmm5 0F290E
    packssdw xmm1,xmm2 660F6BC6
    movaps [esi+10h],xmm5 0F296E10
    packssdw xmm3,xmm4 660F0BCD
    movaps [esi+20h],xmm5 0F296E20
    packuswb xmm1,xmm3 660F67CB
    movaps [esi+30h],xmm5 0F296E30
    movups [edi+ebp],xmm1 0F110C2F
    add ebp,10h 83C510
    js @cvtRGB 78C6
    add ebx,[eax+00h] 0318
    jz @moreVrowsSSE 7493
    divss xmm0,xmm0 F30F5EC0
    jg @zoomvertSSE 0F8FF4FEFFFF

  • P.H.

    senior tag

    SSE2-kód AMD-re egy kicsit kevesebb utasítással, kis utasítássorrend-módosítással (körvonalazódik, hogy VectorPath célszerűen feltételes ugrás után vagy ugrás céljaként rendezendő)

    K8 Opteron: 517M clock (-10%), átlagosan 1.3 IPC

    @copyarraySSE:
    movd xmm0,[eax+04h]
    @zoomvertSSE:
    mov [esp],edi
    xor ebx,ebx
    mov esi,[esp+_STRROWS]
    and edi,-64
    sub edx,[esp+_STRLEFT]
    movd ebp,mm7
    pshufd xmm0,xmm0,00000000b
    movd ecx,mm6
    lea edi,[edi+40h]
    mov esi,[esi]
    cmovge edx,ebx
    movaps xmm1,[edi]
    @sourceLEFT:
    mov bl,[esi]
    add esi,02h
    add edx,ebx
    jle @sourceLEFT
    mov bl,[esi-01h]
    jmp @initpixelSSE
    @newpixelSSE:
    movzx edx,word ptr [esi]
    add esi,02h
    movzx ebx,dh
    @initpixelSSE:
    movaps xmm3,xmm0
    shl ebx,04h
    add dl,01h
    add ebx,[esp+_STRCOLORS]
    mulps xmm3,[ebx]
    @prevHpixelSSE:
    sub dl,01h
    jz @newpixelSSE
    pshufd xmm2,[ecx+00h],10010101b
    movaps xmm4,xmm3
    mov ebx,[ecx+00h]
    @pixelSSE:
    mulps xmm4,xmm2
    sub ebx,01h
    @1pixelSSE:
    addps xmm1,xmm4
    jz @nextHpixelSSE
    movaps [edi],xmm1
    js @stepHelementSSE
    add edi,10h
    movaps xmm4,xmm3
    sub ebx,01h
    movaps xmm1,[edi]
    jnz @1pixelSSE
    @nextHpixelSSE:
    pshufd xmm2,xmm2,11111111b
    cmp ebx,[ecx+08h]
    jnz @pixelSSE
    not ebx
    @stepHelementSSE:
    add ebp,ebx
    lea ecx,[ecx+10h]
    jnz @prevHpixelSSE
    mov edi,[esp]
    xor edx,edx
    @moreVrowsSSE:
    add [eax+00h],ebx
    jg @cvtROW
    jl @stepVelementSSE
    add ebp,[eax+08h]
    movd xmm0,ebp
    jnz @zoomvertSSE
    @stepVelementSSE:
    add dword ptr [esp+_STRROWS],04h
    add [esp+_VSIZE],ebx
    lea eax,[eax+10h]
    jnz @copyarraySSE
    sub eax,10h
    mov [eax+00h],ebx
    @cvtROW:
    mov esi,edi
    mov ebp,[esp+_INCREASE]
    and esi,-64
    sub edi,ebp
    @cvtRGB:
    add esi,40h
    cvtps2dq xmm1,[esi+00h]
    cvtps2dq xmm2,[esi+10h]
    cvtps2dq xmm3,[esi+20h]
    cvtps2dq xmm4,[esi+30h]
    movaps [esi+00h],xmm5
    packssdw xmm1,xmm2
    movaps [esi+10h],xmm5
    packssdw xmm3,xmm4
    movaps [esi+20h],xmm5
    packuswb xmm1,xmm3
    movaps [esi+30h],xmm5
    movups [edi+ebp],xmm1
    add ebp,10h
    js @cvtRGB
    cmp dword ptr [eax+00h],01h
    jz @moreVrowsSSE
    divss xmm0,xmm0
    jg @zoomvertSSE

  • P.H.

    senior tag

    Perfmonitor: x87-kód - K10.5 - végtelen ciklusban

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Instructions per cycle (IPC) (átlag: 2.1 IPC)
    Counter 2 : Retired x87 instructions
    Counter 3 : Retired uops (átlag: 2.16 uop/cycle)

    T(ms) c0(M/s) c1(i/c) c2(M/s) c3(M/s)
    50 3285.4 2.2 3529.4 7076.8
    100 3063.2 2.0 3099.1 6264.5
    150 3284.3 2.2 3543.0 7099.7
    200 3188.5 2.1 3319.6 6680.5
    250 3272.3 2.1 3450.2 6938.7
    300 3255.9 2.2 3497.3 7011.3
    350 3173.4 2.0 3247.4 6558.3
    400 3285.2 2.1 3496.2 7020.2
    450 3133.1 2.0 3214.7 6477.7
    500 3241.0 2.1 3432.2 6899.0
    550 3162.5 2.1 3294.7 6630.9
    600 3282.7 2.1 3463.3 6967.7
    650 3143.3 2.0 3247.2 6534.4
    700 3279.9 2.1 3463.5 6966.5
    750 3168.5 2.1 3330.2 6697.5
    800 3160.7 2.1 3303.5 6645.5
    850 3257.3 2.1 3398.0 6837.9
    900 3286.2 2.1 3517.0 7055.1
    950 3156.7 2.0 3244.1 6546.1
    1000 3286.9 2.1 3495.6 7020.8
    1050 3147.3 2.0 3259.4 6566.0
    1100 3284.1 2.1 3478.9 6992.5
    1150 3157.7 2.0 3279.2 6601.2
    1200 3282.2 2.1 3461.4 6964.0
    1250 3142.5 2.0 3248.9 6537.4
    1300 3248.4 2.1 3428.5 6896.7
    1350 3168.8 2.0 3285.2 6617.9
    1400 3276.6 2.1 3488.3 7006.2
    1450 3160.6 2.0 3217.0 6490.4
    1500 3283.6 2.2 3526.5 7071.4
    1550 3164.2 2.0 3229.8 6524.4
    1600 3280.5 2.2 3538.5 7090.2
    1650 3160.1 2.0 3219.3 6506.2
    1700 3277.7 2.2 3538.4 7089.3
    1750 3227.3 2.1 3442.4 6909.4
    1800 3140.5 2.0 3214.9 6486.7
    1850 3284.8 2.1 3499.9 7027.2
    1900 3164.0 2.0 3272.6 6594.4
    1950 3246.3 2.1 3346.8 6746.4
    2000 3283.9 2.2 3539.6 7093.4

    Perfmonitor: SSE2-kód - K10.5 - végtelen ciklusban
    (ott fut a tisztán kód, ahol a counter 2 oszlop 0.0)

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Instructions per cycle (IPC) (átlag: 1.7 IPC)
    Counter 2 : Retired x87 instructions
    Counter 3 : Retired uops (átlag: 1.67 uop/cycle)

    T(ms) c0(M/s) c1(i/c) c2(M/s) c3(M/s)
    50 3110.8 1.7 0.0 5212.7
    100 3119.8 1.6 219.1 5110.6
    150 3138.6 1.6 195.4 5217.6
    200 3280.6 1.6 23.5 5409.9
    250 3163.5 1.6 219.1 5193.5
    300 3291.7 1.7 0.0 5519.1
    350 3125.2 1.6 219.4 5141.1
    400 3299.2 1.7 0.0 5514.0
    450 3175.4 1.6 218.8 5266.7
    500 3279.5 1.7 0.0 5465.3
    550 3145.7 1.6 219.0 5146.2
    600 3296.9 1.7 0.0 5542.1
    650 3172.3 1.6 218.8 5205.1
    700 3172.6 1.6 218.7 5211.1
    750 3275.5 1.7 0.0 5503.3
    800 3167.4 1.6 220.0 5211.2
    850 3296.8 1.7 0.0 5519.2
    900 3146.2 1.6 219.0 5161.8
    950 3299.9 1.7 0.0 5507.0
    1000 3157.2 1.6 218.6 5227.3
    1050 3300.9 1.7 0.0 5518.8
    1100 3175.5 1.6 218.9 5230.2
    1150 3200.4 1.6 141.9 5361.2
    1200 3227.2 1.6 77.2 5275.1
    1250 3167.0 1.6 218.9 5195.1
    1300 3294.7 1.7 0.0 5516.8
    1350 3159.2 1.6 218.8 5212.8
    1400 3298.6 1.7 0.0 5512.2
    1450 3169.7 1.6 218.9 5254.5
    1500 3300.2 1.7 0.0 5509.1
    1550 3089.0 1.6 216.1 5077.3
    1600 3297.4 1.7 0.0 5527.0
    1650 3173.8 1.6 219.0 5221.7
    1700 3137.5 1.6 217.2 5211.7
    1750 3293.4 1.7 1.6 5442.9
    1800 3157.7 1.6 218.7 5185.6
    1850 3292.4 1.7 0.0 5518.1
    1900 3142.9 1.6 219.0 5171.3
    1950 3298.1 1.7 0.0 5506.7
    2000 3174.0 1.6 218.8 5261.2

  • P.H.

    senior tag

    Perfmonitor: x87-kód - K8 - végtelen ciklusban

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Instructions per cycle (IPC) (átlag: 1.6 IPC)
    Counter 2 : Retired x87 instructions
    Counter 3 : Retired uops (átlag: 1.67 uop/cycle)

    T(ms) c0(M/s) c1(i/c) c2(M/s) c3(M/s)
    50 2147.3 1.7 1764.7 3557.5
    100 2144.6 1.7 1789.1 3574.9
    150 2148.1 1.6 1743.1 3523.0
    200 2144.3 1.6 1737.0 3516.0
    250 2145.9 1.6 1749.0 3534.2
    300 1951.9 1.5 1518.6 3068.6
    350 1951.9 1.5 1518.6 3068.6
    400 2166.6 1.6 1784.2 3573.8
    450 2145.0 1.6 1740.0 3515.3
    500 2148.4 1.6 1739.3 3521.1
    550 2080.0 1.7 1728.9 3469.3
    600 2080.0 1.7 1728.9 3469.3
    650 2174.7 1.7 1815.4 3625.6
    700 2146.9 1.6 1735.7 3510.5
    750 2153.0 1.6 1739.5 3522.5
    800 2146.5 1.7 1776.5 3573.7
    850 2146.5 1.7 1776.5 3573.7
    900 2161.3 1.7 1810.6 3611.2
    950 2145.1 1.6 1735.2 3509.7
    1000 2143.9 1.6 1736.8 3513.5
    1050 2149.8 1.7 1766.1 3560.8
    1100 1901.3 1.4 1373.4 2820.3
    1150 1901.3 1.4 1373.4 2820.3
    1200 2170.7 1.6 1773.8 3565.8
    1250 2149.7 1.6 1745.0 3526.8
    1300 2146.6 1.6 1754.7 3542.4
    1350 1917.8 1.4 1437.8 2919.8
    1400 1917.8 1.4 1437.8 2919.8
    1450 2175.2 1.7 1794.4 3596.8
    1500 2143.4 1.6 1739.3 3513.9
    1550 2146.2 1.6 1739.8 3521.4
    1600 2007.6 1.6 1621.3 3281.0
    1650 2007.6 1.6 1621.3 3281.0
    1700 2168.2 1.7 1806.2 3609.1
    1750 2147.8 1.6 1742.8 3521.1
    1800 2146.3 1.6 1732.0 3508.8
    1850 2148.4 1.7 1782.0 3582.2
    1900 1912.0 1.4 1362.6 2799.5
    1950 1912.0 1.4 1362.6 2799.5
    2000 2173.2 1.6 1776.2 3570.1

    Perfmonitor: SSE2-kód - K8 - végtelen ciklusban
    (ott fut a kód, ahol a counter 2 oszlop 0.0)

    PerfMonitor Record file
    Counter 0 : Non-halted clock cycles
    Counter 1 : Instructions per cycle (IPC) (átlag: 1.2 IPC)
    Counter 2 : Retired x87 instructions
    Counter 3 : Retired uops (átlag: 1.89 uop/cycle)

    T(ms) c0(M/s) c1(i/c) c2(M/s) c3(M/s)
    50 2144.4 1.2 0.0 3937.9
    100 2124.2 1.2 0.0 3932.0
    150 2124.2 1.2 0.0 3932.0
    200 2163.4 1.3 0.0 4087.8
    250 2151.2 1.2 0.0 3928.3
    300 2148.1 1.2 0.0 3949.5
    350 2150.4 1.3 0.0 4026.4
    400 2150.4 1.3 0.0 4026.4
    450 2113.7 1.3 0.0 3985.9
    500 2145.0 1.2 0.0 3944.8
    550 2140.1 1.2 0.0 3936.2
    600 1997.1 1.2 91.2 3642.2
    650 1997.1 1.2 91.2 3642.2
    700 2169.1 1.2 0.0 4043.4
    750 2145.4 1.2 0.0 3945.1
    800 2145.3 1.2 0.0 3987.8
    850 1915.7 1.1 269.3 3111.7
    900 2146.0 1.3 0.0 4045.9
    950 2146.0 1.3 0.0 4045.9
    1000 2170.9 1.2 0.0 4005.7
    1050 2141.6 1.3 0.0 4013.2
    1100 1906.3 1.1 269.3 3077.8
    1150 2148.3 1.3 0.0 4031.8
    1200 2148.3 1.3 0.0 4031.8
    1250 2170.4 1.2 0.0 3984.1
    1300 1972.1 1.2 140.0 3523.7
    1350 2086.6 1.2 129.3 3613.1
    1400 2144.9 1.2 0.0 3973.6
    1450 2144.9 1.2 0.0 3973.6
    1500 2163.4 1.2 0.0 4044.9
    1550 1376.2 1.1 128.3 2225.5
    1600 2077.9 1.2 141.0 3582.1
    1650 2149.2 1.2 0.0 3983.2
    1700 2150.4 1.2 0.0 3957.1
    1750 2150.4 1.2 0.0 3957.1
    1800 1931.8 1.1 269.2 3197.0
    1850 2151.3 1.3 0.0 4054.5
    1900 2148.0 1.2 0.0 3947.1
    1950 2142.7 1.2 0.0 3929.8
    2000 2142.7 1.2 0.0 3929.8

  • P.H.

    senior tag

    A dolog befejettnek tekinthető, végső stat:

    - SSE2-kód Prescott CeleronD + DDR: 630M clock
    - SSE2-kód Northwood Celeron + SDRAM: 635M clock
    - SSE2-kód K8 Opteron + DDR2: 585M clock
    - SSE1-kód P3 Coppermine + SDRAM: 670M clock
    - x87-kód Prescott CeleronD + DDR: 950M clock
    - x87-kód K8 Opteron + DDR2: 590M clock

  • P.H.

    senior tag

    Azt hiszem, elérhetetlen céljaim egyike, hogy a Netburst-öt megértsem...

    Prescott CeleronD: 630M clock (-4%)
    K8 Opteron: 585M clock (+4%)

    Csupán két utasítás sorrendjének felcserélésével (melynek mellékhatásaként a memóriaparaméteres PSHUFD 3 millió helyett 6 milliószor fut le).

    K8 analízis (túl sok a VectorPath):

    @copyarraySSE: //
    movd xmm0,[eax+04h] // 9/- FPUvector
    @zoomvertSSE: //
    mov [esp],edi // 3/1 p0/1/2 ALU 0/1/2
    xor ebx,ebx // 1/1 p0/1/2 ALU 0/1/2
    mov esi,[esp+_STRROWS] // 3/1 p0/1/2 ALU 0/1/2
    and edi,-64 // 1/1 p0/1/2 ALU 0/1/2
    sub edx,[esp+_STRLEFT] // 4/1 p0/1/2 ALU 0/1/2
    movd ebp,mm4 // 4/- FPUvector
    pshufd xmm0,xmm0,00000000b // 4/- FPUvector
    movd ecx,mm6 // 4/- FPUvector
    lea edi,[edi+40h] // 1/1 p0/1/2 ALU 0/1/2
    mov esi,[esi] // 3/1 p0/1/2 ALU 0/1/2
    cmovge edx,ebx // 1/1 p0/1/2 ALU 0/1/2
    movaps xmm1,[edi] // 4/- p5 FSTORE
    @sourceLEFT: //
    mov bl,[esi] // 4/1 p0/1/2 ALU 0/1/2
    add esi,02h // 1/1 p0/1/2 ALU 0/1/2
    add edx,ebx // 1/1 p0/1/2 ALU 0/1/2
    jle @sourceLEFT // 1/1 p0/1/2 ALU 0/1/2
    mov bl,[esi-01h] // 4/1 p0/1/2 ALU 0/1/2
    jmp @initpixelSSE // 1/1 p0/1/2 ALU 0/1/2
    @newpixelSSE: //
    movzx edx,word ptr [esi] // 1/1 p0/1/2 ALU 0/1/2
    add esi,02h // 1/1 p0/1/2 ALU 0/1/2
    movzx ebx,dh // 1/1 p0/1/2 ALU 0/1/2
    @initpixelSSE: //
    movaps xmm3,xmm0 // 2/1 p3/4 FADD/FMUL
    shl ebx,04h // 1/1 p0/1/2 ALU 0/1/2
    add dl,01h // 1/1 p0/1/2 ALU 0/1/2
    add ebx,[esp+_STRCOLORS] // 4/1 p0/1/2 ALU 0/1/2
    mulps xmm3,[ebx] // 7/2 p4 FMUL
    @prevHpixelSSE: //
    sub dl,01h // 1/1 p0/1/2 ALU 0/1/2
    pshufd xmm2,[ecx+00h],10010101b // 4/- FPUvector
    jz @newpixelSSE // 1/1 p0/1/2 ALU 0/1/2
    movaps xmm4,xmm3 // 2/1 p3/4 FADD/FMUL
    mov ebx,[ecx+00h] // 4/1 p0/1/2 ALU 0/1/2
    @pixelSSE: //
    mulps xmm4,xmm2 // 7/2 p4 FMUL
    test ebx,ebx // 1/1 p0/1/2 ALU 0/1/2
    @1pixelSSE: //
    addps xmm1,xmm4 // 5/2 p3 FADD
    jz @nextHpixelSSE // 1/1 p0/1/2 ALU 0/1/2
    movaps [edi],xmm1 // 3/- p5 FSTORE
    js @stepHelementSSE // 1/1 p0/1/2 ALU 0/1/2
    add edi,10h // 1/1 p0/1/2 ALU 0/1/2
    movaps xmm4,xmm3 // 2/1 p3/4 FADD/FMUL
    sub ebx,01h // 1/1 p0/1/2 ALU 0/1/2
    movaps xmm1,[edi] // 4/- p5 FSTORE
    jnz @1pixelSSE // 1/1 p0/1/2 ALU 0/1/2
    @nextHpixelSSE: //
    cmp ebx,[ecx+08h] // 4/1 p0/1/2 ALU 0/1/2
    pshufd xmm2,xmm2,11111111b // 4/- FPUvector
    lea ebx,[ebx-01h] // 1/1 p0/1/2 ALU 0/1/2
    jnz @pixelSSE // 1/1 p0/1/2 ALU 0/1/2
    @stepHelementSSE: //
    add ebp,ebx // 1/1 p0/1/2 ALU 0/1/2
    lea ecx,[ecx+10h] // 1/1 p0/1/2 ALU 0/1/2
    jnz @prevHpixelSSE // 1/1 p0/1/2 ALU 0/1/2
    mov edi,[esp] // 4/1 p0/1/2 ALU 0/1/2
    xor edx,edx // 1/1 p0/1/2 ALU 0/1/2
    @moreVrowsSSE: //
    add [eax+00h],ebx // 4/1 p0/1/2 ALU 0/1/2
    jns @cvtROW // 1/1 p0/1/2 ALU 0/1/2
    cmp ebx,[eax+00h] // 4/1 p0/1/2 ALU 0/1/2
    jnz @stepVelementSSE // 1/1 p0/1/2 ALU 0/1/2
    add ebp,[eax+08h] // 4/1 p0/1/2 ALU 0/1/2
    movd xmm0,ebp // 9/- FPUvector
    jnz @zoomvertSSE // 1/1 p0/1/2 ALU 0/1/2
    @stepVelementSSE: //
    add dword ptr [esp+_STRROWS],04h // 4/1 p0/1/2 ALU 0/1/2
    add [esp+_VSIZE],ebx // 4/1 p0/1/2 ALU 0/1/2
    lea eax,[eax+10h] // 1/1 p0/1/2 ALU 0/1/2
    jnz @copyarraySSE // 1/1 p0/1/2 ALU 0/1/2
    sub eax,10h // 1/1 p0/1/2 ALU 0/1/2
    mov [eax+00h],ebx // 3/1 p0/1/2 ALU 0/1/2
    @cvtROW: //
    mov esi,edi // 1/1 p0/1/2 ALU 0/1/2
    mov ebp,[esp+_INCREASE] // 4/1 p0/1/2 ALU 0/1/2
    and esi,-64 // 1/1 p0/1/2 ALU 0/1/2
    sub edi,ebp // 1/1 p0/1/2 ALU 0/1/2
    @cvtRGB: //
    add esi,40h // 1/1 p0/1/2 ALU 0/1/2
    cvtps2dq xmm1,[esi+00h] // 7/2 p5 FSTORE
    cvtps2dq xmm2,[esi+10h] // 7/2 p5 FSTORE
    cvtps2dq xmm3,[esi+20h] // 7/2 p5 FSTORE
    cvtps2dq xmm4,[esi+30h] // 7/2 p5 FSTORE
    movaps [esi+00h],xmm5 // 3/- p5 FSTORE
    packssdw xmm1,xmm2 // 2/- p3/4 FADD/FMUL
    movaps [esi+10h],xmm5 // 3/- p5 FSTORE
    packssdw xmm3,xmm4 // 2/- p3/4 FADD/FMUL
    movaps [esi+20h],xmm5 // 3/- p5 FSTORE
    packuswb xmm1,xmm3 // 2/- p3/4 FADD/FMUL
    movaps [esi+30h],xmm5 // 3/- p5 FSTORE
    movups [edi+ebp],xmm1 //
    add ebp,10h // 1/1 p0/1/2 ALU 0/1/2
    js @cvtRGB // 1/1 p0/1/2 ALU 0/1/2
    cmp [eax+00h],edx // 4/1 p0/1/2 ALU 0/1/2
    jz @moreVrowsSSE // 1/1 p0/1/2 ALU 0/1/2
    divss xmm0,xmm0 //16/- p4 FMUL
    jns @zoomvertSSE // 1/1 p0/1/2 ALU 0/1/2

    Nem látom Netburst-ön tovább az utat: a 19 clock/forráspixeles globális sebességet PSHUFD-MOVAPS-MULPS-ADDPS kvartett kifeszíti, a többi utasítás futását szinte teljesen elrejti.

    Most már kíváncsi vagyok, hogy egy P3-on mit lehet kihozni.

  • P.H.

    senior tag

    Harmadik felvonás, az előző már érdemes volt egy gyors első generációs Netburst port issue elemzésre és TSC-mérésekre.

    Előző (Prescott CeleronD): 735M clock
    Az alábbi (Prescott CeleronD): 670M clock (-10%)
    Az alábbi (K8 Opteron): 565M clock

    movd xmm0,[eax+04h] // 6+6/2 p1+1+2 MMX_MSC+MMX_SH+LOAD
    @zoomvertSSE: //
    mov [esp+_DESTROW],edi // 2/d p3 STORE
    xor ebx,ebx // d/d p0/1 ALU 0/1
    mov esi,[esp+_STRROWS] // 2+d/d p0/1+2 ALU 0/1+LOAD
    and edi,-64 // d/d p0/1 ALU 0/1
    sub edx,[esp+_STRLEFT] // 2+d/d p0/1+2 ALU 0/1+LOAD
    movd ebp,mm4 // 10/1 p0+1 FP_MOV+FP_MISC
    pshufd xmm0,xmm0,00000000b // 4/2 p1 MMX_SH
    movd ecx,mm6 // 10/1 p0+1 FP_MOV+FP_MISC
    lea edi,[edi+40h] // d/d p0/1 ALU 0/1
    mov esi,[esi] // 2+d/d p0/1+2 ALU 0/1+LOAD
    cmovge edx,ebx //
    movaps xmm1,[edi] // 6+6/1 p0+2 FP_MOV+LOAD
    @sourceLEFT: //
    mov bl,[esi] // 2+d/d p0/1+2 ALU 0/1+LOAD
    add esi,02h // d/d p0/1 ALU 0/1
    add edx,ebx // d/d p0/1 ALU 0/1
    jle @sourceLEFT // -/d p0 ALU 0
    mov bl,[esi-01h] // 2+d/d p0/1+2 ALU 0/1+LOAD
    jmp @initpixelSSE // -/d p0 ALU 0
    @newpixelSSE: //
    movzx edx,word ptr [esi] // 2+d/d p0/1+2 ALU 0/1+LOAD
    add esi,02h // d/d p0/1 ALU 0/1
    movzx ebx,dh // d/d p0/1+2 ALU 0/1
    @initpixelSSE: //
    movaps xmm3,xmm0 // 6/1 p0 FP_MOV
    shl ebx,04h // 4/1 p1 CMPXALU
    add dl,01h // d/d p0/1 ALU 0/1
    add ebx,[esp+_STRCOLORS] // 2+d/d p0/1+2 ALU 0/1+LOAD
    mulps xmm3,[ebx] // 6+6/2 p1+2 FP_MUL+LOAD
    @prevHpixelSSE: //
    sub dl,01h // d/d p0/1 ALU 0/1
    jz @newpixelSSE // -/d p0 ALU 0
    pshufd xmm2,[ecx+00h],10010101b // 6+4/2 p1+2 MMX_SH+LOAD
    movaps xmm4,xmm3 // 6/1 p0 FP_MOV
    mov ebx,[ecx+00h] // 2+d/d p0/1+2 ALU 0/1+LOAD
    @pixelSSE: //
    mulps xmm4,xmm2 // 6/2 p1+2 FP_MUL
    test ebx,ebx // d/d p0/1 ALU 0/1
    @1pixelSSE: //
    addps xmm1,xmm4 // 4/2 p1 FP_ADD
    jz @nextHpixelSSE // -/d p0 ALU 0
    movaps [edi],xmm1 // 6+6/1 p0+3 FP_STR+STORE
    js @stepHelementSSE // -/d p0 ALU 0
    add edi,10h // d/d p0/1 ALU 0/1
    movaps xmm4,xmm3 // 6/1 p0 FP_MOV
    sub ebx,01h // d/d p0/1 ALU 0/1
    movaps xmm1,[edi] // 6+6/1 p0+2 FP_MOV+LOAD
    jnz @1pixelSSE // -/d p0 ALU 0
    @nextHpixelSSE: //
    cmp ebx,[ecx+08h] // 2+d/d p0/1+2 ALU 0/1+LOAD
    pshufd xmm2,xmm2,11111111b // 4/2 p1 MMX_SH
    lea ebx,[ebx-01h] // d/d p0/1 ALU 0/1
    jnz @pixelSSE // -/d p 1 ALU 0
    @stepHelementSSE: //
    add ebp,ebx // d/d p0/1 ALU 0/1
    lea ecx,[ecx+10h] // d/d p0/1 ALU 0/1
    jnz @prevHpixelSSE // -/d p0 ALU 0
    mov edi,[esp+_DESTROW] // 2+d/d p0/1+2 ALU 0/1+LOAD
    xor edx,edx // d/d p0/1 ALU 0/1
    @moreVrowsSSE: //
    add [eax+00h],ebx // 2+2+d/d p0+2+3 ALU 0/1+LOAD+STORE
    jns @cvtROW // -/d p0 ALU 0
    cmp ebx,[eax+00h] // 2+d/d p0/1+2 ALU 0/1+LOAD
    jnz @stepVelementSSE // -/d p0 ALU 0
    add ebp,[eax+08h] // 2+d/d p0/1+2 ALU 0/1+LOAD
    movd xmm0,ebp // 6/2 p1 MMX_MSC+MMX_SH
    jnz @zoomvertSSE // -/d p0 ALU 0
    @stepVelementSSE: //
    add dword ptr [esp+_STRROWS],04h // 2+2+d/d p0+1+3 ALU 0/1+LOAD+STORE
    add [esp+_VSIZE],ebx // 2+2+d/d p0+1+3 ALU 0/1+LOAD+STORE
    lea eax,[eax+10h] // d/d p0/1 ALU 0/1
    jnz @copyarraySSE // -/d p0 ALU 0
    sub eax,10h // d/d p0/1 ALU 0/1
    mov [eax+00h],ebx // 2/d p3 STORE
    @cvtROW: //
    mov esi,edi // d/d p0/1 ALU 0/1
    mov ebp,[esp+_INCREASE] // 2+d/d p0/1+2 ALU 0/1+LOAD
    and esi,-64 // d/d p0/1 ALU 0/1
    sub edi,ebp // d/d p0/1 ALU 0/1
    @cvtRGB: //
    add esi,40h // d/d p0/1 ALU 0/1
    cvtps2dq xmm1,[esi+00h] // 6+5/1 p1 FP_ADD+LOAD
    cvtps2dq xmm2,[esi+10h] // 6+5/1 p1 FP_ADD+LOAD
    cvtps2dq xmm3,[esi+20h] // 6+5/1 p1 FP_ADD+LOAD
    cvtps2dq xmm4,[esi+30h] // 6+5/1 p1 FP_ADD+LOAD
    movaps [esi+00h],xmm5 // 6+6/1 p0+3 FP_STR+STORE
    movaps [esi+10h],xmm5 // 6+6/1 p0+3 FP_STR+STORE
    movaps [esi+20h],xmm5 // 6+6/1 p0+3 FP_STR+STORE
    movaps [esi+30h],xmm5 // 6+6/1 p0+3 FP_STR+STORE
    packssdw xmm1,xmm2 // 2/1 p1 MMX_SHF
    packssdw xmm3,xmm4 // 2/1 p1 MMX_SHF
    packuswb xmm1,xmm3 // 2/1 p1 MMX_SHF
    movups [edi+ebp],xmm1 // 6/1 p0 FP_MOV
    add ebp,10h // d/d p0/1 ALU 0/1
    js @cvtRGB // -/d p0 ALU 0
    cmp [eax+00h],edx // 2+d/d p0/1+2 ALU 0/1+LOAD
    jz @moreVrowsSSE // -/d p0 ALU 0
    divss xmm0,xmm0 // 23/23 p1 FP_DIV
    jns @zoomvertSSE // -/d p0 ALU 0

  • P.H.

    senior tag

    válasz P.H. #12 üzenetére

    hotfix:

    Ennek ellentmond, hogy a (dinamikusan allokált tömb méretének lekérdezése, ha a tömb nem NULL):

    test eax,eax
    cmovnz eax,[eax-04h]

    kód EAX = 0 esetben védelmi hibával leáll, tehát a cmovcc függ mindkét bemeneti értékétől.

  • P.H.

    senior tag

    Under investigation: K8 utasítássorrend

    ad 1:

    @rewrite:
    xor eax,eax
    sub ecx,01h
    js @finished
    mov dl,[ebx+ecx]
    add eax,[edi+ecx*04h]
    mov ebp,[esi+edx*04h]
    cmovz eax,ebp
    test dl,dl
    cmovz ebp,eax
    mov [ebx+ecx*04h],ebp
    jmp @rewrite

    ad 2:
    @rewrite:
    xor eax,eax
    sub ecx,01h
    mov dl,[ebx+ecx]
    js @finished
    add eax,[edi+ecx*04h]
    mov ebp,[esi+edx*04h]
    cmovz eax,ebp
    test dl,dl
    cmovz ebp,eax
    mov [ebx+ecx*04h],ebp
    jmp @rewrite

    ECX = 2 853 960 bemeneti értékkel az első ciklus lefutása 25M clock (~9 clock/pixel), a 2. ciklusé 30M clock (~10-11 clock/pixel). Az első cmovz általi átírás sosem fut le, a másodiké 90%-ban.

    Ennek ellentmod, hogy a

    test eax,eax
    cmp eax,[eax-04h]

    kód abban az esetben, ha EAX = 0, védelmi hibával leáll, tehát a cmovcc függ mindhárom bemeneti értékétől.

    A referencia x86 kód 32M órajel:

    @rewrite:
    xor eax,eax
    sub ecx,01h
    mov dl,[ebx+ecx]
    js @finished
    add eax,[edi+ecx*04h]
    mov ebp,[esi+edx*04h]
    jz @store
    test dl,dl
    xchg ebp,eax
    jz @store
    mov ebp,eax
    @store:
    mov [ebx+ecx*04h],ebp
    jmp @rewrite
    @finished:

  • P.H.

    senior tag

    Alakulgat:

    @copyarraySSE:
    pshufd xmm0,[eax],01010101b
    @zoomvertSSE:
    mov [esp+_DESTROW],edi
    mov esi,[esp+_STRROWS]
    xor ebx,ebx
    and edi,-32
    sub edx,[esp+_STRLEFT]
    movd ebp,mm4
    movd ecx,mm6
    lea edi,[edi+20h]
    mov esi,[esi]
    movaps xmm1,[edi]
    jge @newpixelSSE
    @sourceLEFT:
    mov bl,[esi]
    add esi,02h
    add edx,ebx
    js @sourceLEFT
    mov bl,[esi-01h]
    jnz @initpixelSSE
    @newpixelSSE:
    movzx edx,word ptr [esi]
    add esi,02h
    movzx ebx,dh
    @initpixelSSE:
    shl ebx,04h
    add ebx,[esp+_STRCOLORS]
    movaps xmm7,[ebx]
    jmp @nxpixelSSE
    @prevHpixelSSE:
    sub dl,01h
    jz @newpixelSSE
    @nxpixelSSE:
    movaps xmm4,xmm7
    movlps xmm6,[ecx+04h]
    mov ebx,[ecx+00h]
    mulps xmm4,xmm0
    pshufd xmm2,xmm6,01000000b
    shufps xmm6,xmm6,01010101b
    movaps xmm3,xmm4
    @pixelSSE:
    test ebx,ebx
    mulps xmm4,xmm2
    @1pixelSSE:
    addps xmm1,xmm4
    jz @nextHpixelSSE
    movaps [edi],xmm1
    js @stepHelementSSE
    add edi,10h
    movaps xmm4,xmm3
    sub ebx,01h
    movaps xmm1,[edi]
    jnz @1pixelSSE
    @nextHpixelSSE:
    cmp ebx,[ecx+08h]
    movaps xmm2,xmm6
    lea ebx,[ebx-01h]
    jnz @pixelSSE
    @stepHelementSSE:
    add ebp,ebx
    lea ecx,[ecx+10h]
    jnz @prevHpixelSSE
    mov edi,[esp+_DESTROW]
    xor edx,edx
    @moreVrowsSSE:
    add [eax+00h],ebx
    jns @cvtROW
    cmp [eax+00h],ebx
    jnz @stepVelementSSE
    cmp ebp,[eax+08h]
    pshufd xmm0,[eax],10101010b
    jnz @zoomvertSSE
    @stepVelementSSE:
    add dword ptr [esp+_STRROWS],04h
    add [esp+_VSIZE],ebx
    lea eax,[eax+10h]
    jnz @copyarraySSE
    sub eax,10h
    mov [eax+00h],ebx
    @cvtROW:
    mov esi,edi
    mov ebp,[esp+_INCREASE]
    and esi,-32
    sub edi,ebp
    @cvtRGB:
    add esi,20h
    cvtps2dq xmm3,[esi+00h]
    movaps [esi+00h],xmm5
    cvtps2dq xmm1,[esi+10h]
    movaps [esi+10h],xmm5
    packssdw xmm3,xmm1
    packuswb xmm3,xmm1
    movq [edi+ebp],xmm3
    add ebp,08h
    js @cvtRGB
    cmp [eax+00h],edx
    jz @moreVrowsSSE
    divps xmm0,xmm0
    jns @zoomvertSSE

    x87:

    fldz
    @copyarray:
    fadd dword ptr [eax+04h]
    @zoomvert:
    mov edi,[esp+_DESTROW]
    mov ecx,[esp+_STRVAR+_ECX]
    xor ebx,ebx
    mov esi,[esp+_STRROWS]
    mov ebp,[ecx-04h]
    fld dword ptr [edi+00h]
    mov esi,[esi]
    fld dword ptr [edi+04h]
    add ecx,[esp+_XADD]
    xor edx,edx
    sub ebx,[esp+_STRLEFT]
    fld dword ptr [edi+08h]
    jge @newpixelx86
    @sourceLEFTx86:
    mov dl,[esi]
    add esi,02h
    add ebx,edx
    js @sourceLEFTx86
    mov dl,[esi-01h]
    jnz @initpixelx86
    @newpixelx86:
    movzx ebx,word ptr [esi]
    add esi,02h
    movzx edx,bh
    @initpixelx86:
    mov [esp+_TMPCOLOR],bl
    shl edx,04h
    add edx,[esp+_STRCOLORS]
    jmp @nxpixelx86
    @prevHpixel:
    sub byte ptr [esp+_TMPCOLOR],01h
    jz @newpixelx86
    @nxpixelx86:
    fld dword ptr [ecx+04h]
    mov ebx,[ecx+00h]
    @HANDLEPIXEL:
    fmul st,st(4)
    test ebx,ebx
    fld dword ptr [edx+00h]
    fmul st,st(1)
    faddp st(4),st
    fld dword ptr [edx+04h]
    fmul st,st(1)
    faddp st(3),st
    fmul dword ptr [edx+08h]
    fadd
    js @stepHelement
    fld1
    jz @nextHpixel
    fxch st(3)
    fstp dword ptr [edi+00h]
    fstp dword ptr [edi+08h]
    fstp dword ptr [edi+04h]
    add edi,0Ch
    sub ebx,01h
    fld dword ptr [edi+04h]
    fld dword ptr [edi+08h]
    fld dword ptr [edi+00h]
    fxch st(3)
    jnz @HANDLEPIXEL
    @nextHpixel:
    cmp [ecx+08h],ebx
    lea ebx,[ebx-01h]
    fmul dword ptr [ecx+08h]
    jnz @HANDLEPIXEL
    fstp st(0)
    @stepHelement:
    add ebp,ebx
    lea ecx,[ecx+10h]
    jnz @prevHpixel
    fstp dword ptr [edi+08h]
    fstp dword ptr [edi+04h]
    fstp dword ptr [edi+00h]
    @moreVrows:
    add [eax+00h],ebx
    fsub st,st(0)
    mov edi,[esp+_DESTROW]
    jns @cvtROWx86
    @nextVrow:
    cmp [eax+00h],ebx
    jnz @stepVelement
    cmp ebp,[eax+08h]
    fadd dword ptr [eax+08h]
    jnz @zoomvert
    @stepVelement:
    add dword ptr [esp+_STRROWS],04h
    add eax,10h
    add [esp+_VSIZE],ebx
    fsub st,st(0)
    jnz @copyarray
    sub eax,10h
    mov [eax+00],ebx
    @cvtROWx86:
    mov ecx,[esp+_INCREASE]
    mov esi,edi
    lea edx,[edi+ecx]
    mov [esp+_DESTROW],edx
    @cvtRGBx86:
    fld dword ptr [esi+08h]
    mov [esi+00h],ebp
    fld dword ptr [esi+00h]
    mov [esi+08h],ebp
    fld dword ptr [esi+04h]
    mov [esi+04h],ebp
    fistp word ptr [esp+_TMPCOLOR]
    add esi,0Ch
    fistp word ptr [edi+00h]
    mov dl,[esp+_TMPCOLOR]
    sub ecx,04h
    fistp word ptr [edi+02h]
    mov [edi+01h],dl
    lea edi,[edi+04h]
    jnz @cvtRGBx86
    fld1
    cmp [eax+00h],ebp
    fadd
    jz @moreVrows
    js @removeTEMP
    jmp @zoomvert

  • P.H.

    senior tag

    A korábbi pár munkaórás skiccek után egy valódi nagypálya, amelyben már több 10 munkaóra fekszik: a következő kódnak 100 megapixeles képeket kellene kezelnie 1 másodpercen belüli időhatárral; jelenleg 32 megapixeles képen tesztelve bőven megvan az 1 másodperc, de gyorsabbnak érződik 2.26 GHz-es CeleronD-n, mint 2.2 GHz-es Opteron-on. Első lépésben a kép erőteljesen tömörítve lesz, és talán vissza lesz az algoritmus írva integer alapra (MMX/SSE2), a színhelyesség megtartásával.

    A kiindulási kód:

    @decode:
    movd esi,mm5
    movd edx,mm4
    movd ecx,mm7
    movd ebx,mm6
    movss xmm0,[ebp]
    @temprow:
    movzx eax,byte ptr [esi]
    add esi,01h
    shl eax,04h
    sub edx,01h
    movaps xmm3,[ecx+eax]
    movaps [ebx],xmm3
    lea ebx,[ebx+20h]
    jg @temprow
    add esi,[esp+_SROW]
    mov ecx,edi
    movd mm5,esi
    mov edx,[ebp+08h]
    @zoomvertSSE:
    and edi,-32
    movd esi,mm6
    add edi,20h
    shufps xmm0,xmm0,00000000b
    movd eax,mm4
    movaps xmm1,[edi]
    @prevHpixelSSE:
    movaps xmm4,[esi-00h]
    movlps xmm2,[esi-10h]
    mov ebx,[esi-10h+08h]
    mulps xmm4,xmm0
    shufps xmm2,xmm2,01000000b
    movaps xmm3,xmm4
    @pixelSSE:
    test ebx,ebx
    mulps xmm4,xmm2
    @1pixelSSE:
    addps xmm1,xmm4
    jz @nextHpixelSSE
    movaps [edi],xmm1
    js @stepHelementSSE
    add edi,10h
    movaps xmm4,xmm3
    sub ebx,01h
    movaps xmm1,[edi]
    jnz @1pixelSSE
    @nextHpixelSSE: { EBX = 0 }
    shufps xmm2,xmm2,11111111b
    cmp [esi-10h+04h],ebx
    lea ebx,[ebx-01h]
    jnz @pixelSSE
    @stepHelementSSE: { EBX = -1 }
    add eax,ebx
    lea esi,[esi+20h]
    jnz @prevHpixelSSE
    mov edi,ecx
    @moreVrowsSSE: { EAX = 0 és EBX = -1 }
    add edx,ebx
    jns @cvtROW
    cmp edx,ebx
    jnz @stepVelementSSE
    add eax,[ebp+04h]
    movd xmm0,eax
    jnz @zoomvertSSE
    @stepVelementSSE:
    add [esp+_VSIZE],ebx
    lea ebp,[ebp+20h]
    jnz @decode
    mov edx,ebx
    @cvtROW:
    mov esi,ecx
    mov eax,[esp+_INCREASE]
    and esi,-32
    sub edi,eax
    @cvtRGB:
    add esi,20h
    cvtps2dq xmm0,[esi+00h]
    movaps [esi+00h],xmm5
    cvtps2dq xmm1,[esi+10h]
    movaps [esi+10h],xmm5
    packssdw xmm0,xmm1
    packuswb xmm0,xmm1
    movq [edi+eax],xmm0
    add eax,08h
    js @cvtRGB
    test edx,edx
    mov ecx,edi
    jz @moreVrowsSSE
    divss xmm0,xmm0
    jns @zoomvertSSE

  • P.H.

    senior tag

    Under investigation: 2D gráfpont koordinátaszámítás (nagyítás + eltolás) és vágás több százezer ponton.

    - x87-es kiindulási megoldás (extended precision):

    @init:
    fldz
    @coor:
    movzx eax,word ptr [edi+STRUCTURE.RSIZE]
    mov cx,[LIMIT]
    sub edx,01h
    lea edi,[edi+eax+STRUCTURESIZE]
    fstp st(0)
    jle @sections
    or byte ptr [edi+STRUCTURE.BITFIELD],$80
    cmp [edi+STRUCTURE.RSIZE],cx
    fld dword ptr [edi+STRUCTURE.X]
    jle @coor
    fmul st,st(3)
    mov al,[BITFILTER]
    fld dword ptr [edi+STRUCTURE.Y]
    xor ecx,ecx
    mov [esi],edi
    fmul st,st(4)
    fxch
    test [edi+STRUCTURE.BITFIELD],al
    fsub st,st(3)
    mov eax,[IMAGEWIDTH]
    fistp dword ptr [edi+STRUCTURE.XCOOR]
    mov ebp,[IMAGEHEIGHT]
    fsub st,st(1)
    mov [esi+04h],ecx
    fist dword ptr [edi+STRUCTURE.YCOOR]
    jnz @coor
    sub eax,[edi+STRUCTURE.XCOOR]
    mov ecx,[edi+STRUCTURE.YCOOR]
    or eax,[edi+STRUCTURE.XCOOR]
    sub ebp,ecx
    or eax,ecx
    or eax,ebp
    js @coor
    and byte ptr [edi+STRUCTURE.BITFIELD],$7F
    add esi,04h
    jmp @coor
    @sections:
    ...

    - SSE2 (double precision):

    @initSSE:
    mov bp,[LIMIT]
    mov cl,[BITFILTER]
    mov bl,[edi+STRUCTURE.BITFIELD]
    @coorSSE:
    movzx eax,word ptr [edi+STRUCTURE.RSIZE]
    sub edx,01h
    mov [edi+STRUCTURE.BITFIELD],bl
    movapd xmm3,xmm4
    lea edi,[edi+eax+STRUCTURESIZE]
    mov bl,$80
    jle @sectionSSE
    cvtps2pd xmm0,[edi+STRUCTURE.X]
    or bl,[edi+STRUCTURE.BITFIELD]
    cmp [edi+STRUCTURE.RSIZE],bp
    mulpd xmm0,xmm2
    jle @coorSSE
    subpd xmm0,xmm1
    cvtpd2dq xmm0,xmm0
    test bl,cl
    psubd xmm3,xmm0
    movq [edi+STRUCTURE.XCOOR],xmm0
    jnz @coorSSE
    por xmm3,xmm0
    pmovmskb eax,xmm3
    test al,88h
    jnz @coorSSE
    and bl,$7F
    movnti [esi],edi
    add esi,04h
    jmp @coorSSE
    @sectionSSE:
    xor eax,eax
    sfence
    mov [esi],eax
    ...

    - 3DNow! (single precision):

    @init3DNow:
    mov bp,[LIMIT]
    mov cl,[BITFILTER]
    mov bl,[edi+STRUCTURE.BITFIELD]
    @coor3DNow:
    movq mm0,mm2
    movzx eax,word ptr [edi+STRUCTURE.RSIZE]
    sub edx,01h
    mov [edi+STRUCTURE.BITFIELD],bl
    movq mm3,mm4
    lea edi,[edi+eax+STRUCTURESIZE]
    mov bl,$80
    jle @section3DNow
    pfmul mm0,[edi+STRUCTURE.X]
    or bl,[edi+STRUCTURE.BITFIELD]
    cmp [edi+STRUCTURE.RSIZE],bp
    pfsub mm0,mm1
    jle @coor3DNow
    pf2id mm0,mm0
    test bl,cl
    psubd mm3,mm0
    movq [edi+STRUCTURE.XCOOR],mm0
    jnz @coor3DNow
    por mm3,mm0
    pmovmskb eax,mm3
    test al,88h
    jnz @coor3DNow
    and bl,$7F
    mov [esi],edi
    add esi,04h
    jmp @coor3DNow
    @section3DNow:
    xor eax,eax
    emms
    mov [esi],eax
    ...

    A sorrend (TSC alapján):
    - K8: 1.SSE2 2:3DNow! 3:x87 (kb. 5% eltéréssel)
    - Netburst: 1:x87 2.SSE2 (elhanyagolható eltéréssel)

    :F

  • P.H.

    senior tag

    Minő örömmel töltheti el a felhasználót, hogy amennyiben a Microsoft nem unicode-os API-hívásokkal fordítja saját software-eit (pl. a Windows Explorer, Live Messenger, ...cmd.exe), úgy néha megáll az élet 256 hosszú path-ok felett...

    Eset: Windows Live Messenger, Shared Folder-be jönne egy file, ez először egy ideiglenes helyre kerül, majd a teljes átvitel után kerül a valós Shared Folder-be, aminek útvonala ezen a gépen a


    H:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Messenger\ph2000@axelero.hu\Sharing Folders\xxxxxxxx@xxxxxxxx.hu

    Ám a Windows kellemetlen szokása, hogy szereti az ideiglenes file-okat kvázi véletlenszerűen elnevezett vagy class ID-t tartalmazó mappákban/file-okban tárolni, jelen esetben a


    H:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Messenger\ph2000@axelero.hu\SharingMetaData\xxxxxxxx@xxxxxxxx.hu\DFSR\Staging\CS{CA0CF46C-3723-B71A-CE04-F0655DF3F9BE}\48\

    mappa alatti


    48-{B287AD73-60BB-4C0A-9DD7-E10CE71C4C9D}-v48-{B287AD73-60B8-4C0A-9DD7-E10CE71C4C9D}-v48-Partial.frx

    nevű file lenne az. Mivel a mappa neve még 256 karakternél rövidebb, viszont a file-névvel együtt az útvonal már messze hosszabb, ezzel maga a Live Messenger sem tud mit kezdeni az átvitel után, egyszerűen nem tudja áttenni a végleges helyére, pedig a partner szerint 100% feltöltöttséget mutat. A file-on sem Cut/Paste, sem Rename, sem Delete nem segít, sem az, ha a partner törli a Shared Folder-éből, csak a következő utasítássorozat:


    subst z: H:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Messenger\ph2000@axelero.hu\SharingMetaData\xxxxxxxx@xxxxxxxx.hu\DFSR\Staging\CS{CA0CF46C-3723-B71A-CE04-F0655DF3F9BE}\48

    del *.*

    subst z: /d

  • P.H.

    senior tag

    válasz P.H. #6 üzenetére

    hotfix:

    { EAX: src0 string address
    EDX: src1 string address }
    pushad
    xor esi,esi
    xor edi,edi
    mov ebx,offset(_uppercase)
    add esi,eax
    jz @finalize
    add edi,edx
    jz @finalize
    @compare:
    xor eax,eax
    xor edx,edx
    xor ecx,ecx
    add al,[esi]
    lea esi[esi+01h]
    mov dl,[edi]
    mov al,[ebx+eax]
    jz @final
    add cl,[ebx+edx]
    lea edi,[edi+01h]
    jz @finalize
    cmp al,cl
    mov dl,cl
    jz @compare
    @finalize:
    cmp eax,edx
    popad
    setz al ; elhagyható ASM szinten
    ret

    A "viszont a kisebb/nagyobb relációt is az EFLAGS-ben" törölve (_uppercase átszerkesztés kell hozzá, mert z<ő)

  • P.H.

    senior tag

    Két PCHAR vagyis null-terminated karaktersorozat kisbetű/nagybetű azonosságú összehasonlítására Windows alatt az lstrcmpi utasítás helyett (ami Windows NT-k alatt a lokalizáció miatt a natív unicode-formátumára konvertálja belül a két forrás string-et az összehasonlításhoz minden hívás alkalmával, ehhez előtte végigmegy rajtuk a hosszuk meghatározásához, stb.) célszerűbb a következő:

    1. valahol a program indításakor elhelyezni egy 256 elemű _uppercase karakterbömtöt, feltölteni a 256 karakterrel, majd rá kiadni a

    CHARUPPERBUFF(@_uppercase,256) ;

    utasítást,

    2. a programban elhelyezni a következő függvényt:

    { EAX: src0 string address
    EDX: src1 string address }
    pushad
    xor esi,esi
    xor edi,edi
    mov ebx,offset(_UPPERCASE)
    add esi,eax
    jz @finalize
    add edi,edx
    jz @finalize
    @compare:
    xor eax,eax
    xor edx,edx
    xor ecx,ecx
    add al,[esi]
    lea esi[esi+01h]
    mov dl,[edi]
    mov al,[ebx+eax]
    jz @final
    add cl,[ebx+edx]
    lea edi,[edi+01h]
    jz @finalize
    cmp al,cl
    jz @compare
    @finalize:
    cmp eax,edx
    popad
    setz al ; elhagyható ASM szinten
    ret

    - procedure STREQUAL(src1,src2: PCHAR): boolean; magas szinten
    - csak a string egyenlőséget/nemegyenlőséget adja vissza BOOL formában, viszont a kisebb/nagyobb relációt is az EFLAGS-ben
    - a NULL pointer mindig a legkisebb a relációban
    - ha egyik bemenő paramétere NULL, a másik egy 00h byte-ra mutató érvényes pointer, akkor nem egyenlőek, a NULL kisebb

  • P.H.

    senior tag

    válasz P.H. #3 üzenetére

    Update:

    K8:
    - előkészített REP STOSD: 153M órajel
    - @unpackSSE2 (movnti [edi],eax): 68M órajel
    - @unpack (mov [edi],eax): 62M órajel
    Netburst (Prescott):
    - előkészített REP STOSD: 410M órajel
    - @unpackSSE2 (movnti [edi],eax): 110M órajel
    - @unpack (mov [edi],eax): 150M órajel

    Ez némi gondolkodnivalót ad a VectorPath, illetve úgy általában a microcode alapú utasításokról. A REP STOSD legrosszabb esetben is egyenértékű a

    @stosd:
    jcxz @done
    dec ecx
    mov [edi],eax
    lea edi,[edi+04h]
    jmp @stosd
    @done:

    sorozattal akár micro-op szinten is: a "service pending interrupts (if any);" lépést és (a debugger-ek tanulsága szerint) ESP-t befolyásoló ugrást mindkettő tartalmaz. A microcode-on alapuló utasítások micro-opjai a microarchitecture szélességére optimalizáltak, de mennyi az az ismétlésmennyiség, aminél a REP STOSD gyorsabb, mint a klasszikus legalapvetőbb egyszerű ciklus? Van egyáltalán ilyen eset?

  • P.H.

    senior tag

    32->8 bit signed szaturált érték létrehozása ugrással hatékonyabb, mint anélkül. A

    {input:EAX output:AL}
    mov edx,000000FFh
    cmp eax,edx
    jc @done
    shr eax,1Fh
    add al,cl
    @done:

    kód gyorsabb K8-on és Netburst-on egyaránt, mint a

    {input:EAX output:DL}
    mov ecx,000000FFh
    cmp eax,ecx
    mov edx,ecx
    sbb ebx,ebx
    adc dl,cl
    and ebx,eax
    add eax,eax
    adc dl,bl

    Netburst-ön érthető, hogy miért gyorsabb, de K8-on? Ott 5 órajel lenne az utóbbi.

    MMX nélkül nehéz az élet.

    Az előző kérdésre a válasz: nincs, az sfence sorbarendező utasítás.

  • P.H.

    senior tag

    A 32 bites non-temporal store-ok K8-as megvalósítása hagy némi kívánnivalót, a sima x86 tárolássorozat gyorsabb (VectorPath REP STOSD kizárt).

    @unpackSSE2:
    movnti [edi],eax
    add edi,04h
    add ebp,ecx
    jnz @unpackSSE2
    @unpckSSE2:
    add ebx,04h
    mov eax,edx
    mov ebp,[esi+ebx]
    jg @fenceUNPACK
    and eax,ebp
    and ebp,ecx
    jmp @unpackSSE2
    @@UNPACKBMP: <<- entry
    lea eax,{tömörített adatra mutató pointer}
    cmp dword ptr [eax],00h
    jz @exitUNPACK
    pushad
    mov edi,{célkép}
    mov esi,[eax]
    mov ecx,0FF000000h
    mov ebx,[esi-04h]
    lea esi,[esi+ebx-04h]
    neg ebx
    cmp {van_SSE2?},cl
    jnz @unpckSSE2
    jmp @unpck
    @unpack:
    mov [edi],eax
    add edi,04h
    add ebp,ecx
    jnz @unpack
    @unpck:
    add ebx,04h
    mov eax,edx
    mov ebp,[esi+ebx]
    jg @returnUNPACK
    and eax,ebp
    and ebp,ecx
    jmp @unpack
    @fenceUNPACK:
    sfence
    @returnUNPACK:
    popad
    @exitUNPACK:
    ret 00h

    8 megapixeles kép esetén:
    K8:
    - előkészített REP STOSD: 153M órajel
    - @unpackSSE2 (movnti [edi],eax): 68M órajel
    - @unpack (mov [edi],eax): 62M órajel
    Netburst (Prescott):
    - előkészített REP STOSD: 410M órajel
    - @unpackSSE2 (movnti [edi],eax): 110M órajel

    64 byte-os cache-line jutó 3-nál több ugró utasítás hatása elhanyagolható, a code-padding befolyása jelentősebb nála.

    kérdés: esetleges téves elágazásbecslés miatt lefutott sfence-eknek van teljesítményvisszafogó hatásuk, vagy el kell távolítani az ágat a critical path közeléből?

  • P.H.

    senior tag

    A Write-Combining pufferekből privát cache-be csak a rendszermemórián kereszül kerülhet adat, oda és vissza egyaránt, közvetlen kapcsolat nincs ~ olvasott cache-line felülírása non-termporal módon tilos.

    @SSE2rewriteALPHA:
    add ebp,ebx
    jns @retirePERFORM
    cmp [esi+ebp],eax
    jz @SSE2rewriteALPHA
    movd xmm2,[esi+ebp]
    movd xmm3,[edi+ebp]
    punpcklbw xmm2,xmm7
    punpcklbw xmm3,xmm7
    punpcklwd xmm2,xmm7
    punpcklwd xmm3,xmm7
    cvtdq2ps xmm2,xmm2
    mov [esi+ebp],eax <<<----
    cvtdq2ps xmm3,xmm3
    mulps xmm2,xmm0
    mulps xmm3,xmm1
    addps xmm2,xmm3
    cvtps2dq xmm2,xmm2
    packssdw xmm2,xmm2
    packuswb xmm2,xmm2
    movd [edi+ebp],xmm2
    jmp @SSE2rewriteALPHA

    K8 lefutás ~2 megapixeles képen 5% layer-kitöltöttség mellett 9M órajel, mov [esi+ebp],eax utasítás helyett movnti [esi+ebp],eax írva 11M órajel.

    Vajon
    - ez igaz a hardware prefetch-elt cache-vonalakra is?
    - az L3-mak jelenléte változtat a dolgon K10 és főleg Nehalem (inclusive) esetén?
    - ez csak az DL1-re igaz, vagy a VIA-féle prefetch cache tartalmára is?

  • P.H.

    senior tag

    Blog.

    Magamnak.

    Sok dolog elveszett már az elmúlt évek alatt.

    Tehát mondjuk online archiválok. Mondjuk ide. Próba szerencse.

    Adott egy feladat: talán kétrétegű rajzolás lehetne a neve. Adott egy NxM pixel méretű 32 bites kép, amelyre rajzolni kell, de csak bizonyos mintában, amelyet egy 8x4 bites érték ír le: minden sorhoz egy 8 bites minta tartozik, amely ahol 1, az adott pixelen felül kell írni az eredeti képet a layeren lévő rajzzal, hacsak az nem egy előre kijelölt 'háttérszín'; és minden 4 sorhoz tartozik egy ismétlődő minta.

    A megvalósítási ötlet szerint mivel egy kép nem tartalmazhat 32 bites negatív pixel értéket (32 bites megjelenítés megkövetelt, ez alatt nincs értelme a SETDIBITSTODEVICE forrásadatában negatív értéket megadni), így a kisegítő layer (amire első körben a rajzolás történik) háttérszíne tetszőleges negatív szám lehet. A kisegítő layer legyen ugyancsak NxM-es tömb, erre lefutnak a módosítás nélküli rajzolási eljárások a kívánt pixeleket felülírva benne a megfelelő színre, ezután fésüljük össze a két 'képet' az adott minta szerint.

    pushad
    mov ecx,{képszélesség}
    mov ebx,{rajzolási maszk}
    mov esi,{layer címe}
    push {képmagasság}
    shl ecx,02h
    mov edi,{célkép címe}
    mov edx,ecx
    mov ebp,ebx
    @inner:
    sub ecx,04h
    js @outer
    ror bl,01h
    mov eax,[esi+ecx]
    mov dword ptr [esi+ecx],-1
    jnc @inner
    test eax,eax
    jl @inner
    mov [edi+ecx],eax
    jmp @inner
    @outer:
    ror ebp,08h
    add edi,edx
    add esi,edx
    sub dword ptr [esp],01h
    mov ecx,edx
    mov ebx,ebp
    jnz @inner
    @exit:
    add esp,04h
    popad
    ret

    Több ponton is bele lehet kötni a fentiekbe:
    - a Core 2 processzorok LSD-je 4x16 byte-nyi utasítást tud tárolni, benne legfejlebb 4 ugró utasítással, ret nélkül; a fenti @inner ciklus az @outer ciklussal együtt is bőven beleférne a 64 byte-ba, viszont 5 ugró utasítás van benne; ha egyet eliminálni lehetne, akkor a szükséges adatok egyszeri beolvasása után sosem kell a teljes kép feldolgozása során az L1 I-cache-hez fordulni.
    - a K8 CPU-k optimalizálási leírását bogarászva kitűnik, hogy a hardware prefetcher-e a cache-vonalakat csak növekvő sorrendben tudja előbetölteni, a fenti eljárás viszont egy adott képsoron visszafelé halad, mivel az @inner ciklusban az offszet (ecx) csökken.

    pushad
    mov ecx,{képszélesség}
    xor edx,edx
    mov ebx,{rajzolási maszk}
    mov esi,{layer címe}
    push {képmagasság}
    shl ecx,02h
    mov edi,{célkép címe}
    not ebx
    sub edx,ecx
    mov ebp,ebx
    @outer:
    sub edi,edx
    sub esi,edx
    sub dword ptr [esp],01h
    mov ebx,ebp
    lea ecx,[edx-04h]
    ror ebp,08h
    js @exit
    @inner:
    or eax,-1
    add ecx,04h
    jns @outer
    xor eax,[esi+ecx]
    mov dword ptr [esi+ecx],-1
    ror bl,01h
    jbe @inner
    not eax
    mov [edi+ecx],eax
    jmp @inner
    @exit:
    add esp,04h
    popad
    ret

    A következő változások történtek:
    - a korábbi "a layer háttérszíne tetszőleges negatív szám lehet" feltétel szűkült arra, hogy csakis -1 lehet
    - az @outer ciklus is elöltesztelős lett: átlép a következő sor elejére, így az @inner 0 felé egyre közelítő negatív offszettel fér a két tömb pixeleihez.
    - az @inner ciklusban eggyel kevesebb ugrás található, viszont miután az XOR -1,x utáni ROR reg,01h nem változtatja a ZF-et (sem, csak az OF-et és CF-et), így a JBE (jump if below or equal = jump if CF = 1 or ZF = 1) mindkét feltételt egyszerre kezeli; ehhez viszont bit-negálni kell a maszkot a ciklusok előtt.
    Ilyen jellegű megoldás nem létezik magas szintű programozási nyelvekben.

    A következőkben nem történt változás:
    - a 8 használható regiszter közül csak háromnak változik az értéke az @inner ciklusban, ezért képsoronként egyszer a Core 2 belefut az @outer ciklus elején a registerfile-olvasási korlátjába, mivel EDI, ESI, EDX, ESP és EBP is 'befagyott' register-nek tekinthető.
    - ha lenne még egy szabad register, amelyben a -1 konstans tárolható lenne, akkor 1+1+2 byte-tal kisebb lenne a két ciklus kódja, ez x64 alatt megoldható lenne.

    Az elméleti nyereség:
    - bármilyen egyszerű hardware prefetcher-rel ellátott microarchitecture esetén a két tömbön végigmenni minimális L1/L2 cache-tévesztéssel jár (az is nagyrészt csak a 4 KB-os lapok miatt van)
    - teljesen üres layer esetén csakis a jns @outer ugrásánál lehet téveszteni (soronként egyszer)
    - teljesen kitöltött layer esetén a ror bl,01h bizonyos, 8 esetenként ismétlődő minta szerint dolgozik, amit a többszintű ugrás-előrejelzőknek illik lekezelni
    - az algoritmus jól kezeli a layer folyamatos huzamosabb háttér- ill. előtér sorozatait, viszont a gyakori váltásokat nem (ott jobban teljesít az első algoritmus).

    A gyakorlati nyereség: K8 és két, különböző (Kb. 80% és 10%) kitöltöttségű ~2 megapixeles kép+layer esetén TSC-rel kimérve 25M/33M-ról 15M/24M órajel.

Aktív témák