1
Datan rinnakkaistamisessa siis eri prosessointiyksiköt suorittavat saman operaation annetulle datalle, joka pilkotaan prosessointiyksikköjen kesken. Pointti on siis se, että kyseessä ei ole tehtävien rinnakkaistaminen (kuten usein puhuttaessa rinnakkaisuudessa), vaan jokainen prosessointiyksikkö suorittaa saman koodin samanaikaisesti, jolloin datan käsittelyyn saadaan huomattava nopeuslisä. Varsinainen ohjelma voi siis olla yksisäikeinen ja saada silti huomattavan nopeuslisän. Moderneissa grafiikkakorteissa hyödynnetään myös samanlaista toimintamallia 2
3DNow!:n tuki on nykyään lähes loppunut -> ei välttämättä enää löydy tulevaisuuden suorittimista esim. SSE4.2 tuo operaatiot CRC32-summan laskemiseen. SSE4A on AMD:n oma laajennos ja ei ole saatavilla Intelin suorittimissa SSE:n käytössä on olennaista huomioida, että uusin päivitys ei välttämättä ratkaise kaikkia ongelmia. Ei siis kannata ajatella, että otetaan SSE4 käyttöön ja ongelma ratkeaa, koska kaikki SSE2:n jälkeen tulleet versiot ovat suurimmaksi osin käskylaajennoksia ja moni ongelma voi silti olla sellainen, että sen ratkaisemiseen ei tarvitse (tai edes pysty) käyttämään SSE tai SSE2:ta uudempaa tekniikkaa. AVX (Advanced Vector Extensions) on uusi tekniikka ja tulee korvaamaan nykyiset SSEtekniikat, eli SSE tekniikkana on kehityksen/yleistymisen puolesta enemmänkin kallistumassa ehtoopuolelle. AVX:ssä on kuitenki tuki vanhoille SSE-operaatioille, jota toimivat AVX:n rekisterien alemmassa 128 bitissä. AVX Vaatii suhteellisen uuden käyttöjärjestelmän toimiakseen, esim. Windows 7 SP1. AVX:n tarjoama uusi ohjelmointitapa mahdollistaa mm. kahdelle rekisterille tehtävän operaation tuloksen tallentamisen kolmanteen rekisteriin, mikä ei ole ollut aiemmissa tekniikoissa mahdollista. Etuna tässä on, että operaation tulos ei ylikirjoita toisen parametri rekisterin alkuarvoa, kuten aiemmissa tekniikoissa tapahtuu (esim. ennen a = a+b, mutta uudessa c = a+b). 3
Vaikea löytää mitään kunnollista mainospuhetta, koska tekniikka (SIMD/SSE) jo tavallaan mainostaa itse itseään Erityistä hyötyä on kuitenkin mahdollista saada sovelluksissa, jotka käsittelevät suuria datamääriä. Yksittäisten lukujen tapauksessa SSE:n käyttö ei maksa vaivaa, koska tekniikan ajatuksena on nimenomaan ladata paljon dataa ja tehdä sille operaatioita Ohjelman nopeutumiseen SSE:n avulla vaikuttaa tietenkin myös moni muu tekijä, esimerkiksi miten ohjelma on yleisesti ottaen rakennettu ja millainen algoritmi on kyseessä Sovelluskohteet on otettu Intelin näkemyksen perusteella. Näissä kaikissa on nähtävissä samankaltaisuus siinä mielessä, että tiettyä operaatiota tehdään isolle datajoukolle. 4
Tässä siis joitain esimerkkejä, joissa on käytetty SSE-optimointeja Peleissä yleisesti, mutta tässä esimerkkinä Doom3, koska sen lähdekoodit ovat saatavilla ja niistä näkee, että esim. vektori- ja matriisilaskuissa sekä äänen prosessoinnissa on käytetty SSE:tä MS:n DirectX/Direct3D tunnistaa ajonaikaisesti onko SSE:tä mahdollista käyttää Qt:ssa käytetään SSE:tä piirtorutiinien optimointiin ja ainakin on tehty tutkimusta merkkijono-operaatioiden nopeuttamisen osalta VLC-soittimessa SSE:tä käytetään ainakin puskurien kopioinnin nopeuttamiseen Yleisesti ottaen voidaan todeta, että SSE:tä käytetään paljon erilaisissa multimediasovelluksissa ja sovellusalueissa 5
MXCSR rekisteri sisältää tietoa liukulukuoperaatioista, mm. poikkeukset ja pyöristysten kontrollointi Jokaista SSE:n rekisteriä (XMMn) voi käsitellä erikseen 32 bittiset luvut pakataan 128 bittiseen rekisteriin omiin lokeroihinsa. Kaikkien neljän skalaarin käsittely tapahtuu PS-päätteisillä käskyillä (Packed Scalar) SSE:ssä on myös käskyjä (SS-päätteiset Single Scalar), joilla voidaan käsitellä yksittäisiä skalaareja. Tällöin käsitellään XMMn-rekisterin 32 alinta bittiä ja operaatio ei vaikuta kolmeen ylempään skalaariin. 6
SSE2:n tuomissa käskyissä rekisteri voi sisältää 2 64bit kokonaislukua, 4 32bit kokonaislukua, 8 16bit kokonaislukua, 16 8bit kokonaislukua tai 2 64bit liukulukua. SSE:n tuoma tuki 32bit liukuluvuille on toki edelleen voimassa. Kaikille datatyypeille (kokonaisluku/liukuluku) on omat erilliset käskynsä. SSE2:n myötä päästiin eroon SSE:n ja MMX:n sekakäytöstä. Myöhemmät SSE-versiot eivät tuoneet muuta, kuin joukon uusia käskyjä, joten SSE2:n esittelemä datankäsittelymalli on edelleen voimassa. Loppukommenttina mainitaan, että SSE tarvitsee tuen käyttöjärjestelmältä. Tuki vaaditaan, jotta prosessorin tila osataan tallentaa oikein esimerkiksi ohjelmasta toiseen siirryttäessä, millä vältetään mm. datan korruptoituminen ja hukkuminen. Käytännössä tuki SSE:lle on kaikissa moderneissa käyttöjärjestelmissä, mutta esimerkiksi aiemmin mainitun AVX:n tapauksessa tuki on vasta Windows 7 SP1:stä alkaen. 7
Assemblyllä ohjelmoidessa voi lähdemateriaaliksi ottaa esimerkiksi Intelin SSE-speksin, jossa kaikki käskyt on kerrottu. Ongelmana kuitenkin on, että esim. visual studio ei salli inline assemblyn käyttöä 64bit ohjelmissa. Suositellumpi tapa on käyttää kääntäjän intrinsic-funktioita, jotka on yleensä kuvattu kääntäjän dokumentaatiossa. Ongelmana voi kuitenkin olla eroavaisuudet eri kääntäjien välillä. Kääntäjän vektorointitoiminnoilla vältytään itse kirjoittamasta SSE-koodia. Ajatuksena on, että kääntäjä pyrkii tuottamaan tavallisesta koodista SIMD-periaatteita noudattavaa koodia. Vektorointitoiminnon saa moderneista kääntäjistä käyttöön tietyillä vivuilla, jotka on kuvattu kääntäjän dokumentaatiossa. Ongelma kuitenkin on, että lopputuloksen laatu on täysin kääntäjän päätettävissä ja erityisesti tässä on suuria eroja kääntäjien välillä. Intelin oma kääntäjä tekee useimmiten parasta jälkeä. Joka tapauksessa kääntäjän valmiilla toiminnoilla voi kuitenkin saada pientä nopeuslisää ohjelmaan. 8
Muuttujat näkyvät käyttäjälle ikään kuin unionina, eli 128bit muuttujan eri kohtiin on mahdollisuus päästä käsiksi. Tätä ei kuitenkaan suositella. Kääntäjän tarjoamat intrinsic-funktiot löytyvät parhaiten kääntäjän dokumentaatiosta Esimerkissä (_mm_mul_ps) ps tarkoittaa packed scalar, eli operaatio suoritetaan 128bit muuttujille, joihin on pakattu neljä 32bit liukulukua, ts. saadaan laskettua neljän floatin yhtäaikainen kertolasku Useat liukulukuja käsittelevistä intrinsic-funktioista on nimetty suoraan assemblykäskyjen perusteella, mutta tämä ei päde esim. joidenkin vertailufunktioiden osalta. Kokonaislukujen osalta assembly-käskyt eivät täysin vastaa intrinsic-funktioiden nimeämistä (esim. PADDD -> _mm_add_epi32) Tässäkin ohjelmointitavassa toimitaan hyvin lähellä laitteistotasoa, koska intrinsicfunktiot on mapattu suoraan vastaaviin assembly-käskyihin. Ohjelmointi muistuttaa aika paljon assembly-ohjelmointia, eli annetaan käsky ja operandit, jonka jälkeen saadaan tulos tiettyyn paikkaan. Lisäksi tarvitaan osaamista bittien pyörittelystä, koska monet käskyt ottavat myös bittimaskin, jonka perusteella asioita tehdään. Tästä tulee esimerkkiä myöhemmin. 9
Tässä siis yksinkertainen esimerkki kokonaislukutaulukon nollaamisesta. Ensimmäiseksi ihan tavallinen C++-toteutus vertailun vuoksi. Jälkimmäisessä SSE-toteutus, jossa ensimmäiseksi castataan uusi SSE-tyyppinen kokonaislukuosoitin alkuperäiseen int-taulukkoon Koska int on 32 bittinen ja SSE:n rekisterit ovat 128 bittisiä, voidaan silmukassa käsitellä neljä 32bit kokonaislukua samaan aikaan _mm_setzero_si128-funktio luo uuden m128i muuttujan, jonka kaikki komponentit ovat nollia. _mm_store_si128- funktio sijoittaa muuttujan taulukkoon buf-osoittimen määräämään paikkaan. 10
Tässä siis yksinkertainen esimerkki, miten pistetulo voidaan laskea yhdellä käskyllä - _mm_dp_ps. Vaatii siis SSE4.1-tuen. _mm_dp_ps on 32 bittisille liukuluvuille, _mm_dp_pd on 64 bittisille _mm_set_ps-käskyllä saadaan luotua uusi 128bit muuttuja, joka sisältää neljä 32bit liukulukua. Jos haluttaisiin luoda vektori, jonka kaikilla komponenteilla on sama arvo, voitaisiin käyttää _mm_set1_ps-käskyä. _mm_dp_ps:n viimeisenä parametrina oleva vakio on maski, joka kuvaa mitkä komponentit laskettavista vektoreista ovat mukana laskussa ja mihin komponentteihin laskun tulos sijoitetaan tulosvektorissa. Maskin bitit 0-3 kuvaavat mihin komponentteihin tulosvektorissa pistetulon arvo laitetaan (sama arvo sijoitetaan kaikkiin valittuihin) Bitit 4-7 kuvaavat mitkä komponentit lähdevektoreista ovat laskussa mukana. 0xE1 = 1110 0001, eli lähdevektoreista valitaan komponentit 2, 3 ja 4 laskettavaksi ja pistetulon tulos sijoitetaan tulosvektorin ensimmäiseen komponenttiin 11
AltiVec on siis PowerPC:n vastaava SIMD-tekniikka. AltiVec tuo 32 128bittistä rekisteriä ja tekniikka tukee kokonaislukujen (8-32bit) sekä 32bit liukulukujen laskemista. AltiVec:n RGB-tietotyyppi on erityinen tietotyyppi pikselien käsittelyyn. Yksi tietotyyppi sisältää 8 16bit pikseliä muodossa 1/5/5/5. Vastaavaa tietotyyppiä ei ole SSE:ssä. AltiVec:ssä ei voida siirtää dataa tavallisten CPU-rekisterien ja vektorirekisterien välillä, ts. kaikki näiden välillä liikuteltava data on kierrätettävä muistin kautta. SSE:ssä tällaista rajoitusta ei ole, mutta asia on myös x86:sta tuttu x87:n (FPU) käsittelyn osalta. Ohjelmoitaessa C/C++:lla AltiVec tarjoaa erityisen vector-avainsanan, jolla voidaan muodostaa helposti uusia vektorimuuttujia. Esim vector int i; luo uuden 128bit muuttujan, joka sisältää 4 32bit kokonaislukua. Vastaavaa mahdollisuutta ei ole SSE:ssä. Toisaalta vector-avainsanan käyttö aiheuttaa ongelmia STL:n vectorin kanssa, vaikka tähän tosin on esim. GCC:ssä olemassa kiertotie. Edelleen vector-avainsana mahdollistaa normaalien aritmeettisten ja binäärioperaatioiden tekemisen C/C++-koodissa, mikä on luonnollisesti mielekkäämpää ohjelmoijan kannalta. SSE ei tällaista toimintaa tue, joten aina on käytettävä kääntäjän intrinsic-funktioita. Lopussa on linkki eräässä yliopistossa tehtyyn tutkimukseen SSE:n ja AltiVec:n välillä lähinnä nopeuden osalta. Yhteenvedossa todetaan, että vaikka AltiVec on huomattavasti kypsempi ja ohjelmoijaystävällisempi, SSE on kuitenkin mennyt nopeudessa selkeästi ohi. 12
Tässä siis joitain huomioonotettavia asioita ja jopa haasteita SSE:n käytössä Luonnollisestikaan tekniikka ei sovellu kaikkeen mahdolliseen käyttöön. Esimerkiksi jonkin järjestelyalgoritmin toteuttaminen voi olla haastavaa, vaikka joitain toteutuksia näiltä osin on tehty. Kääntäjissä on eroja luonnollisesi tuotetun koodin laadun osalta (Intelin kääntäjä on yleensä paras), mutta myös kääntäjän tarjoaman tuen osalta. Esimerkiksi GCC:ssä on tavallisten SSE intrinsic-funktioiden lisäksi omat ja hieman erilaiset toteutukset SSE:n käyttöön, joten tällaisia toteutuksia käytettäessä tehdään helposti kääntäjäriippuvaista koodia. Tuotettu koodi on tietenkin x86/x64 riippuvaista, joten muille arkkitehtuureille joudutaan tekemään omat vastaavat toteutukset tai muut ratkaisut. Lisäksi on huomioitava, että kaikkia SSE-versioita ei ole välttämättä saatavilla kaikissa koneissa, joten tällaiseenkin tilanteeseen on varauduttava. Monet SSE:n käskyt vaativat, että käsiteltävä data on jaksotettu 16 tavun pätkiin. Yhtenä esimerkkinä tästä on tavallisen taulukon käsittely SSE:n avulla. Koska SSE lataa muistista käsiteltäväksi aina 16 tavua kerrallaan, on huolehdittava, että alkuperäisen taulukon koko menee tavumäärällisesti tasan 16:lla jaettuna. Tämä vaatimus voi luonnollisesti aiheuttaa lisätyötä, jos käsiteltävä data ei luonnostaan ole halutunlaisesti jaksotettua. Kaikissa SSE:n käskyissä tätä vaatimusta ei ole, mutta yleensä suoritus on nopeampaa, jos data on 16 tavun jaksoissa. SSE:n tehokas hyödyntäminen vaatii usein manuaalista työtä ja välttämättä koodin muuttaminen SSE-käskykannalle ei ole järin yksinkertaista, joten voi olla syytä miettiä, 13
maksaako optimointi vaivan. Kääntäjien vektorointiominaisuuksia kannattaa tietenkin hyödyntää, mutta tuloksen laadussa on suuria eroja kääntäjien välillä ja usein tulos ei kuitenkaan ole niin tehokas kuin ohjelmoijan kirjoittamana (ainakaan taitavan ohjelmoijan). Viimeisenä seikkana on liukulukulaskujen tarkkuuserot x87:n ja SSE:n välillä. Pointti on siinä, että x87 pitää liukulukulaskujen välitulokset 80 bittisinä, mutta SSE:n tarkin liukulukutarkkuus on 64 bittiä. Tästä voi aiheutua tarkkuuseroja tuloksissa SSEoptimointien jälkeen, millä voi olla merkitystä esimerkiksi jossain tieteellisessä laskennassa. 13
Tässä joitain hyödyllisiä linkkejä, jos aihe alkaa kiinnostamaan. Luonnollisesti Google tarjoaa lisää. 14