Alimman ykkösbitin etsintä



Samankaltaiset tiedostot
Ongelma(t): Miten tietokoneen komponentteja voi ohjata siten, että ne tekevät yhdessä jotakin järkevää? Voiko tietokonetta ohjata (ohjelmoida) siten,

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

811120P Diskreetit rakenteet

811120P Diskreetit rakenteet

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

Ongelma(t): Miten mikro-ohjelmoitavaa tietokonetta voisi ohjelmoida kirjoittamatta binääristä (mikro)koodia? Voisiko samalla algoritmin esitystavalla

Algoritmit 2. Luento 13 Ti Timo Männikkö

LOAD R1, =2 Sijoitetaan rekisteriin R1 arvo 2. LOAD R1, 100

Algoritmit 1. Luento 3 Ti Timo Männikkö

13. Loogiset operaatiot 13.1

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

12. Javan toistorakenteet 12.1

12. Javan toistorakenteet 12.1

Tiedon esitysmuodot. Luento 6 (verkkoluento 6) Lukujärjestelmät Kokonaisluvut, liukuluvut Merkit, merkkijonot Äänet, kuvat, muu tieto

Tietokonearitmetiikka

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Tietotyypit ja operaattorit

13. Loogiset operaatiot 13.1

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Sisällys. 12. Javan toistorakenteet. Yleistä. Laskurimuuttujat

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Tietokonearitmetiikka

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

Algoritmit 2. Luento 12 To Timo Männikkö

Johnson, A Theoretician's Guide to the Experimental Analysis of Algorithms.

11. Javan toistorakenteet 11.1

Ohjelmoinnin perusteet Y Python

52480S TIETOKEARKKITEHTUURIT Tentti

Osoitin ja viittaus C++:ssa

TAMPEREEN TEKNILLINEN YLIOPISTO

Tietorakenteet ja algoritmit - syksy

Ohjelmoinnin perusteet Y Python

Algoritmit 2. Luento 14 Ke Timo Männikkö

A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.

Intel Pentium Pro -prosessori. tietokonearkkitehtuurit, syksy -96 Ari Rantanen

Ohjelmoinnin perusteet Y Python

Ohjelmoijan binaarialgebra ja heksaluvut

Numeropelissä 3x3-ruudukko sisältää luvut 1, 2,, 9. Tehtäväsi on järjestää ruudukko näin:

Algoritmit 1. Luento 10 Ke Timo Männikkö

Ohjelmoinnin perusteet Y Python

Harjoitustyö: virtuaalikone

Tietokonearitmetiikka

Tieto ja sen osoite (3) Jakso 3 Konekielinen ohjelmointi (TTK-91, KOKSI) Osoitinmuuttujat. Tieto ja sen osoite (5)

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

Tietokonearitmetiikka

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Harjoitustyön testaus. Juha Taina

Algoritmit 2. Luento 8 To Timo Männikkö

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

Sisällys. 11. Javan toistorakenteet. Laskurimuuttujat. Yleistä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 1 Ti Timo Männikkö

Algoritmit 2. Luento 7 Ti Timo Männikkö

Tietorakenteet ja algoritmit

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 7. joulukuuta 2009

Tietorakenteet, laskuharjoitus 7, ratkaisuja

Java-kielen perusteet

Sisällys. 16. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. Aritmetiikkaa toisin merkiten

Kappale 20: Kantaluvut

Laitteistonläheinen ohjelmointi

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.

1. Keskusyksikön rakenne

TAMPEREEN TEKNILLINEN YLIOPISTO

Olkoon S(n) kutsun merge-sort(a, p, q) tilavaativuus kun p q + 1 = n. Oletetaan merge toteutetuksi vakiotyötilassa (ei-triviaalia mutta mahdollista).

16. Ohjelmoinnin tekniikkaa 16.1

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

VIII. Osa. Liitteet. Liitteet Suoritusjärjestys Varatut sanat Binääri- ja heksamuoto

Jakso 3 Konekielinen ohjelmointi (TTK-91, KOKSI)

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 11 Ti Timo Männikkö

Java-kielen perusteet

Ohjelmoinnin perusteet Y Python

16. Ohjelmoinnin tekniikkaa 16.1

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Tietokoneen rakenne: Harjoitustyö. Motorola MC prosessori

811312A Tietorakenteet ja algoritmit, , Harjoitus 3, Ratkaisu

Ongelma(t): Miten jollakin korkeamman tason ohjelmointikielellä esitetty algoritmi saadaan suoritettua mikro-ohjelmoitavalla tietokoneella ja siinä

Numeeriset menetelmät

Java-kielen perusteita

Perinteiset tietokoneohjelmat alkavat pääohjelmasta, c:ssä main(), jossa edetään rivi riviltä ja käsky käskyltä.

Tietueet. Tietueiden määrittely

1.3Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

TAMPEREEN TEKNILLINEN YLIOPISTO Digitaali- ja tietokonetekniikan laitos. Harjoitustyö 4: Cache, osa 2

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

7.4 Sormenjälkitekniikka

Jakso 3 Konekielinen ohjelmointi (TTK-91, KOKSI)

Algoritmit 1. Luento 4 Ke Timo Männikkö

Luento 3 (verkkoluento 3) Ttk-91 konekielinen ohjelmointi. Ohjelman esitysmuoto Konekielinen ohjelmointi ttk-91:llä (Titokone, TitoTrainer)

811312A Tietorakenteet ja algoritmit I Johdanto

ANSI/IEEE Std

Määrittelydokumentti

Teemun juustokakku Rekisterien, välimuistin, muistin, levymuistin ja magneettinauhan nopeudet suhteutettuna juuston hakuaikaan juustokakkua tehdessä?

Sisällys. 17. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. for-lause lyhemmin

811120P Diskreetit rakenteet

Sisältö. 2. Taulukot. Yleistä. Yleistä

Transkriptio:

Alimman ykkösbitin etsintä Hannu Peltola hpeltola(at)cs.hut.fi Seminaariesitelmä 7.4.2009 T-106.5800 Algoritmien virittäminen -seminaari Tietotekniikan laitos Teknillinen korkeakoulu Tiivistelmä Algoritmit koostuvat alkeistoimenpiteistä. Algoritmin aikavaativuuden laskeminen menee helposti väärin, jos jonkin yksittäisen alkeistoimenpiteen suoritusajan riippuvuus syötteestä jää huomaamatta tai oletetaan virheellisesti vakioiksi. Toisinaan joidenkin mutkikkaampien alkeistoimenpiteiden implementointi jätetään määrittelemättä tarkasti. Keskeisten alkeistoimenpiteiden tehokkuus on usein ratkaisevaa koko algoritmin käytännön suorituskyvyn kannalta. SVM-merkkijononhakualgoritmin implementoinnin keskeinen ongelma on se, miten paljon hahmon tarkastelukohtaa voidaan siirtää eteenpäin tekstissä. Siinä tarkoituksessa täytyy etsiä bittivektorista alkaen vähemmän merkitsevistä biteistä seuraava mahdollista kohtaa vastaava bitti. Algoritmissa tämä on määritelty funktioksi BSF. Algoritmin analyysissä BSF on oletettu suoritettavaksi vakioaikaisena konekäskynä. Alkuperäisessä muodossa, jossa ei kurkistella merkkejä etukäteen, siirtymän enimmäispituus on hahmon pituus. Mikään nyt käsiteltävistä BSF:n implementoinneista ei hyödynnä tietoa hahmon pituudesta. Haarukointiin perustuvat versiot ovat siksi enemmän tai vähemmän vakioaikaisia. Tässä esityksessä tarkastellaan BSF:n useiden erilaisten toteutusten käytännön suoritusnopeutta erilaisilla testiaineistoilla. Implementointikokeilut painottuvat ehdollisten hyppykäskyjen nopeuttamiseen ja korvaamiseen laskennalla. Esityksessä keskitytään C-kieleen ja rajoitutaan x86-arkkitehtuuriin sekä gcc-kääntäjään. 1 Johdanto Merkkijononhaussa (engl. string matching) etsitään kohdat, joissa annettu hahmo esiintyy tekstissä. Merkitään n merkin mittaista tekstiä T = t 1 t 2 t n ja m merkin mittaista hahmoa P = p 1 p 2 p m. Bittivektori (engl. bitvector) tarkoittaa biteistä koostuvaa muuttujatyyppiä, jota voidaan käsitellä loogisilla operaattoreilla (maskauksia): (inklusiivinen) OR; & AND; (yhden) komplementti; ˆ XOR, ekslusiivinen OR;! negaatio (ei kovin käyttökelpoinen) sivuttaissiirrot: << vasemmalle ja >> oikealle (tyypillisesti täytetään nollilla). Sivuttaissiirroissa käytetään tyypillisesti samaa rajoitusta kuin C-kielessä: siirron pituuden täytyy olla pienempi kuin operandin bittimäärä. 1

vertailuoperaattoreilla: ==,! =, >=, >, <= ja < aritmeettisilla operaattoreilla: + ja harvoin myös kahden komplementti 1 : Paras bittivektorin koko on käytetyn laitteiston rekisterin leveys. Toisaalta gcc-kääntäjä on jo pitkään osannut tuottaa 32-bittistä koodia, joka käsittelee 64 bittisiä muuttujia (useammalla operaatiolla). C-kielessä käyttökelpoisin muuttujatyyppi on etumerkittömissä tarkan levyisissä kokonaisluvuissa (engl. Exact-width integer types); erityisesti uint32 t ja uint64 t 2. Kannattaa muistaa, että x86:n SSE-käskykanta puolestaan käsittelee 128 bittisiä rekistereitä. Muutamissa bittirinnakkaisissa merkkijononhakualgoritmeissa tarvitaan alkeistoimenpidettä, jossa bittivektorista haetaan seuraavaa tietyn arvoista bittiä. Terminologiassa tehtävä on vakiintunut ykkösbitin hakemiseksi; nollabittihän löytyy triviaalisti komplementoimalla argumentti. Jos etsintä aloitetaan vähemmän merkitsevistä biteistä, selvitetään lopussa olevien nollien määrä (engl. number of trailing zeros). Päinvastaiseen suuntaan edetessä ratkaistaan edeltävien nollien määrä (engl. number of leading zeros). Bitin haku -ongelma on vanha ja ratkaisuja on useita [6, s. 15, ss. 84 87], mutta suuri osa lienee dokumentoimatta ja julkaisematta. Tässä esityksessä keskitytään Shift-Vector Matching (SVM) algoritmissa [5] tarvittavaan alinta bittiä seuraavan nollabitin etsintätapoihin. Käytännössä useimmissa tapauksissa bittivektoria siirretään ensin bitti oikealle ja komplementoidaan sitten, jolloin itseasiassa haetaan alinta ykkösbittiä. 2 Shift-Vector Matching Tavanomaisilla syötteillä Boyer Moore-algoritmi [2] ja sen eri variaatiot ovat erinomaisia. Niiden akilleen kantapäänä ovat toisteiset hahmot ja tekstit. Sillä tavallinen Boyer Moore-pohjainen algoritmi unohtaa hahmon siirron yhteydessä kaiken näkemästään. Tuon tyyppisten algoritmien aikavaativuuden kannalta keskeistä on hahmon siirtäminen useampia positioita kerrallaan. Jokainen tekstistä tutkittu merkki rajoittaa sitä, missä kohdissa hahmo voi esiintyä tekstissä; näin ei käy, jos hahmo koostuu samasta merkistä ja löydettiin tekstistä juuri se. SVM-algoritmin idea on käyttää bittivektoria, johon talletetaan tieto siitä, missä hahmo ei voi esiintyä. Hahmon siirron yhteydessä bittivektoria päivitetään samanmittaisella sivuttaissiirrolla. SVM-algoritmin [5] pseudokoodi on esitetty seuraavassa Algoritmina 1. Kaikkien mahdollisten merkkien joukkoa aakkostoa merkitään Σ:lla. Koska sivuttaissiirroissa vapautuvat bitit täytetään nollilla, on luontevaa käyttää mahdottoman esiintymiskohdan merkkinä arvoa yksi. Silloin päädytään automaattisesti bittivektorin päivittämiseen OR-operaatioilla. Jotta saadaan mahdollisimman paljon positioita bittivektoriin, täytyy tutkittavana olevaa kohdistusta vastaavan bitin olla jommassa kummassa päässä. Algoritmissa 1 tutkittavana oleva kohta on vähiten merkitsevässä bittissä. Valinnan syynä oli se, että rivillä 8 käytettävä maski 1 on helppo ja nopea muodostaa. Jos eri suuntiin toimivien sivuttaissiirtojen suorituskyvyssä on eroa, niin niiden suunnan muuttamista kannattaa harkita. 1 C:ssä erityisesti tyypeille Exact-width integer types on taattu kahden komplementtiesitys 2 Vielä versio 4.3.2. ei osaa 64 bittiä laajempia tyyppejä 2

Algoritmi 1 SVM(P = p 1 p 2 p m, T = t 1 t 2 t n ) /* Preprocessing */ 1: for all c Σ do C[c] 1 m 2: for j 1 to m do 3: C[p j ] C[p j ] & 1 j 1 01 m j /* Searching */ 4: epos m; S 0 5: while epos n do 6: S S C[tepos] 7: j 1 8: while (S&1) = 0 do 9: if j m then 10: report an occurrence at epos + 1 m 11: goto Over 12: S S (C[tepos j] >> j) 13: j j + 1 14: Over: 15: last BSF( (S >> 1))+1 16: S S >> last 17: epos epos + last Funktioon BSF tultaessa nykyinen kohdistus on tutkittu ja voidaan siirtyä ainakin yksi positio eteenpäin. Rivillä 15 olevassa kutsussa bittivektoria on siirretty jo eteenpäin. Siitä seuraa, että bittivektorissa on aina ainakin yksi ehdot täyttävä bitti. Näin helpotetaan funktion BSF toimintaa. Samalla taataan, että bittivektorin tarvittava sivuttaissiirto on laillisen mittainen. SVM-algoritmi tyypillisesti tutkii vähemmän tekstin merkkejä ja tekee keskimäärin pidempiä siirtymiä kuin muut merkkijononhakualgoritmit. Kätevä piirre on muiden bittivektoreita käyttävien algoritmien tapaan se, että esimerkiksi isojen ja pienten kirjainten samaistus hoituu helposti alustuksen yhteydessä. Nykyään prosessoreiden ja muistiväylien nopeutuminen on vienyt siihen suuntaan, että hyvin suoraviivaiset algoritmit toimivat nopeimmin. Esimerkiksi esiintymiä tarkastettaessa (rivillä 8) jokaisen tekstistä poimitun merkin jälkeen tapahtuva testaus lienee hidaste; (rivillä 6) kannattaisi samantien lisätä useamman tekstin merkin tiedot summavektoriin S. Myös BSF on suhteellisen raskas toimenpide. SVM-algoritmi on parhaimmillaan, kun etsittävät hahmot ovat melko pitkiä ja sisältävät samoja merkkejä useammassa positiossa. 3 Mahdollisia tehostuskeinoja 3.1 Likely / Unlikely Linuxin kernelissä totuusarvolausekkeissa on käytössä funktiokutsuilta näyttävät likely() ja unlikely(). Ne ovat itseasiassa makromäärittelyjä, jotka vinkkaavat gcc-kääntäjälle kumpi vaihtoehto on todennäköisempi: 3

/* from linux/compiler.h */ #define likely(x) builtin_expect(!!(x), 1) #define unlikely(x) builtin_expect(!!(x), 0) Tavoitteena on generoida sikäli optimaalista konekoodia, että todennäköisemmässä vaihtoehdossa ei tehdä yhtään hyppykäskyä, jotka tyhjentäisivät prosessorin liukuhihnan. Yleisesti likely()- ja unlikely()-makroja neuvotaan käyttämään vain, kun toinen vaihtoehdoista on hyvin paljon todennäköisempi. Kääntäjän sisäisen funktion long builtin expect (long exp, long c) semantiikkana on ilmaista, että todennäköisesti exp == c. 3 3.2 Haarautumisten poistaminen Haarautumisia ehdolliset, epäsuorat ja suorat (JMP) hyppykäskyt sekä aliohjelmakutsut (CALL) ja paluut pyritään ennustamaan prosessoreissa omassa yksikössä. Haarautumisten vähentäminen parantaa suorituskykyä, koska [9, luku 3.4.1.1] mahdollisuus ennustaa väärin poistuu haarautumiskohtapuskurissa (branch targer buffer (BTB)) tarvitaan vähemmän alkioita. Ehdolliset hyppykäskyt, joita ei koskaan suoriteta, eivät kuluta BTB:tä Intelin uusissa prosessoreissa hyppykäskyt eivät mielellään saisi olla kolmea sisäistä käskyä (µops) lähempänä toisiaan [9, luku 3.4.1]. AMD Athlon 64 ja Opteron kykenee ennustamaan 16 tavun alueella enintään kolme haarautumista. Haarautuminen, joka ylittää 16 tavun rajan, kirjataan kohdealueelle. Ennustettujen rajoja ylittävien haarautumisten tapauksessa käskyjen valmistelu pysähtyy. Haarautumiset kannattaisi siis järjestää niin, ettei 16 tavun alueen rajaa ylitetä; täytekäskyjen lisääminen väliin ei ole kannattavaa. (Koskee myös 32-bittistä koodia.) [10, ss. 126 127] Haarautumisten poistamisessa viisi keskeistä keinoa ovat [9, luku 3.4.1.1] järjestetään ohjelmakoodi niin, että peruslohkot kasvavat puretaan (unroll) silmukoita (osittain tai kokonaan) käytetään ehdollisia siirtokäskyjä x86-arkkitehtuurissa cmov (Intelillä Pentium II ja myöhemmät; AMD:llä K7:sta lähtien) lataamalla totuusarvo rekisteriin x86-arkkitehtuurissa setcc ja käyttämällä näin saatua kahta vaihtoehtoista arvoa käytetään SSE ja SSE2 käskyjä, jotka suorittavat muuten ehdollisia operaatiota: ANDPS, ANDPD, ANDNPS, ANDNPD, CMPPS, CMPSS, CMPPD, CMPSD, MINPS, MINSS, MINPD, MINSD, MAXPS, MAXSS, MAXPD, ORPS, ORPD, PAND, PANDN, PCMPEQB, PCMPEQD, PCMPEQW, PCMPGTB, PCMPGTD, PCMPGTW, PMAXSW, PMAXUB, PMAXSW, PMAXUB, PMINSW, PMINUB, POR, PXOR, XORPS ja XORPD. 32- bittisessä koodissa on käytettävissä 3DNow! käskyistä PCMPGTB, PCMPGTD, PCMPGTW, 3 http://gcc.gnu.org/onlinedocs/gcc/other-builtins.html 4

PFCMPGT, PFCMPGE, PFMIN, PFMAX, PAND, PANDN, POR, PXOR ja PXOR. [10, s. 136] 3.2.1 Hyppykäskyjen poistaminen Ohjelmointikielissä totuusarvoja vastaavat numeeriset arvot 0 ja 1. Ne voidaan muuttaa muiksi kokonaislukuarvoiksi monella tavalla; vaikka kertolaskulla ja sitten yhteenlaskulla. Perinteinen temppu C-kielellä on kahden komplementtimuotoa hyödyntävä lauseke (<totuusarvo>)-1)&<arvo> Toinen vastaava on (-(!<totuusarvo>))&<arvo> Numeerisen arvon muuntaminen totuusarvoksi käy esimerkiksi ( Bool),!! ja ==0. Prosessorivalmistajien optimointioppaissa neuvotaan tyypillisesti hyppykäskyjen poistoa vain symbolisella konekielellä [9, s. 3-8] ja [10, ss. 136 140]. C-kielisiä haarautumatonta koodia käyttäviä ratkaisuja löytyy yleisesti minimin tai maksimin laskemiseen. Yleensä ne eivät varaudu mitenkään yli- tai/ja alivuotoihin [6, ss. 37 38]. 3.2.2 Ehdolliset siirtokäskyt Ehdolliset siirtokäskyt (engl. conditional move) [6, s. 8, 38] ovat tehokkaita käskyjä: esimerkiksi minimin tai maksimin laskeminen sujuu kahdella käskyllä. Valitettavasti niiden käyttö C-kielestä ei ole kovin luontevaa ja objektikoodin optimaalisuus heikkenee, jos sivuvaikutusten takia joudutaan käyttämään volatile-tarkenninta. Toisaalta kääntäjät voivat halutessaan generoida ehdollisia siirtokäskyjä. 4 BSF variaatioita Seuraavaksi esitellään joukko BSF-funktion implementointeja C-kielellä. Niissä bittivektorit voivat olla joko 32 tai 64 bittisiä; tyyppimäärittelyinä vastaavasti uint32 t ja uint64 t. Bittivektoreiden bittimäärää ohjataan käännösaikaisella vakiolla BITS, jonka voi halutessaan määritellä käännöskomennossa. Summavektorina käytetään muuttujaa sv (pseudokoodissa S). Apubittivektori x on saman kokoinen. Tutkittavan kohdistuksen loppukohtaan tekstissä osoittaa osoitin s (pseudokoodissa epos). Testiajot on suoritettu 2,8 GHz Pentium D (dual core) prosessorilla, jonka molemmilla loogisilla prosessoreilla on 16 KB L1 data välimuistia ja 1024 KB L2 välimuistia. Keskusmuistia on 1 GB. Käyttöjärjestelmänä on Fedora 8. Prosessin vaihto toiselle prosessorille tyhjentää vaihtelevassa määrin välimuisteja. Tämä hidastaa datan noutoa keskusmuistista ja tuo testiajojen ajanmittauksiin vaihtelua. Tässä tarkoituksessa on käytetty Linux in funktiota sched setaffinity, jolla prosessi on kiinnitetty yhteen (loogiseen) prosessoriin. Testattavat ohjelmat on käännetty gcc-kääntäjän versiolla 4.1.2 optimointitasolla -O3. Testiajoissa käytettiin aineistona kolmen tyyppistä tekstiä: englantia, DNA jonoa ja satunnaisesti tasanjakautuneesti kahta merkkiä sisältävää binääridataa. Kunkin tekstin koko on vajaa miljoona merkkiä. Etsittävinä hahmojoukkoina käytettiin vastaavantyyppisiä 200 hahmon joukkoja. Hahmojen pituudet ovat 5, 10, 20, 30, 40, 50 ja 60 merkkiä. Tuloksissa on tilan säästämiseksi annettu tulokset neljältä lyhimmältä hahmojoukolta ja DNA:lta lisäksi 50 mittaisilta hahmoilta. 5

Yksittäisen BSF-funktion suorituksen kesto on niin pieni, että sen mittaaminen suoraan on lähes mahdotonta. Koska se on SVM-algoritmin suoritettavassa koodissa ainoa muuttuva kohta, on luontevaa mitata koko algoritmin suoritukseen kuluvaa aikaa. Kunkin hahmon haku on toistettu 50 kertaa, jotta ajanmittaukseen saadaan tarkkuutta. 4.1 BSF-0 Intelin IA-32-arkkitehtuurin käskykannassa on konekäskyt bsfw ja bsfl. bsfw tuo ensimmäisen argumentin osoittamassa kohdassa olevan sanan (word = 16 bittiä) vähiten merkitsevässä päässä olevien nollabittien määrän toisena argumenttina annettuun rekisteriin. Jos ensimmäinen argumentti sisältää pelkästään nollia, prosessorin ZF lippu (flag) asetetaan (eli saa arvon 1). bsfl-käskyn operandina on kaksoissana (longword) ja 64-bitin käskykannassa bsfq-käskyn operandina on nelisana (quadword)[8]. BSF-käsky lisättiin käskykantaan 80386:ssa [3, s. 112]. asm on gcc-kääntäjän laajennus, jolla voidaan sisällyttää ohjelmaan symbolisia konekäskyjä niin, että operandit on määritelty C-kielen tavoin. 4 On myös mahdollista käyttää useampia peräkkäisiä symbolisia konekäskyjä. Seuraavassa on bsfl- ja bsfq-käskyille käytetyt esittelyt: #if defined x86_64 static inline unsigned long asm_bsf(bitv x) { #if BITS==64 asm ("bsfq %0, %0" : "=r" (x) : "0" (x)); #else asm ("bsfl %0, %0" : "=r" (x) : "0" (x)); #elif defined i386 static inline unsigned long asm_bsf(unsigned long x) { asm ("bsfl %0, %0" : "=r" (x) : "0" (x)); #else # error wrong kind of instruction set return x; } Alimman nollabitin etsintä käy edellisten määrittelyjen avulla helposti [1]. Seuraavaa koodia mutkistaa tilanne, jossa 64 bittisiä bittivektoreita käsitellään 32-bittisellä käskykannalla: x = (sv >>= 1); /* where is lowest zero bit in sv */ /* http://www.jjj.de/bitwizardry/files/bitasm.h */ /* if bitvectors have 64 bits, but registers only 32 */ #if BITS==64 && defined i386 j = asm_bsf(x); if((j==0) && ((x&0xffffffff)==0)) { 4 http://gcc.gnu.org/onlinedocs/gcc/extended-asm.html 6

#else } j = asm_bsf(x); sv >>= j; s += j+1; j = 32 + asm_bsf(x>>32); Taulukko 1: Hakuajat BSF-0:lla millisekunteina eri käskykannoilla (KK) ja bittivektoreilla (BV). hahmot Englannin kieli DNA binääri KK / BV 5 10 20 30 5 10 20 30 50 5 10 20 30 64 / 64 1191 711 415 301 1356 793 470 347 237 2399 1500 875 640 64 / 32 965 585 348 257 1125 657 392 291 2007 1259 737 538 32 / 32 956 581 346 254 1148 655 390 291 2009 1265 740 541 32 / 64 1544 928 543 388 1780 1024 595 432 325 3036 1897 1104 805 SVM-algoritmin tapauksessa suorituskykyero 64- ja 32-bittisen käskykannan välillä näyttää olevan mitätön ja jopa vähän ristiriitainen: binääridatalla 64-bittinen näyttää olevan nopeampi, mutta muilla aineistoilla hitaampi. Bittivektorin koolla on huomattava merkitys. 64 bittisillä vektoreilla aikaa kuluu jopa yli 20% enemmän kuin 32 bittisillä. Suhteellinen ero ei näytä riippuvan hahmojen pituudesta; ei myöskään tutkittujen merkkien lukumäärästä. Tilanteeseen vaikuttaa mahdollisesti se, että 32 bittisen operandin etumerkin laajennus (sign extension) 64 bittiin on nopeampaa kuin yläosa nollaus (zero extension) [9, luku 9.2.4]. 32-bittisellä koodilla ja 64 bittisillä bittivektoreilla tehty testi osoittaa, että 64-bittisellä koodilla voisi käsitellä 128 bittisiä bittivektoreita vielä siedettävän nopeasti ja hakea hahmoja, joiden pituus on enintään 128 merkkiä. 4.2 BSF-1 Kaikkein yksinkertaisin ratkaisu on siirtää summavektoria yhdellä bitillä oikealle, ja lopettaa, kun nollabitti löytyy: do { /* NOT EFFICIENT, BUT WORKS */ sv >>= 1; s += 1; } while(sv&1); Menetelmän hyviä puolia ovat ne, ettei tarvita mitään valmisteluita eikä lopuksi päivityksiä. Nopeuskin on hyvä, jos nollabitti löytyy pian; näin käy ainakin, kun hahmo on melko lyhyt. Navarro ja Raffinot ovat käyttäneet tätä tekniikkaa implementoidessaan BM BNDM:ää ja TurboBNDM:ää [4]. Vastaava on myös Warrenin kirjassa [6, s. 86] koodina 5-16. 7

Kannattaa huomata, että kaikki rivit while-silmukassa suoritetaan jokaisella mahdollisella kohdistuksella; siis vähintään n m + 1 kertaa. Tämä saattaa vaikuttaa koko SVM-algoritmin aikavaativuuteen. while-lauseesta generoitavan ehdollisen hyppykäskyn valinta voi vaikuttaa huomattavasti suoritusnopeuteen. Lopetusehdon testauksessa on hyvin luonteva paikka kokeilla likely- ja unlikely-makroja. Koska kyseessä lienee kohdekoneen arkkitehtuurista riippuva tilanne, kokeiltiin käännöksessä vaihtoehtona vipuja -march=nocona -mno-sse3. Testiajon tulokset ovat taulukossa 2. Taulukko 2: Hakuajat BSF-1:lla millisekunteina likely- (L) ja unlikely-makroilla (U). hahmot Englannin kieli DNA binääri versio 5 10 20 30 5 10 20 30 50 5 10 20 30 ei kohdekoneen valintaa BSF-1 1344 1232 1172 1145 1559 1154 1003 926 796 1921 1524 1219 1147 BSF-1L 1322 1243 1317 1158 1543 1168 1062 941 804 1898 1520 1253 1161 BSF-1U 1326 1226 1176 1146 1584 1150 1012 932 802 1938 1468 1212 1164 kohdekoneen valintana -march=nocona -mno-sse3 BSF-1 2019 1534 1253 1112 1855 1327 1050 909 778 2057 1661 1388 1233 BSF-1L 1353 1219 1164 1139 1584 1141 992 923 794 1954 1506 1231 1159 BSF-1U 1341 1233 1288 1146 1580 1153 1035 934 798 1913 1502 1247 1168 Keskim. siirtymä 4,56 7,99 14,10 19,93 3,69 6,33 10,85 15,03 22,52 2,97 5,01 8,68 11,96 Suurin testissä havaittu ero ilmeni BSF-1:llä: kohdekoneen määrittely tuotti selvästi hitaampaa koodia muilla kuin vähintään 30 mittaisilla ja sitä pidemmillä hahmoilla. Toisaalta niillä BSF-1 ei ole muutenkaan kilpailukykyinen. Likely-makroa käyttävästä BSF-1L:stä generoitui nopeampaa koodiaa määrittelemällä kohdekone (paitsi 5 mittaisilla hahmoilla). Unlikely-makrolla varustetulla BSF-1U:lla kävi päinvastoin paitsi yli 30 mittaisilla DNA jonoilla. Perusversioon BSF-1 verrattuna likely- ja unlikely-makroilla näyttää olevan selvää merkitystä vain kun kohdekone valitaan; silloinkin niiden kahden ero on aika pieni. Intel neuvoo, että usein suoritettavissa silmukoissa tulisi olla enintään 16 iteraatiota kullakin suorituskerralla [9, s. 3-7]. Toisaalla todetaan, että Pentium M prosessoreilla ei kannata purkaa silmukoita, joissa on iteraatioita yli 64 [9, s. 3-15]. Englannin kielellä 16 iteraation raja ylittyy melko usein jo 20 merkin mittaisia hahmoilla. DNA:lla 30 mittaisilla hahmojonoilla 16 iteraatiota ylittyy likimain joka toinen kerta. Kun verrataan BSF-1:n (taulukossa 2 ilman kohdekoneen valintaa) BSF-0:n hakuaikoihin (taulukossa 1), havaitaan 5 mittaisilla binäärihahmoilla BSF-1:n olevan nopeampi. Tämä johtuu ilmeisesti siitä, että keskimääräinen hahmon siirto on vain 2,97, kun se on 5:n mittaisilla DNA-hahmoilla 3,69. 4.3 BSF-2 Lauseke x & (-x) eristää oikeanpuoleisimman (=vähiten merkitsevän) 1-bitin; tulos on nolla, jos yksikään bitti ei ole viritetty. Toisin sanoen kaikki muut paitsi oikeanpuoleisin 1-bitti nollataan. Ilmeisesti vastaavaa lauseketta vasemmanpuolimmaiselle 1-bitille ei ole [6, ss. 11 12]. Edellä olevassa 8

lausekkeessa oletetaan kahden komplementtimuoto. Kun täsmälleen yksi bitti on viritetty, BSF ratkaisee itseasiassa kaksikantaisen logaritmin. Kun täsmälleen yksi bitti on viritetty, sen etsintä maskeilla käy puolitusperiaatteella seuraavasti [1]. Käytettävien testien järjestys on vapaa. j = 0; x = (sv >>= 1); x &= -x; /* clear all other but the lowest set bit */ /* where is lowest zero bit in sv */ /* http://www.jjj.de/bitwizardry/files/bitlow.h */ #if(bits==32) if(x & 0xffff0000) j += 16; if(x & 0xff00ff00) j += 8; if(x & 0xf0f0f0f0) j += 4; if(x & 0xcccccccc) j += 2; if(x & 0xaaaaaaaa) j += 1; #elif(bits==64) if(x & 0xffffffff00000000) j += 32; if(x & 0xffff0000ffff0000) j += 16; if(x & 0xff00ff00ff00ff00) j += 8; if(x & 0xf0f0f0f0f0f0f0f0) j += 4; if(x & 0xcccccccccccccccc) j += 2; if(x & 0xaaaaaaaaaaaaaaaa) j += 1; #else abort(); sv >>= j; s += j+1; Tuo implementointi on vakioaikainen. Jos käytettäisiin hyväksi sitä, että siirtymä on enintään hahmon pituinen, aikavaativuus riippuisi pituuden logaritmista. Täysleveät bittimaskit ovat potentiaalinen ongelma: Ainakin Intelin NetBurst-arkkitehtuurissa voi ilmetä hidastumista, jos yli 16 bittisiä vakioita (immediates) käyttävän käskyn perään laitetaan toisia käskyjä, jotka käyttävät vakioita [9, s. 3-4]. 4.4 BSF-3 BSF-2:ssa tavun sisällä olevien bittien haarukointiin kuluu kolme testiä! Tavun sisältä vähiten merkitsevien nollabittien määrä voidaan taulukoida seuraavasti: static const unsigned char lowest_bit_in_byte[] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 9

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; Sivuttaissiirroilla tutkittavaa aluetta puolittamalla voidaan ainoan ykkösbitin sisältävä tavu siirtää näppärästi oikeaan laitaan. Tavusta ykkösbitti löytyy nopeasti edellä määritellyn taulukon avulla: j = 0; x = (sv >>= 1); x &= -x; /* clear all other but the lowest set bit */ /* where is lowest zero bit in sv */ #if(bits==32) if(x >> 16) {j += 16; x >>= 16;} if(x >> 8) {j += 8; x >>= 8;} #elif(bits==64) if(x >> 32) {j += 32; x >>= 32;} if(x >> 16) {j += 16; x >>= 16;} if(x >> 8) {j += 8; x >>= 8;} #else abort(); j += lowest_bit_in_byte[x & 0xFF]; sv >>= j; s += j+1; Hahmon pituushan on maksimisiirtymä. Siten BSF-3:ssa on itseasiassa tiedossa, että ensimmäinen if-ehto ei ole tosi koskaan, kun hahmonpituus on enintään puolet bittivektorista. Lisäämällä ensimmäiseen if-ehtoon ja 64 bittisessä tapauksessa myös toiseen unlikely-makro saadaan aikaan BSF-3U. BSF-3 on toteutettavissa myös luvussa 3.2.1 esitetyllä tavalla ilman hyppykäskyjä esimerkiksi seuraavasti: #if(bits==32) j = (((x >> 16)==0)-1)&16; /* j gets 0 or 16 */ 10

j += (((x >> j+8)==0)-1)&8; #elif(bits==64) j = (((x >> 32)==0)-1)&32; /* j gets 0 or 32 */ j += (((x >> j+16)==0)-1)&16; j += (((x >> j+8)==0)-1)&8; #else abort(); j += lowest_bit_in_byte[(x >> j) & 0xFF]; 4.5 BSF-4 Jos sivuttaissiirtojen suoritusnopeudessa eri suuntiin on eroja, BSF-3:n if-ehdoissa käytetyt sivuttaissiirrot voidaan kääntää, jolloin saadaan seuraava versio: j = 0; x = (sv >>= 1); x &= -x; /* clear all other but the lowest set bit */ /* where is lowest zero bit in sv */ #if(bits==32) if(!(x << 16)) {j += 16; x >>= 16;} if(!(x << 24)) {j += 8; x >>= 8;} #elif(bits==64) if(!(x << 32)) {j += 32; x >>= 32;} if(!(x << 48)) {j += 16; x >>= 16;} if(!(x << 56)) {j += 8; x >>= 8;} #else abort(); j += lowest_bit_in_byte[x & 0xFF]; sv >>= j; s += j+1; Warrenin kirjassa [6, s. 85] koodi 5-15 on samankaltainen; vastaava ylimmän ykkösbitin etsintä on koodissa 5-6. Samaan tapaan kuin BSF-3 on implementoitavissa ilman hyppykäskyjä myös BSF-4 voidaan toteuttaa vaikkapa seuraavasti. Sivuttaissiirtoja oikealle on vain yksi indeksoinnissa! #if(bits==32) j = (((_Bool)(x << 16))-1)&16; j += (((_Bool)(x << 24-j))-1)&8; #elif(bits==64) j = (((_Bool)(x << 32))-1)&32; j += (((_Bool)(x << 48-j))-1)&16; j += (((_Bool)(x << 56-j))-1)&8; 11

#else abort(); j += lowest_bit_in_byte[(x>>j) & 0xFF]; Warrenin kirjassa [6, s. 80] on myös etumerkin laajentamiseen perustuva ratkaisu koodina 5-10. Sitä kutsutaan seuraavassa nimellä BSF-5a. Taulukko 3: Hakuajat BSF-3:lla ja BSF-4:lla perus- ja haarautumattomilla (BF) versioilla millisekunteina. hahmot Englannin kieli DNA binääri versio 5 10 20 30 5 10 20 30 50 5 10 20 30 BSF-3 1085 939 613 505 1169 844 561 463 364 2046 1316 807 633 BSF-3BF 2113 1375 770 572 2070 1293 773 575 440 3202 1960 1156 856 BSF-4 1045 915 596 480 1145 827 555 457 357 1988 1277 781 613 BSF-4BF 2040 1199 699 506 2001 1173 695 510 390 3105 1909 1115 816 BSF-3U 1086 941 621 512 1171 847 567 477 365 2047 1311 806 643 BSF-5a 2430 1422 821 592 2332 1367 808 593 403 3561 2189 1275 932 Sivuttaissiirtoihin perustuvien versioiden vertailu on taulukossa 3. BSF-5a ja BSF-3:n versio unlikely-makrolla ovat selvästi toivottoman hitaita. BSF-4 toimii nopeammin kuin BSF-3. Vielä selkeämmin perusversiot ovat nopeampia kuin haarautumattomat versiot. Niiden välinen ero on suurempi lyhyillä kuin pidemmillä hahmoilla. Koska lyhyillä hahmoilla siirtoja on enemmän, tuo ero viittaa siihen, että haarautumaton koodi on huomattavasti hitaampaa. 5 Yhteenvetoa ja täydentäviä havaintoja Liitteessä A taulukon 5 laadinnassa käytetty prosessori on varsin lähellä testeissä käytettyä. Niistä vahvistuu edellisistä testeistä syntynyt epäilys sille, että sivuttaissiirto oikealle on hidas. Erityisen hidasta se näyttää olevan 64 bittisillä tiedolla. Siksi yhteenvetotesti on mielekkästä tehdä 32 bittisillä bittivektoreilla. Taulukko 4: Hakuaikojen (millisekunteina) vertailu 32 bittisillä bittivektoreilla. hahmot Englannin kieli DNA binääri versio 5 10 20 30 5 10 20 30 5 10 20 30 BSF-0 954 580 346 253 1114 654 391 291 2011 1265 740 541 BSF-1 1154 693 600 546 1247 743 585 510 1483 1073 820 736 BSF-1L 2114 1922 1722 1601 1927 1572 1394 1227 2456 1935 1670 1559 BSF-2 1334 957 600 489 1436 907 597 474 1967 1255 779 626 BSF-3 824 730 471 376 935 688 456 373 1697 1095 677 536 BSF-4 820 708 462 371 931 660 440 359 1684 1074 655 506 Testeissä käytetyssä prosessorissa BSF-konekäskyt ovat suhteellisen hitaita. Niitä kannattaa 12

käyttää 32 bittisillä bittivektoreilla vasta, kun keskimääräinen siirtymä on vähintään 10. 64 bittisillä bittivektoreilla kannattavuusraja on alempana. Alle 10 mittaisilla hahmoilla BSF-1 on todennäköisesti paras binääridatalla; muuntyyppisellä aineistolla BSF-4 on paras. Sivuttaissiirrot kannattaa järjestää tällä prosessorilla mahdollisuuksien mukaan vasemmalle. Jos siirretään oikealle, niin käytetään mieluummin 32 kuin 64 bittisiä bittivektoreita. Likely- ja unlikely-makrot eivät näytä hyödyllisiltä. Haarautumaton koodi ei vaikuta nopealta. Core 2 -sarjan prosessoreissa kaikki näyttää olevan toisin ;-) Viitteet [1] Jörg Arndt: Jörgs useful and ugly BIT WIZARDRY page. URL: http://www.jjj.de/bitwizardry/ bitwizardrypage.html. [2] Robert S. Boyer and J Strother Moore: A fast string searching algorithm. Communications of the ACM, 20(10):762 772, 1977. [3] Agner Fog: 4. Instruction tables. Lists of instruction latencies, throughputs and micro-operation breakdowns for Intel and AMD CPU s. Copenhagen University Collage of Engineering. (Last updated 2008-08-24) URL: http://www.agner.org/optimize/instruction tables.pdf [4] Gonzalo Navarro and Mathieu Raffinot: Fast and flexible string matching by combining bitparallelism and suffix automata. ACM Journal of Experimental Algorithms, 5(4):1 36, 2000. [5] Hannu Peltola and Jorma Tarhio. Alternative algorithms for bit-parallel string matching. In String Processing and Information Retrieval, 10th International Symposium, SPIRE 2003, volume 2857 of Lecture Notes in Computer Science, pages 80 94, Springer-Verlag, Berlin, 2003. [6] Henry S. Warren, Jr.: Hacker s Delight. ISBN-10: 0-201-91465-4, ISBN-13: 978-0-201-91465- 8. Addison-Wesley, 2003 [7] Assembler Instructions with C Expression Operands URL: http://gcc.gnu.org/onlinedocs/gcc/ Extended-Asm.html [8] Intel R 64 and IA-32 Architectures Software Developer s Manual. Volume 2A: Instruction Set Reference, A-M. Order Number: 253666-029US URL: http://download.intel.com/design/ processor/manuals/253666.pdf November 2008 [9] Intel R 64 and IA-32 Architectures Optimization Reference Manual. Order Number: 248966-017 URL: http://download.intel.com/design/processor/manuals/248966.pdf December 2008 [10] Software Optimization Guide for AMD64 Processors. Publication # 25112 Revision: 3.06 URL: http://www.amd.com/us-en/assets/content type/white papers and tech docs/25112.pdf September 2005 13

A Eräiden keskeisten käskyjen suorituskykytietoja Operandit i = käskyssä oleva vakio; r = joku rekisteri, r16 = 16 bitin rekisteri, r32 = 32 bitin rekisteri, r64 = 64 bitin rekisteri; m = muistissa oleva operandi; myös epäsuorasti osoitettu. cl tarkoittanee rekisteristä tavun kokoista osaa. µops Ops Dekoodattujen mikrokäskyjen määrä. (Ne talletetaan trace cache een.) Dekoodattujen (sisäisten) makrokäskyjen määrä. Latenssi Minimi määrä kellojaksoja ennenkuin seuraavan riippuvan käskyn suoritus voi alkaa samassa (suoritus)yksikössä. Ei sisällä muistista noutoa, jos operandi voi olla rekisterissä tai muistissa (r/m). Tavallisempi merkitys termille latenssi kuin seuraava. P4 ja P4E prosessoreissa tulee yhden kellojakson ylimääräinen latenssi, kun jossain (suoritus)yksikössä suoritettavan mikrokäskyn (µop) tulosta tarvitaan jossain muussa yksikössä. Läpäisykyky Keskimääräinen määrä kellojaksoja (suorituksen alusta) ennenkuin seuraavan saman tyyppisen riippumattoman käskyn suoritus voi alkaa samassa (suoritus)yksikössä. Esimerkiksi arvo 0.25 tarkoittaa 4 käskyä kellojaksossa (yhdessä threadissä). Harvinaisempi merkitys termille latenssi (issue latency). Taulukko 5: Intel Pentium 4E (Family 15, Model 4) [3]. Käsky operandit µops latenssi läpäisykyky ADD, SUB r,r 1 1 0.25 ADD, SUB r,m 2 1 1 ADD, SUB m,r 3 5 2 AND, OR, XOR r,r 1 1 0.5 AND, OR, XOR r,m 2 1 1 AND, OR, XOR m,r 3 5 2 BSF, BSR r,r/m 2 16 4 SHL r,i 1 1 0.5 SHL r,cl 2 2 2 SHL, SHR m8/16/32,i 3 10 SHL, SHR m8/16/32,cl 2 10 SHR r8/16/32,i 1 1 0.5 SHR r64,i 1 7 2 SHR r8/16/32,cl 2 2 2 SHR r64,cl 1 8 14

Taulukko 6: Intel Core 2 (45nm) (Family 6, Model 23) [3]. Käsky operandit µops latenssi läpäisykyky ADD, SUB r,r/i 1 1 0.33 ADD, SUB r,m 1 1 1 ADD, SUB m,r/i 2 6 1 AND, OR, XOR r,r/i 1 1 0.33 AND, OR, XOR r,m 1 1 1 AND, OR, XOR m,r/i 1 6 1 BSF, BSR r,r 2 2 1 BSF, BSR r,m 2 1 SHL, SHR r,i/cl 1 1 0.5 SHL, SHR m,i/cl 3 6 1 Taulukko 7: AMD K7 (Family 6 Model 6) [3]. Käsky operandit Ops latenssi läpäisykyky ADD, SUB r,r/i 1 1 1/3 ADD, SUB r,m 1 1 1/2 ADD, SUB m,r 1 7 2.5 AND, OR, XOR r,r 1 1 1/3 AND, OR, XOR r,m 1 1 1/2 AND, OR, XOR m,r 1 7 2.5 BSF r,r 19 7 7 BSF r,m 20 8 8 BSR r,r 23 9 9 BSR r,m 23 10 10 SHL, SHR r,i/cl 1 1 1/3 Taulukko 8: AMD K8 (Family 15, Model 5) [3]. Käsky operandit Ops latenssi läpäisykyky ADD, SUB r,r/i 1 1 1/3 ADD, SUB r,m 1 1 1/2 ADD, SUB m,r 1 7 2.5 AND, OR, XOR r,r 1 1 1/3 AND, OR, XOR r,m 1 1 1/2 AND, OR, XOR m,r 1 7 2.5 BSF r16/r32,r 21 8 8 BSF r64,r 22 9 9 BSF r16,m 20 8 8 BSF r32,m 22 9 9 BSF r64,m 25 10 10 BSR r,r 28 10 10 BSR r,m 28 10 10 SHL, SHR r,i/cl 1 7 3 15