Mitäs ihmettä selittelet, toki koodi voidaan optimoida OOO-suoritusta silmälläpitäen. Intelillä on tähän hyvät työkalut joilla voi tutkia koodin todellista suoritusta prosessorissa ja lukea feedbackkinä missä koodin suorituksen osassa tulee pullonkauloja - ja kooderi voi optimoida koodiaan näiden tietojen avulla toimimaan paremmin ko. suorittimen OOO-ikkunassa.
Ei.
Jos nyt aloitetaan pilkun viilaamisella siitä , että kooderilla (
Digitaalitekniikka - luento 6: Dekooderit ) ei ole ohjelmakoodin kirjoittamisen ja optimoinnin kanssa mitään tekemistä.
Ja sen jälkeen jatketaan itse aiheeseen.
Se, että koodia optimoidaan toimimaan jonkun
tietyn prosessorin liukuhihnalla ja välimuisteilla ei ole mitään tekemistä sen kanssa, että koodia optimoidaan toimimaan
yleisesti OoOE-prosessoreilla.
In-order-prosessori on hyvin niuho sen suhteen. millaista koodia sille syöttää, kun se stallaa heti, kun esim. yritetään heti loadin jälkeen käyttää ladattua arvoa. Ja jos esim halutaan saada hyvää suorituskykyä aikaiseksi loopeista, in-order-prossulle loopit pitää joku unrollata tai softa-liukuhihnoittaa, jotta toisen looppi-iteraation koodia voi suoritua kun yksi looppi-iteraatio odottaa lataustaan muistista (ja välimuistillakin on monen kellojakson viive).
Ja kääntäjän tekemä softa-liukuhihnoitus on hyvin monimutkainen ongelma saada toimimaan hyvin muissa kuin hyvin yksinkertaisissa tapauksissa.
Out-of-order-prossulle taas voidaan syöttää koodi, jonka käskyjä ei ole kääntäjän toimesta skeduloitu
yhtään, joka olettaa täysin sekventiaalisen suorituksen ilman liukuhihnaa, ja OoOE-prossu fetchailee itsekseen koodia loopin seuraavia iteraatioita eteenpäin ja uudelleenjärjestelle käskyjä ja suorittaa niitä loopin alkupän käskyjä seuraavista loopin iteraatioista ennen kuin loopin edelliset iteraatiota ovat valmistuneet, eikä sen tarvi stallata.
Ei ole
mitään sellaista erityistä optimointia, minkä OoOE-prossu "tarvisi" koska se tekee käskyjen uudellenjärjestelyä. Rekisteritkin se uudelleennimeää siten että antidependenssitkään ei ole sille ongelma. Optimointi OoOE-prossulle tarkoittaa pitkälti, sitä, että "tee yleisesti ottaen järkevää koodia joka ei tee mitään tyhmää/turhaa" ja "älä tee turhia matalan tason nysväoptimointeja". Ja tietysti, että "pidä huoli että välimuistisi osuu mahdollisimman usein" mutta tämänkin merkitys on OoOE-prossulla siinä mielessä absoluuttisesti pienempi kuin muilla, että se kärsii vähemmän niistä välimuistihuteista. (suhteellisesti sen merkitys sen sijaan on suurempi, kun muut optimoinnit ei ole niin tärkeitä)
OoOE-prossutkin kuitenkin usein hyötyvät HIUKAN esim. looppien unrollaamisesta, koska tällä voidaan vähentää suoritettavien vertailukäskyjen määrää. Mutta jos looppi unrollataan liian monta kertaa, sitten tällä on haitallisia vaikutuksia käskyvälimuistin osumatarkkuuteen. Se, mikä on "liian monta kertaa" on kuitenkin melko prosessorimallikohtainen. Ja
tällaisiin juttuihin niitä intelin suorituskykyanalysaattoreita tarvitaan.
Ja moniin asioihin on monta vaihtoehtoista tapaa tehdä se. Esimerkkinä vaikka kolmella kertominen:
Naiivi tapa on käyttää kertolaskukäskyä. (Yksi käsky, viive kolme kellojaksoa, throughput 1/kellojakso (koska kertolaskuyksiköitä on vain 1)).
Toinen tapa on käyttää kahta peräkkäistä yhteenlaskua. Paitsi että koska x86lla ei ole ei-destruktiivista tapaa laskea sitä yhteenlaskua, tämä tarkoittaakin ensin siirtokäskyä, ja sitten kahta peräkkäistä yhteenlaskua. Kolme käskyä, viive kaksi kellojaksoa (siirtokäskyllä ei ole viivettä, koska se tehdään rekistereitä uudelleennimeämällä, siirron kohde uudelleenimetään samaksi rekisteriksi kuin sen lähde jo prosessorin frontendissä), throughput n. 1.33/kellojakso.
Kolmas tapa on käyttää shiftausta ja yhteenlaskua. Ja jälleen tarvii siirtokäskyn eteen. Kolme käskyä, kahden kellojakson viive, throughput n .1.33/kellojakso.
Käytännössä shift+add ja add+add antaa moderneilla prossuilla kaikissa tilanteissa saman suorituskyvyn, mutta entäs nämä vs kertolasku?
Riippuu täysin siitä, onko pullonkaula sillä hetkellä prossun etupäässä vai takapäässä. Mikäli pullonkaula on etupäässä (käskyvälimuisti, käskynhaku, dekoodaus, rekisterien uudelleennimeäminen), kertolaskukäsky on nopeampi.
Mikäli pullonkaula on takapäässä (yleensä käskyjen viive, joskus harvoin vapaiden laskentayksiköiden määrä), shift+add tai add+add on nopeampi.
Ja siihen, kumpi on milläkin kohtaa koodia enemmän pullonkaula tarvitaan sitä intelin suorituskykyanalysaattoria. Mutta tämä on jälleen hyvin riippuvainen siitä prosessorimallista.
Tosin, tämä kolmella kertominen on nyt siinä mielessä kaukaa haettu esimerkki, että tämän kolmella kertomisen optimointi menee todlela lillukanvarsiksi. Käytännössä melkein kaikki normaalit tilanteet joisa sitä intelin suorituskykyanalysaattoria käytetään on nykyään softan välimuistikäyttäytymisen tutkimista.