BabeBolyai Tudomnyegyetem MatematikaInformatika Kar Alkalmazsok s opercis rendszerek
„Babeş-Bolyai” Tudományegyetem, Matematika-Informatika Kar Alkalmazások és operációs rendszerek optimizálása 11, 12 Forráskód szintű optimizálások C-ben Assembly szintű optimizálások előadás dr. Robu Judit szeminárium drd. Lukács Sándor 2006 BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
2 ¢ ¢ ¢ Optimizálási alapszabályok 1 mielőtt optimizálnánk egy programot, előbb készítsünk el egy helyes, nem-optimizált kódot l győződjünk meg a program helyességéről l ha egy hiba estén egy programot / programrészt helyettesítünk egy nem-optimizált változattal és a hiba eltűnik a hiba az optimizációban van mindig első lépésként algoritmus szintű optimizációt használjunk l sokkal fontosabb mint az implementáció szintű vagy platform specifikus optimizálások l pl. lineáris keresés bináris keresés optimizálás ≠ átírjuk a programot C-ről asszemblyre l előbb minden esetben a forráskód szintű optimizálásokat végezzük el BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
3 ¢ ¢ Optimizálási alapszabályok 2 mielőtt átírnánk egy programot asszemblyre, előbb ellenőrizzük a C fordító által generált kódot l lehet, hogy nem a fordítás a lassú sebesség oka l lehet, hogy a processzor vagy a memória túl lassú próbáljuk meg egy debuggerben végig követni a C fordító által generált ASM kód végrehajtását l lehet, hogy allignment, ugrás stb. problémák vannak nem kizárt, hogy valóban elég lassú és nem optimális a fordítás jó ilyen esetben ASM-ben optimizálni l de vannak már előre optimizált függvénykönyvtárak amikor ASM-et implementálunk készítsünk standard, elegáns kódot l külön modulok, jó, ha nem inline assemblyvel dolgozunk l lehetőleg ne alkalmazzunk „nyakatekert” trükköket BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
4 Tipikus téveszmék a kompiler mindent optimizál ¢ kiváló sebesség csak asszembly kód segítségével érhető el ¢ a programozók, egy jó optimizáló kompilerrel ellentétben nem képesek egy processzor minden egyes tulajdonságát kihasználni ¢ az x 86 -os processzorok nem érik meg a fáradozást, igazán csak Power. PC és más RISC processzorokon lehet optimizálni ¢ BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
5 Processzor mikroarchitektúra ¢ ¢ ¢ BBTE, Alkalmazások és operációs rendszerek optimizálása dekódoló egységek végrehajtó egységek visszaíró egységek 2006
Utasítás végrehajtás 6 ¢ az utasításokat egyenként olvassa ki a dekódoló egység l ¢ ¢ több dekódoló egység dolgozhat párhuzamosan a dekódolása után a processzor betölti az esetleges szükséges adatokat a processzor lefoglalja a szükséges erőforrásokat megtörénik az effektív végrehajtás (ALU stb. egységeken) szükség esetén az eredmény kiíródik vissza a memóriába BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
7 ¢ ¢ Pipeline véhrehajtás egy utasítás végrehajtása több lépésben történik a pipeline végreahjtás alapötlete: ameddig egység (pl. dekódoló) egy utasítás esetén az egységnek megfelelő műveletet végezi el, a processzor további egységei más műveleteket végezhetnek inst 1 inst 2 inst 3 inst 4 inst 5 BBTE, Alkalmazások és operációs rendszerek optimizálása inst 3 inst 4 inst 5 végrehajtási idő 2006
Végrehajtási sebesség 8 ¢ throughput (átmenet) ≠ latency (késleltetés) l pl. egy gyár óránként 1000 chipet készít, mennyi időbe tellik egyetlen chip készítése? • NEM 3. 6 másodperc!!! l nem lehet egy korszerű pipeline-os processzor esetén igazából egyetlen utasításhoz szükséges óraciklusok számáról beszélni • pl. 1 szorzás ~ 10 ciklus, 10 szorzás ~ 24 óraciklus BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
9 Branch prediction (Pentium Pro) BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
10 ¢ ¢ ¢ Cache memória architektúrák 1 a jelenlegi számítógépek esetén a processzor és a memória sebessége nagymértékben különbözik l tipikusak az 1: 10, 1: 20 vagy még ennél is roszabb arányok amikor a processzor vár egy következő utasítás betöltésére, ha a memória túl lassú, értékes óraciklusok vesznek el (annélkül, hogy a processzor effektíve dolgozna) a probléma kiküszöbölésére cache memóriákat alkalmaznak l a fizikai memóriánál sokkal kissebb méretű, nagyon gyors memóriák (tipikusan 1: 1, 1: 2, legfennebb 1: 4) egy klasszikus processzorban több szintű cache memória van l L 0 cache memória (tipikusan 4 – 32 KB), a leggyorsabb l L 1 cache memória (tipikusan 128 – 512 KB) l L 2 cache memória (tipikusan 512 – 8192 KB) a korszerű processzorok több további cache-t is alkalmaznak l mint például TLB cache a lapozás számára BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
11 Cache memória architektúrák 2 ¢ RAM cache hit – a processzor által kért adatok a cache-ben találhatók l cache kontroller cache memória végrehajtó egységek ¢ nagyon kevés óraciklus alatt elérhetők az adatok cache miss – a processzor által kért adatok NEM találhatók a cache-ben l lényegesn több óraciklus alatt érhetők el az adatok processzor BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
12 ¢ Cache memória architektúrák 3 adatok betöltése RAM-ból cache-be l load-on-demand – amikor először kérjük az adatot l speculative load – megpróbáljuk előre „kitalálni” milyen adatokra lesz szüksége a processzornak • az eddigi végrehajtási mintát elemezve • a következő utasításokat elemezve ¢ ¢ késleltetett adatkiírás (delay write) l több írási művelet eredményét a cache-ben tároljuk l egyetlen írási műveletként utolagosan kiírjuk a RAM-ba a cache memória blokkokra van felosztva l egy blokk (cache line) a cache alapegysége l mivel a fizikai memória méretek sokkal nagyobb mint a cache, egyetlen cache vonalnak több fizikai memória blokk felel meg • tárolni kell egy cache blokkban lévő adattal együtt az adatok címét is BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
13 ¢ ¢ ¢ Cache memória architektúrák 4 mivel a cache memória tárolja a fizikai és/vagy lineáris címeket, felépítéséből adódóan asszociatív memória a cache memória címzése érték alapú (és nem index alapú, mint például a fizikai memória estén) l pl. a 456 -os cache vonalat használja a processzor (ahol 456 a cache tag/címke értéke) és nem a 16 -dik cache vonalat tipikus probléma: a processzor az XYZ című adatot szeretné elérni l a cache ki kell keresse, hogy található-e a cache memóriában az XYZ címnek megfelelő adat l a keresés a cache címkéken történik – ez lehet nagyon időigényes • szekvenciális keresés, párhuzamos keresés ¢ több klasszikus cache architektúra l direct mapped l N-way associative (tipikusan 2, 4 vagy 8) BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
14 Cache memória architektúrák 5 1 2 3 4 cache memória direct mapped 1 2 3 4 5 6 7 8 9 10 11 12 fizikai memória BBTE, Alkalmazások és operációs rendszerek optimizálása 1 2 3 4 cache memória 2 -way associative 1 2 3 4 5 6 7 8 9 10 11 12 fizikai memória 2006
15 ¢ ¢ ¢ Cache memória architektúrák 6 cache koherencia – főképp multi-processzoros rendszerekben write-through l a cache read-only, minden írás a fizikai memóriába történik write-combining l az írások egy átmeneti bufferben tárolódnak l csoportosan vannak kiírva a fizikai memóriába write-back l miden cache vonalhoz státusz attributúm van rendelve l írás esetén DIRTY lesz l minden DIRTY vonal flush-al kiíródik ha más eszköz kéri a cache vonalnak megfelelő fizikai memóriában lévő adatot MESI / MOESI protocol SMP rendszerek számára l Modified, Owned, Exclusive, Shared, Invalid BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
Optimizálási szintek 1 16 ¢ algoritmus szintű optimizálások l ¢ forráskód szintű optimizálások l ¢ l l standard C library speciális optimizált könyvtárak használata (pl. matematika, 3 D, DSP etc. ) pipeline szintű optimizálás l ¢ pl. 4 MB-os lapok alkalmazása memória kiosztás library szintű optimizálások l ¢ adatok elrendezése, modulok felépítése operációs rendszer szintű optimizálások l ¢ a legfontosabb, tipikusan komplexitás szintjén gyorsítja a programot minél jobban ki legyenek használva a pipelineok – több utasítás egyszerre végrehajtó egység szintű optimizálás l minél nagyobb mértékben legyenek kihasználva a végrehajtó egységek BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
Optimizálási szintek 2 17 ¢ branch optimizálások l l ¢ cache optimizálás l l ¢ pl. PAUSE utasítás használata spinlockban Intel Pentium 4 -en SIMD optimizálások (vektorizálás) l l ¢ adatok elrendezése architektúra specifikus optimizálások – pl. spinlock-ok cache vonalakon SMP rendszerben processzor specifikus optimizálások l ¢ minél kevesebb ugró utasítás prefetch kódók MMX, SSE lehet forráskód szintjén is végezni, Intel intrinsic makrókkal multi-threading szintű optimizálás l l megfelelő szinkronizációk Open. MP – akár több processzes felbontás, masszívan párhuzamos gépek esetén vagy tudományos kutatási projektekben használt a leginkább BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
C forráskód szintű optimizálások 1 18 ¢ a single konstansokat f suffixel deklaráljuk l ¢ a C szintjén keverni lehet a tömb és pointer elemeket, ahol lehet, használjunk tömböket l ¢ ¢ a C/C++ fordítók jobban tudnak optimizálni a kis iteráció számú ciklusokat rendszerint bontsuk ki (loop unrolling) a logikai kifejezések esetén az && és || kiértékelései esetén sokszor elég egy részkifejezést kiértékelni l ¢ a C/C++ alapértelmezés szerint double-nek tekinti a lebegőpontos értékeket ha különböző valószínűséggel fordulnak elő a részkifejezések igazság értékei, rendezzük sorba őket if utasítások esetén próbáljuk meg elkerűlni a túl sűrű feltételes részkifejezéseket (túl sűrű ugró utasításokat generálnak) l pl. annak függvényében, hogy a és b rendszerint min és max között van-e? • if (a <= max && a >= min && b <= max && b >= min) • if (a > max || a < min || b > max || b < min) BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
19 ¢ ¢ ¢ C forráskód szintű optimizálások 2 a malloc függvény által visszatérített memória mutatókat szükség esetén ígazítsuk nagyságrend szerint l double *p; l double *np; l p = (double *)malloc(sizeof(double) * number_of_doubles + 7 L); l np = (double *)((((long)(p)) + 7 L) & (-8 L)); mindig használjunk függvény prototípusokat l jobban optimizál a C/C++ kompiler használjuk gyakran (ahol lehet) a const kulcsszót minden kivűlről nem használt függvényt deklaráljunk static-nak a C/C++ változókat és a struktúrák mezőit rendezzük a méretűknek megfelelően csökkenő sorrendbe ahol lehet, helyettesítsük az egész osztásokat szorzással l m = i / j / k; → m = i / (j * k); BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
20 ¢ ¢ C forráskód szintű optimizálások 3 a malloc függvény által visszatérített memória mutatókat szükség esetén ígazítsuk nagyságrend szerint a ciklusokból emeljük ki a ciklustól nem függő részeket for (i. . . ) { if (CONSTANT 0) { Do. Work 0(i); // Does not affect CONSTANT 0. } else { Do. Work 1(i); // Does not affect CONSTANT 0. } } if (CONSTANT 0) { for (i. . . ) { Do. Work 0(i); } } else { for (i. . . ) { Do. Work 1(i); } } BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
21 ¢ C forráskód szintű optimizálások 4 a ciklusokat átírhatjuk explicit párhuzamosságot felhasználva double a[100], sum 1, sum 2, sum 3, sum 4, sum; int i; sum 1 = 0. 0; sum 2 = 0. 0; sum 3 = 0. 0; sum 4 = 0. 0; for (i = 0; i < 100; i + 4) { sum 1 sum 2 sum 3 sum 4 += += a[i]; a[i+1]; a[i+2]; a[i+3]; } sum = (sum 4 + sum 3) + (sum 1 + sum 2); BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
Asszembly szintű optimizálások 1 22 ¢ a lebegőpontos osztás és négyzetgyök sokszor elégséges single pontossággal /* Prototype for _controlfp function */ #include <float. h> unsigned int orig_cw; /* Get current FPU control word and save it. */ orig_cw = _controlfp(0, 0); /* Set precision control in FPU control word to single precision. This reduces the latency of divide and square-root operations. */ _controlfp(_PC_24, MCW_PC); /* Restore original FPU control word. */ _controlfp(orig_cw, 0 xfffff); ¢ ¢ 64 bites egész műveletekhez használjunk 64 bites regisztereket kiterjesztett pontosságú egész műveletekhez használjunk 64 bites regisztereket l l pl. 1024 bites szorzás 32 bites regiszterekkel 256 szorzást, 509 átviteles összeadást és 255 összeadást igényel 64 bites regiszterekkel 64 + 125 + 63 BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
23 ¢ ¢ ¢ Asszembly szintű optimizálások 2 ha lehet használjunk 128 bites SSE utasításokat MMX és x 87 helyett 32 bites egész műveletek számára használjunk 32 bites regisztereket (és ne 64 bitest) amikor lehet használjunk load-execute utasításokat movss xmm 0, [float_var 1] movss xmm 12, [float_var 2] mulss xmm 0, xmm 12 load-execute formában movss xmm 0, [float_var 1] mulss xmm 0, [float_var 2] ¢ az utasításokat kódoljuk a lehető legrövidebb formában 81 C 0 78 56 34 12 add eax, 12345678 h ; 2 -byte opcode form (with Mod. RM) 81 C 3 FB FF FF FF add ebx, -5 ; 32 -bit immediate value 0 F 84 05 00 00 00 jz label 1 ; 2 -byte opcode, 32 -bit immediate minimális ábrázolással 05 78 56 34 12 83 C 3 FB 74 05 add eax, 12345678 h ; 1 -byte opcode form add ebx, -5 ; 8 -bit sign-extended immediate jz label 1 ; 1 -byte opcode, 8 -bit immediate BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
Asszembly szintű optimizálások 3 24 ¢ ha lehet, kerüljünk a részregiszterek használatát mov al, bl mov al, [ebx] movss xmm 1, xmm 2 optimálisabb használat movzx eax, bl movzx eax, byte ptr [ebx] movaps xmm 1, xmm 2 ¢ ¢ mindig igazítsuk az adatokat a nagyságrendüknek megfelelő határra SMP rendszerekben a több processzor között osztott (shared), cache vonalakban lévő adatok lényeges teljesítmény romláshoz vezethetnek l ¢ ¢ időnként elkerülhetetlen, pl. szemaforok esetén megfelelő adatminták esetén használjunk PREFETCH utasításokat azonos cache vonalra ne helyezzünk el adatot és kódot egyaránt az ugró utasításokat ha lehet helyezzük úgy el, hogy ne lépjenek át egy 16 bájtos paragrafus határt egy paragrafusba ne helyezzünk el háromnál több ugró utasítást BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
25 ¢ ¢ ¢ ¢ Asszembly szintű optimizálások 4 ha lehet építsünk fel ugró utasítás mentes végrehajtást, főképp ott, ahol véletlenszerű (egyenletesen elosztott) az ugrás valószínűsége l használjunk pl. CMOVxx utasítást a CALL és RET utasításokat használjunk mindig párossával kerüljük a LOOP és a távoli ugró/hívó utasítások használatát használjuk gyakran a MOVSX és MOVZX utasításokat a memóriából helyezzük közvetlenül a veremre a szükséges adatokat (és ne egy regiszteren keresztül) vigyázzunk arra, hogy minden SIMD adat helyesen legyen a méretének megfelelően igazítva a memóriában ha lehet kerüljük az MMX és áltlános regiszterek közötti közvetlen adatmozgató utasításokat (MOVD) BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
26 ¢ ¢ Asszembly szintű optimizálások 5 adatmásoló (pl. memcpy) eljárásokat implementáljunk MMX / SSE utasításokat felhasználva használjuk a PXOR / XORPS utasítást a SIMD értékek előjelének változtatására signmask DQ 80000000 h, 80000000 h xorps xmm 0, [signmask] ¢ a SIMD értékek abszolut értékének meghatározására használjunk PAND / ANDPS utasításokat absmask DQ 7 FFFFFFFh, 7 FFFFFFFh andps xmm 0, [absmask] ¢ a lebegőpontos és egész aritmetikát egyaránt próbáljuk meg átírni MMX / SSE-re BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
27 ¢ ¢ Optimizációs példa – Hangerősség 1 a hangadatok (minták) 16 bites, előjeles egészek sztereo hang esetén egymás után váltakozva helyezkednek el a két csatorna 16 bites mintái (együtt 32 bit egy BAL, JOBB páros) l BALk, JOBBk, BALk+1, JOBBk+1, BALk+2, JOBBk+2, . . . minta (sample) értékek l 0 – hangtalan l -32768, +32767 – maximális hangerő hangosítás = a minták szorzása konstanssal l x 2 – kétszeres hangerő l x 0. 5 – fél hangerő l a végső érzékelt hangerő nem úgyanúgy módosul; az embeli fül számára logaritmikus skálán kell módosítani a hangerőt (DB) BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
28 Hangerősség – Delphi // get volume factor 0 – 1024 fact : = tck. Amplify. Position; for i : = start to stop do begin // amplify left channel temp : = Wave. Buffer[2*i]; temp : = (temp*fact) div 512; if (temp < -32768) then Wave. Buffer[2*i] : = -32768 else if (temp > +32767) then Wave. Buffer[2*i] : = +32767 else Wave. Buffer[2*i] : = temp; . . . // amplify right channel temp : = Wave. Buffer[2*i+1]; temp : = (temp*fact) div 512; if (temp < -32768) then Wave. Buffer[2*i+1] : = -32768 else if (temp > +32767) then Wave. Buffer[2*i+1] : = +32767 else Wave. Buffer[2*i+1] : = temp; end; ¢ x 0 – x 2 hangerő skála → 0 – 1024 l l l BBTE, Alkalmazások és operációs rendszerek optimizálása 0 – x 0 hangerő 512 – x 1 hangerő 1024 – x 2 hangerő 2006
29 asm push mov mov @again: movsx mul sar cmp jg mov jmp @nb 1: cmp jl mov @done 1: mov. . . Hangerősség – ASM 1 edi esi ecx, factor edi, paddr esi, start eax, WORD PTR [edi+esi*4] ecx eax, 9 eax, -32768 @nb 1 eax, -32768 @done 1 eax, +32767 [edi+esi*4], ax BBTE, Alkalmazások és operációs rendszerek optimizálása . . . movsx mul sar cmp jg mov jmp @nb 2: cmp jl mov @done 2: mov add cmp jb pop end; eax, WORD PTR [edi+esi*4+2] ecx eax, 9 eax, -32768 @nb 2 eax, -32768 @done 2 eax, +32767 [edi+esi*4+2], ax esi, 1 esi, stop @again esi edi 2006
30 asm push mov mov @again: movsx mul sar mov cmp cmovl cmp cmovg mov. . . Hangerősség – ASM 2 a edi esi ebx ecx, edi, esi, ebx, factor paddr start -32768 eax, WORD PTR [edi+esi*4] ecx eax, 9 edx, +32767 eax, ebx eax, edx [edi+esi*4], ax BBTE, Alkalmazások és operációs rendszerek optimizálása . . . movsx mul sar mov cmp cmovl cmp cmovg mov. . . eax, WORD PTR [edi+esi*4+2] ecx eax, 9 edx, +32767 eax, ebx eax, edx [edi+esi*4+2], ax eax, WORD PTR [edi+esi*4+4] ecx eax, 9 edx, +32767 eax, ebx eax, edx [edi+esi*4+4], ax 2006
31 . . . movsx mul sar mov cmp cmovl cmp cmovg mov add cmp jb pop pop end; Hangerősség – ASM 2 a eax, WORD PTR [edi+esi*4+6] ecx eax, 9 edx, +32767 eax, ebx eax, edx [edi+esi*4+6], ax esi, 2 esi, stop @again ebx esi edi BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
32 Hangerősség – SSE 1 a pxor xmm 0, xmm 0 XMM 0 0 0 movd xmm 1, factor pshufd xmm 1, $00 00. 00. 00 XMM 1 factor 0 0 factor movdqu xmm 2, [edx+eax*4] movdqu xmm 3, xmm 2 XMM 2 A 7 A 6 A 5 A 4 A 3 A 2 A 1 A 0 XMM 3 A 7 A 6 A 5 A 4 A 3 A 2 A 1 A 0 BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
33 Hangerősség – SSE 1 b punpcklwd xmm 2, xmm 0 punpckhwd xmm 3, xmm 0 XMM 3 0 A 7 0 A 6 0 A 5 0 A 4 XMM 2 0 A 3 0 A 2 0 A 1 0 A 0 pmaddwd xmm 2, xmm 1 pmaddwd xmm 3, xmm 1 XMM 3 A 7*factor A 6*factor A 5*factor A 4*factor XMM 2 A 3*factor A 2*factor A 1*factor A 0*factor BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
34 Hangerősség – SSE 1 c psrad xmm 2, 9 psrad xmm 3, 9 XMM 3 A 7*factor >> 9 A 6*factor >> 9 A 5*factor >> 9 A 4*factor >> 9 XMM 2 A 3*factor >> 9 A 2*factor >> 9 A 1*factor >> 9 A 0*factor >> 9 packssdw xmm 2, xmm 3 XMM 2 f*A 7/512 f*A 6/512 f*A 5/512 f*A 4/512 f*A 3/512 f*A 2/512 f*A 1/512 f*A 0/512 BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
35 Hangerősség – SSE 2 asm // setup indexing mov edx, paddr mov eax, start // eax = i // setup zero XMM register pxor xmm 0, xmm 0 // setup factor XMM register movd xmm 1, factor pshufd xmm 1, $00 // load source wave samples @again: // process 2 x 16 bit samples(L/R) movdqu xmm 2, [edx + eax*4] movdqu xmm 3, xmm 2 // unpack samples to 32 bit punpcklwd xmm 2, xmm 0 punpckhwd xmm 3, xmm 0. . . BBTE, Alkalmazások és operációs rendszerek optimizálása . . . // multiply samples by 0 – 1024 // (and add with zero) pmaddwd xmm 2, xmm 1 pmaddwd xmm 3, xmm 1 // divide samples by 512 psrad xmm 2, 9 psrad xmm 3, 9 // pack samples to 16 bit with // signed saturation packssdw xmm 2, xmm 3 // store destination samples movdqu [edx + eax*4], xmm 2 // loop to next samples // 4 x (2 x 16) bit each step add eax, 4 cmp eax, stop jb @again end; 2006
36 Hangerősség – SSE 3 a asm // setup indexing, ensure 16 byte allign mov edx, paddr mov eax, start // eax = i and edx, $fffffff 0 and eax, $fffffffc // setup zero XMM register pxor xmm 0, xmm 0 // setup factor XMM register movd xmm 1, factor pshufd xmm 1, $00 // load source wave samples , also // prefetch data for the next cycle @again: movdqa xmm 2, [edx + eax*4] // we process 2 samples (L-R) // and each is 2 bytes movdqa xmm 3, xmm 2 movdqa xmm 4, [edx + eax*4 + 16] movdqa xmm 5, xmm 4 movdqa xmm 6, [edx + eax*4 + 32] movdqa xmm 7, xmm 6. . . BBTE, Alkalmazások és operációs rendszerek optimizálása . . . // unpack samples to 32 bit punpcklwd xmm 2, xmm 0 punpckhwd xmm 3, xmm 0 punpcklwd xmm 4, xmm 0 punpckhwd xmm 5, xmm 0 punpcklwd xmm 6, xmm 0 punpckhwd xmm 7, xmm 0 prefetcht 0 [edx + eax*4 + 48] // load into L 0, L 1, L 2 cache // at least 32 bytes, multiply samples // by 0 - 1024 (and add with zero) pmaddwd xmm 2, xmm 1 pmaddwd xmm 3, xmm 1 pmaddwd xmm 4, xmm 1 pmaddwd xmm 5, xmm 1 pmaddwd xmm 6, xmm 1 pmaddwd xmm 7, xmm 1 prefetcht 0 [edx + eax*4 + 80] // load into L 0, L 1, L 2 cache at least 32 bytes. . . 2006
37 Hangerősség – SSE 3 b . . . // divide samples by 512 psrad xmm 2, 9 psrad xmm 3, 9 psrad xmm 4, 9 psrad xmm 5, 9 psrad xmm 6, 9 psrad xmm 7, 9 // pack samples back to 16 bit with signed saturation packssdw xmm 2, xmm 3 packssdw xmm 4, xmm 5 packssdw xmm 6, xmm 7 // store destination wave samples movdqa [edx + eax*4], xmm 2 movdqa [edx + eax*4 + 16], xmm 4 movdqa [edx + eax*4 + 32], xmm 6 // loop to next samples add eax, 12 // process 12 x (2 x 16) bit samples each step // (2*i, 2*i+1), (2*i+2, 2*i+3), . . . , (2*i+22, 2*i+23) cmp eax, stop jb @again end; BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
38 Köszönöm a figyelmet! BBTE, Alkalmazások és operációs rendszerek optimizálása 2006
- Slides: 38