Hirdetés

2024. május 9., csütörtök

Gyorskeresés

Hozzászólások

(#51) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#52) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#53) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#54) P.H.


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).

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#55) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#56) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#57) P.H. válasza P.H. (#56) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#58) P.H.


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).

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#59) P.H.


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).

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#60) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#61) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#62) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#63) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#65) P.H. válasza P.H. (#63) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#66) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#67) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#68) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#69) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#70) P.H. válasza P.H. (#51) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#71) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#72) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#73) P.H. válasza P.H. (#72) üzenetére


P.H.
senior tag

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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#74) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#75) P.H. válasza P.H. (#74) üzenetére


P.H.
senior tag

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.

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#76) P.H. válasza P.H. (#72) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#77) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#78) P.H. válasza P.H. (#39) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#79) P.H. válasza P.H. (#77) üzenetére


P.H.
senior tag

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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#80) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#81) P.H.


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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#82) P.H. válasza P.H. (#80) üzenetére


P.H.
senior tag

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:
...

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#83) P.H.


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} ...

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#84) P.H. válasza P.H. (#39) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#85) P.H. válasza P.H. (#84) üzenetére


P.H.
senior tag

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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#86) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#87) P.H. válasza P.H. (#83) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#88) P.H.


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%).

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#89) P.H. válasza P.H. (#88) üzenetére


P.H.
senior tag

.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#90) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#91) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#92) P.H.


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;

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#93) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#94) P.H. válasza P.H. (#93) üzenetére


P.H.
senior tag

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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#95) P.H.


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

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#96) P.H. válasza P.H. (#95) üzenetére


P.H.
senior tag

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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#97) P.H.


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

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#98) P.H.


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 ) }

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#99) P.H. válasza P.H. (#98) üzenetére


P.H.
senior tag

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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

(#100) P.H. válasza P.H. (#99) üzenetére


P.H.
senior tag

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.

[ Szerkesztve ]

Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙

Copyright © 2000-2024 PROHARDVER Informatikai Kft.