Useampien ytimien hyödyntäminen softatasolla

Liittynyt
18.05.2017
Viestejä
21 331
Tällainen perustietotason kyssäri kun aloin pohtimaan lueskeltuani kerta toisen jälkeen miten "XYZ on hyvin suoritinintensiivinen mutta vaihtaminen parempaan ei välttämättä auta suhteessa niin paljoa koska käyttää vain yhtä ydintä laskentaan".

Onko monen ytimen hyödyntämisessä joku erityinen ohjelmointipuolen haaste, että sitä ei vakiona tungeta kaikkeen peleistä alkaen jo niiltä ajoilta kun moniytimiä alkoi esiintymään? Eikö tällaista voi mitenkään käyttistasolla tai erikseen hommaan tehdyllä "välimiessoftalla" hoitaa jotenkin "käänteisvirtualisoimalla" useammat ytimet yhdeksi sen ohjelmiston silmissä silloin kun ko. softa alkaa kuormittamaan sitä yhtä ydintä lähes tappiin saakka? Ymmärtääkseni etenkin monet fysiikkaa paljon mallintavat pelitkin hyötyisivät siitä ja prosessori voi olla vajaakäytöllä pullonkaula.
 
Monesti suoritettava tehtävä riippuu jonkun toisen tehtävän lopputuloksesta. Tällöin niitä ei pystytä suorittamaan rinnakkain ja siten ollen niiden jakaminen useammalle ytimelle ei välttämättä nopeuta laskentaa, vaan se riippuu siitä kuinka nopeasti se yksittäinen ydin saa tuloksensa ulos. Suurin haaste on siis käsittääkseni se, että tehtäviä on hankala jakaa järkevällä tavalla ydinten välillä.
 
Viimeksi muokattu:
Käytännössä kaikki normaalisti CPUlla yleisesti käytetyt ohjelmointikielet nyt sattuu olemaan toimintaperiaatteeltaan sarjallisia. Ohjelma kirjoitetaan sarjaksi PERÄKKÄISIÄ asioita joiden luonnollinen suoritustapa tarkoittaa niidein suoritusta samassa säikeessä.

Ja jotta kukin laskutoimitus saa oikean arvon, sen käskyn tai rutiinin joka sen tuotti pitää olla valmistunut ennen kuin sen laskennan joka sitä käyttää voi aloittaa.

Teoriassa kääntäjä voi yrittää analysoida sitä, mikä data menee mistä minnekin, ja rinnakkaistaa asioita, joiden välillä ei ole datariippuvuuksia, mutta esim. "vapaasti" käytettävien osoittimien käyttäminen pilaa tätä analyysiä hyvin tehokkaasti.

(Mikäli siellä ei ole hankalia "villejä osoittimia" joista ei tiedetä tarpeeksi), käytännössä tämä analyysi toimii kohtalaisen hyvin usein pienessä mittakaavassa, kun puhutaan maksimissaan kymmenistä tai sadoista käskyistä. Kääntäjät osaavat usein rinnakkaistaa esim. koodin

r = r * scale;
g = g * scale;
b = b * scale;

käyttämään 4-leveää SIMD-käskykantaa (SSE tai Neon) (neljäs linja laskee tyhjää)

Säikeiden käytön overhead on kuitenkin tuhansia tai kymmenäituhansia käskyjä, joten käytännössä kääntäjä ei kykene löytämään ohjelmasta rinnakkaisuutta sillä mittakaavalla, mitä automaattinen monisäikeistys vaatisi.

Ohjelmointikielellä on toki huomattava vaikutus siihen, kuinka helppoa sitä on rinnakkaistaa - "vappaat osoittimet" on lähnnä C- ja C++-kielien ominaisuus, esim. Rust on kieli joka on suunniteltu siten että siinä on (melkein) yhtä vähän overheadeja kuin C/C++ssa yksinkertaisessa sarjallisessa suorituksessa, mutta kääntäjällä on paremmin tietoa siitä, mitä ohjelma oikeasti teke ja mikä data menee mistä minnekin, mikä mahdollistaa kääntäjälle sekä 1) monien virhetilanteiden havaitsemisen jo käännösaika 2) aggressiivisemmat rinnakkaistusoptimoinnit.

Käytännössä, jos ohjelma kirjoitetaan C-kielellä tai vanhalla versiolla C++-kielestä, ohjelmoijan pitää AINA erikseen joko kertoa kääntäjälle, että "nämä saa rinnakkaistaa" TAI luoda säikeet "käsin" ja hallita niitä "käsin". C++-kielen uusissa versiossa on joitain uusia ominaisuuksia joilla voi "luonnollisesti" kirjoittaa rinnakkaisia lausekkeille tietyille asioille tietyissä tapauksissa, mutta yleensä näilläkin usein saa rinnakaistettua vain pieniä paloja koodista; Esim pelien kaltaisilla softilla voisi mennä usein että 80% koodista ajautuu edelleen yhdessä säikeessä mutta 20% voidaan monisäikeistää.
 
Semmoista olen itse miettinyt että kun peleissä on lukuisia NPC:itä ja niitä ohjaa joku AI, niin eikö ne olisi periaatteessa mahdollista rinnakkaistaa ns. "loputtomasti". Eli jokaista NPC:tä ohjaisi toisistaan riippumaton threadi, välillä vaan tehtäisiin jotain "törmäystarkistuksia" sen suhteen missä ne liikkuvat ja mitä tekevät ja mitkä niiden tavoitteet ovat. Jokaisella AI:lla on joku oma rutiini mitä se toistaa (herää aamulla, laittaa ruokaa, käy torilla ostamassa ruokaa tai lähtee metsästämään tms.) ja jos pelaaja sattuu hahmoa vastaan niin sitten alkaisi keskustelurutiini tai taistelu.
 
Semmoista olen itse miettinyt että kun peleissä on lukuisia NPC:itä ja niitä ohjaa joku AI, niin eikö ne olisi periaatteessa mahdollista rinnakkaistaa ns. "loputtomasti". Eli jokaista NPC:tä ohjaisi toisistaan riippumaton threadi, välillä vaan tehtäisiin jotain "törmäystarkistuksia" sen suhteen missä ne liikkuvat ja mitä tekevät ja mitkä niiden tavoitteet ovat. Jokaisella AI:lla on joku oma rutiini mitä se toistaa (herää aamulla, laittaa ruokaa, käy torilla ostamassa ruokaa tai lähtee metsästämään tms.) ja jos pelaaja sattuu hahmoa vastaan niin sitten alkaisi keskustelurutiini tai taistelu.

Teoriassa jokaisen NPCn tekoälyn voisi joo laittaa omaksi säikeekseen.

Toimii aika hyvin silloin kun ne NPCt on isoja ja monimutkaisia ja niitä on melko pieni määrä (eli kun ne on "pelaajiin verrattavissa olevia botteja")

Mutta jos niitä NPCitä on paljon ja sen yksittäisen NPCn koodi on lyhyt, silloin suoraan omalle säikeelle rinnakkaistaminen tarkoittaisi liian suuria overheadeja siitä säikeistyksestä.

Silloin näitä pitäisi niputtaa jonkinlainen määrä samaan säikeeseen, joko staattisesti (etukäteen yhdistetään tietyt N NPCtä samaan säikeeseen) tai dynaamisesti (thread pooling/task queuing). Näistä tämä dynaaminen optio tarkoittaisi kuitenkin vähintään yhtä synkronointia/NPC.


Tuo kommunikaatio toimii käytännössä luonnollisesti siten että joka framen (tai engine-tickin, jota voidaan ajaa eri nopeudella kuin graffaengineä) alussa jokainen NPC saa sisäänsä inputit (mitä näkee jne) ja sen koko framen tai game engine tick:n aikana se laskee mitä se tekee, ja tuottaa lopussa hahmon tekemät komennot. Ja sama koodi ajataan kokonaan uusiksi seuraavalla framella/game engine tick:llä.

Jos homma liukuhihnoitetaan kunnolla, seuravalla framella/game engine tick:llä sitten fysiikkaengine lukee NPCiden (ja pelaajien) edellisellä tick:llä antamat komentot ja laskee niiden perusteella, mitä maailmassa tapahtuu, ja AI-koodi kaikille NPCille pyörii täysin rinnakkain sen fyssaenginen kanssa.

Jos taas hommaa ei liukuhihnoiteta, fysiikkakoodi odottelee että kaikkien NPCiden antamat komennot on valmiina ja alkaa ajautumaan vasta sen jälkeen. TÄllöin tarvitaan enemmän synkronointia.
 
Joo, grafiikat ovat yleensä sellainen asia, joka voidaan "helposti" laskea erikseen lähes jokaisen pikselin sisältö kullakin hetkellä. Tämän suorittaminen meneekin GPU:lle jossa on satoja ytimiä rinnaksaisesti ko. laskentaan. Lisäksi esim Excelissä, jokin vlookuppi voi toimia siten, että se laskee jokaista lookuppia erikseen niin kauan, kuin soluissa ei viitata toisiinsa ja tämänkin voi rinnakkaistaa. Mutta toisella puolla on sitten laskennat, jotka menevät automaattisesti sarjassa, eli toista ei voida aloittaa ennen kuin edellisen tulos on saatu selville. Kun palataan pelipuoleen niin sielläkin on osa asioista sellaisia, että ne ovat helpommin rinnakkaistettavia (esim. erilliset toisistaan tietämättömät AI:t silloin kuin ne eivät vaikuta toisiinsa), mutta paljon on sellaista, että asiaa ei voida laskea ennen kuin tiedetään edellisen tulos: mitä pelattavalle hahmolle tapahtuu riippuu siitä mitä kaikki muut pelissä olevat "npc hahmot" ensin tekevät. Yksittäisen ohjelmoijan näkökulmasta tämä on varmasti valtava soppa ja pysyvästi ainoastaan ratkaistavilla hyvillä työkaluilla, jotka analysoivat koodia ja hakevat sieltä riippuvuuksia ja niitä, jotka voidaan laskea rinnakkain asyncroonisesti. Webbidevauksessahan käytetään samaa, mutta siellä devaajat erikseen määrittävät mitkä kaikki elementit saa toteuttaa toisistaan riippumattomina.

Lisäksi noissa on osittaista riippuvuutta: jokin saa tulla valmiiksi hieman epäsynkassa, mutta ei vaikkapa 5 sekuntia myöhässä. Sama jos AI:t ovat kaukana toisistaan, niin voidaan hyväksyä rinnakkaislaskenta, mutta kun ne ovat lähellä toisiaan voidaan ehkä vaatia single threadia. Löytyyköhän tähän lopulta ratkaisu jostain AI ohjelmasta, joka analysoi koko koodin ja rakentelee siihen erilaisia skenaarioita jonka pohjalta sitten luokittelee mikä kaikki kelpaa rinnakkaisajoon. Muuttujana tulee varmasti sellaiset asiat, että miten kriittiset asiat ovat toistensa tuloksista. Joku peli on ok, jos asiat tapahtuvat hieman epäsynkassa, mutta lääkeannostelu tai ydinvoimalan ohjaustietokone haluaa, että antureilta tulevat tieto on varmasti käsitelty ennen, kuin päätetään mitä seuraavaksi tapahtuu. Sekin voi olla rinnakkaisajoa, mutta jossain pisteessä tulee "wait for readiness before proceeding" -tarkastus.
 
Muuttujana tulee varmasti sellaiset asiat, että miten kriittiset asiat ovat toistensa tuloksista. Joku peli on ok, jos asiat tapahtuvat hieman epäsynkassa, mutta lääkeannostelu tai ydinvoimalan ohjaustietokone haluaa, että antureilta tulevat tieto on varmasti käsitelty ennen, kuin päätetään mitä seuraavaksi tapahtuu. Sekin voi olla rinnakkaisajoa, mutta jossain pisteessä tulee "wait for readiness before proceeding" -tarkastus.

Yleisimmät prosessorit ovat cache-coherensseja, eli cachesta luettava data on synkassa. Kriittisiin kohtiin tarvitaan tarkistukset, softalla flushataan puskurit nopeutta vaativissa toteutuksissa mutta se on aina epävarmaa, jos täytyy olla varma niin threadien synkkaukset täytyy tehdä atomisina, eli datan luvut ja kirjoitukset täytyy peräkkäistää ilman vaaraa että joku muu threadi muuttaa ko. arvoa välissä. Pelkän cache-coherencyn omaavissa laitteistoissahan tuo atominen operaatio on raskas, jos muistilukuja ei jäljitetä ainoa varma ratkaisu on tyhjentää kaikkien ytimien puskurit ja aloittaa luennat uudestaan cachesta.

Kriittisiin tehtäviin kannattaa sitten suunnitella prosessori jossa taataan että luettu data on aina viimeisin eikä jostain puskurista löydetty vanha versio, esimerkiksi nVidialla on näitä prosessoreita, suunniteltu varmaan just autokäytttöön tms. jossa reaaliaikainen datan saaminen on tärkeää, näissäkin data on varmasti ajantasalla vain memory-barrier käskyjen jälkeen mutta koska ARM mahdollistaa muuten vapaan muistinkäsittelyn memory barrier tarvitaan synkkaan jokatapauksessa ja overheadi tuosta ei ole aivan hirveä.

Jännä nähdä alkaako muutkin ARM-valmistajat tehdä prossunsa samalla tyylillä, suhteellisen pienellä perf-hitillä olisi saavutettavissa suuria etuja rinnakkaisohjelmoinnin toimivuuteen, helpottaisi ainakin lukituksen tekoa todella paljon.
 
Hienoa saada tekevien tahojen näkemyksiä tähän. Itse joutuu lähinnä spekuloimaan noita asioita.
Yleisimmät prosessorit ovat cache-coherensseja, eli cachesta luettava data on synkassa. Kriittisiin kohtiin tarvitaan tarkistukset, softalla flushataan puskurit nopeutta vaativissa toteutuksissa mutta se on aina epävarmaa, jos täytyy olla varma niin threadien synkkaukset täytyy tehdä atomisina, eli datan luvut ja kirjoitukset täytyy peräkkäistää ilman vaaraa että joku muu threadi muuttaa ko. arvoa välissä. Pelkän cache-coherencyn omaavissa laitteistoissahan tuo atominen operaatio on raskas, jos muistilukuja ei jäljitetä ainoa varma ratkaisu on tyhjentää kaikkien ytimien puskurit ja aloittaa luennat uudestaan cachesta.

Kriittisiin tehtäviin kannattaa sitten suunnitella prosessori jossa taataan että luettu data on aina viimeisin eikä jostain puskurista löydetty vanha versio, esimerkiksi nVidialla on näitä prosessoreita, suunniteltu varmaan just autokäytttöön tms. jossa reaaliaikainen datan saaminen on tärkeää, näissäkin data on varmasti ajantasalla vain memory-barrier käskyjen jälkeen mutta koska ARM mahdollistaa muuten vapaan muistinkäsittelyn memory barrier tarvitaan synkkaan jokatapauksessa ja overheadi tuosta ei ole aivan hirveä.

Jännä nähdä alkaako muutkin ARM-valmistajat tehdä prossunsa samalla tyylillä, suhteellisen pienellä perf-hitillä olisi saavutettavissa suuria etuja rinnakkaisohjelmoinnin toimivuuteen, helpottaisi ainakin lukituksen tekoa todella paljon.

Hienoa saada tekevien tahojen näkemyksiä asiaan. Itse joutuu lähinnä spekuloimaan noita asioita sen pohjalta, mitä on eri tiimeissä aikanaan nähnyt varsinaisten kehittäjien tekevän ja mitä asioita on yhdessä palloteltu.
 
Yleisimmät prosessorit ovat cache-coherensseja, eli cachesta luettava data on synkassa. Kriittisiin kohtiin tarvitaan tarkistukset, softalla flushataan puskurit nopeutta vaativissa toteutuksissa mutta se on aina epävarmaa, jos täytyy olla varma niin threadien synkkaukset täytyy tehdä atomisina, eli datan luvut ja kirjoitukset täytyy peräkkäistää ilman vaaraa että joku muu threadi muuttaa ko. arvoa välissä. Pelkän cache-coherencyn omaavissa laitteistoissahan tuo atominen operaatio on raskas, jos muistilukuja ei jäljitetä ainoa varma ratkaisu on tyhjentää kaikkien ytimien puskurit ja aloittaa luennat uudestaan cachesta.

Kriittisiin tehtäviin kannattaa sitten suunnitella prosessori jossa taataan että luettu data on aina viimeisin eikä jostain puskurista löydetty vanha versio, esimerkiksi nVidialla on näitä prosessoreita, suunniteltu varmaan just autokäytttöön tms. jossa reaaliaikainen datan saaminen on tärkeää, näissäkin data on varmasti ajantasalla vain memory-barrier käskyjen jälkeen mutta koska ARM mahdollistaa muuten vapaan muistinkäsittelyn memory barrier tarvitaan synkkaan jokatapauksessa ja overheadi tuosta ei ole aivan hirveä.

Mitä tarkoitat ytimen "jollain puskurilla", jos se ei ole cache? Rekistereitä? Ja mitä konkreettisesti tarkoitat sillä, että tyhjennetään kaikkien ytimien puskurit ja aloitetaan luennat uudestaan cachesta?

Ja vielä; todellako tarvitaan erikseen tarkoitusta varten suunniteltu prosessori, jotta moniydinprosessorissa voidaan varmistaa, että cachesta löytyvä data on viimeisin, eikä jotain mitä ollaan ehkä parhaillaan muuttamassa tai muutettu? Että yleiskäyttöiset moniydinprosessorit eivät osaa merkata cache-dataa dirtyksi, jos sitä on muutettu tai se on juuri käsittelyssä? Sitäkö tarkoitit?
 
Viimeksi muokattu:
Hienoa saada tekevien tahojen näkemyksiä asiaan. Itse joutuu lähinnä spekuloimaan noita asioita sen pohjalta, mitä on eri tiimeissä aikanaan nähnyt varsinaisten kehittäjien tekevän ja mitä asioita on yhdessä palloteltu.

Juu ite spekuloin ihan vaan huvin vuoksi, en todellakaan ole mitään tälläistä kehittämässä. Aikanaan opiskelut ihan vähän hipaisi noita moniprosessorin muistinkäsittelyongelmia mutta ei ne ongelmat ole siitä juuri muuttuneet.

Mitä sitä itse äkkiseltää tulis mieleen niin tuo sequential consistency, eli prosessorin käsittelemä data on ajantasalla vaatisi lähinnä koherenssiprotokollaan käskyn tyhjennellä jaetun datan käyttämien prossujen puskurit synkkakäskyissä plus systeemi sen varalle että itse cache-linja on jo poistunut mutta data saattaa vielä cpu:n puskureissa. TSO:n kanssahan sitä ei voisi ajatellakaan liian overheadin takia mutta järkevien synkronointikäskyjen kanssa varmaankin suorituskykyvaikutus ei olisi älytön, varsinkin kun ottaa huomioon että ilman jäljittävää rautaa pitää viljellä kaikkia kikkakolmosia synkronoinneissa.
 
Mitä tarkoitat ytimen "jollain puskurilla", jos se ei ole cache? Rekistereitä? Ja mitä konkreettisesti tarkoitat sillä, että tyhjennetään kaikkien ytimien puskurit ja aloitetaan luennat uudestaan cachesta?

Nykyprossussa on jotain 1000 käskyä tai käskyyn liittyvää dataa ajossa yhtäaikaa, vaikka cache on mesi-protokollalla synkroonissa itse cpu ytimet eivät ole. Eli jos (yksinkertaisin mahdollinen) lukitus menee näin: Luetaan lukko vapaaksi, kirjoitetaan oma threadikoodi lukkoon - mikään ei takaa että tuossa välissä ei joku toinen threadi voisi kirjoittaa omaa lukituskoodiaan väliin ja lukitus kusee. Eli lukitus pitää tehdä varmistaen prossun puskurien plus mahdollisten keskeytysten viive - odotetaan x määrä aikaa ja luetaan lukko uusiksi ja jos sielä sen jälkeen löytyy oman threadin lukituskoodi voi olla jo suht varma että lukitus onnistui. Maksaa aikaa(voidaan toki optimoida muun koodinsuorituksen väliin) ja jos rauta tekisi sen niin suorituskykykin paranisi.

Ja vielä; todellako tarvitaan erikseen tarkoitusta suunniteltu prosessori, jotta moniydinprosessorissa voidaan varmistaa, että cachesta löytyvä data on viimeisin, eikä jotain mitä ollaan ehkä parhaillaan muuttamassa tai muutettu? Että yleiskäyttöiset moniydinprosessorit eivät osaa merkata cache-dataa dirtyksi, jos sitä on muutettu tai se on juuri käsittelyssä? Sitäkö tarkoitit?

Tarvitaan toki erikseen suunniteltu prosessori, jos prosessori on cache-coherent niin cachesta luettu data on aina viimeisin. Mutta prosessori voi saada datansa sisäsisistä puskureistaan joten koodarin on varmistettava että esim. lukitusdata tulee cachesta eikä prosessorin puskureista ja se on yllättävän hankalaa.
 
Yleisimmät prosessorit ovat cache-coherensseja, eli cachesta luettava data on synkassa. Kriittisiin kohtiin tarvitaan tarkistukset, softalla flushataan puskurit nopeutta vaativissa toteutuksissa

Softalla ei nimenomaan tarvitse flushata puskureita, kun ollaan välimuistikoherentteja. Softalla pitää ainoastaan kutsua jotain synkroinintiprimitiiviä, joka varmistaa että 1) luku tehdään vasta kirjoituksen jälkeen 2) synkroinnin tekemät muistiaccessit ovat pakottaneet ytimien/rautasäikeiden välille sellaisen muistioperaation, joka on myös pakottanut sen että siinä vaiheessa kun lukija yrittää lukea dataa, muistin konsistenttiussääntöjen säilyttämiseksi välimuistin koherenttiusprotokolla on jo hoitanut tehtävänsä myös alkuperäisen kirjoituksen osalta siten että lukija varmasti lukee päivitetyn datan (eikä siten että se koherenttiusdata tämän datan osalta tulee vasta muutaman kellojakson päästä, jolloin se voisi muuten tulla).

Oikea ongelma on se, että ilman synkronointia säikeet eivät tiedä koska toiset säikeet ajautuvat , ilman synkronointia lukija ei tiedä onko data jo kirjoitettu eikä kirjoittaja tiedä koska data yritetään lukea, eikä välimuistin koherenttiudella taas ole tämän kanssa juurikaan tekemistä.

Jotain tarvii softasta flushata silloin kun joku osa systeemistä ei ole välimuistikoherentti, esim. kun lähetetään dataa erillisnäyttikselle. (nykyiset erillisnäyttikset eivät ole välimuistikoherentteja).

Mutta tämäkään ei poista tarvetta synkronoinnille, vaan tämä pitää silloin tehdä sen synkronoinnin lisäksi.

Kriittisiin tehtäviin kannattaa sitten suunnitella prosessori jossa taataan että luettu data on aina viimeisin eikä jostain puskurista löydetty vanha versio, esimerkiksi nVidialla on näitä prosessoreita, suunniteltu varmaan just autokäytttöön tms. jossa reaaliaikainen datan saaminen on tärkeää, näissäkin data on varmasti ajantasalla vain memory-barrier käskyjen jälkeen mutta koska ARM mahdollistaa muuten vapaan muistinkäsittelyn memory barrier tarvitaan synkkaan jokatapauksessa ja overheadi tuosta ei ole aivan hirveä.
Jännä nähdä alkaako muutkin ARM-valmistajat tehdä prossunsa samalla tyylillä, suhteellisen pienellä perf-hitillä olisi saavutettavissa suuria etuja rinnakkaisohjelmoinnin toimivuuteen, helpottaisi ainakin lukituksen tekoa todella paljon.

Nyt menee kyllä jälleen tosi ja tarina sekä softa ja rauta ihan sekaisin.

Nykyprossussa on jotain 1000 käskyä tai käskyyn liittyvää dataa ajossa yhtäaikaa, vaikka cache on mesi-protokollalla synkroonissa itse cpu ytimet eivät ole. Eli jos (yksinkertaisin mahdollinen) lukitus menee näin: Luetaan lukko vapaaksi, kirjoitetaan oma threadikoodi lukkoon - mikään ei takaa että tuossa välissä ei joku toinen threadi voisi kirjoittaa omaa lukituskoodiaan väliin ja lukitus kusee. Eli lukitus pitää tehdä varmistaen prossun puskurien plus mahdollisten keskeytysten viive - odotetaan x määrä aikaa ja luetaan lukko uusiksi ja jos sielä sen jälkeen löytyy oman threadin lukituskoodi voi olla jo suht varma että lukitus onnistui. Maksaa aikaa ja jos rauta tekisi sen niin suorituskykykin paranisi.

Ei todellakaan toimi tuollainen lukitus...

Softa ei voi koskaan luottaa siihen että jonkun saa tehdä "jonkun ajan jälkeen". Softa ei voi tietää, kuinka nopealla raudalla sitä, ajetaan, ja CPUlla siellä voi olla vaikka mitä viiveitä sotkemassa niitä ajoituksia.

Tosiasiassa homma toimiii käytännössä siten, että kaikilla yleisillä käskykanta-arkkitehtuureilla löytyy sopivia atomisia käskyjä, jotka eivät valmistu, ennenkuin on varmistettu että muut eivät pääse sotkemaan tilannetta.

Ja JOS meillä ei olisi/arkkitehtuureilla joilla ei ole niitä atomisia käskyjä, sitten käytetään esim Petersenin algoritmia:

 
Viimeksi muokattu:
Softalla ei nimenomaan tarvitse flushata puskureita, kun ollaan välimuistikoherentteja. Softalla pitää ainoastaan kutsua jotain synkroinintiprimitiiviä, joka varmistaa että 1) luku tehdään vasta kirjoituksen jälkeen 2) synkroinnin tekemät muistiaccessit ovat pakottaneet ytimien/rautasäikeiden välille sellaisen muistioperaation, joka on myös pakottanut sen että muistin konsistenttiussääntöjen säilyttämiseksi välimuistin koherenttiusprotokollan on jo hoitanut tehtävänsä myös alkuperäisen kirjoituksen osalta siten että lukija varmasti lukee päivitetyn datan.

Välimuistikoherenssi on vain välimuistikoherenssi, eli välimuisti on aina ajantasalla alusta loppuun koska kaikki muut välimuistikopiot on invalidoitu ennenkuin välimuistiprotokolla antaa luvan kirjoittaa jaettuun dataan.

Oikea ongelma on se, että ilman synkronointia säikeet eivät tiedä koska toiset säikeet ajautuvat , ilman synkronointia lukija ei tiedä onko data jo kirjoitettu eikä kirjoittaja tiedä koska data yritetään lukea, eikä välimuistin koherenttiudella taas ole tämän kanssa mitään tekemistä.

Jos meillä on välimuistikoherenssi niin välimuistista luettu data on aina ajantasalla.

Jotain tarvii softasta flushata silloin kun joku osa systeemistä ei ole välimuistikoherentti, esim. kun kirjoitetaan näyttikselle. (nykyiset erillisnäyttikset eivät ole välimuistikoherentteja).

Mikään ei välimuistikoherentissa systeemissä estä datan muutosta luvun ja kirjoituksen välillä.


Ei todellakaan mene näin.

Softa ei voi koskaan luottaa siihen että jonkun saa tehdä "jonkun ajan jälkeen". Softa ei voi tietää, kuinka nopealla raudalla sitä, ajetaan, ja CPUlla siellä voi olla vaikka mitä viiveitä sotkemassa niitä ajoituksia.

Tosiasiassa homma toimiii käytännössä siten, että kaikilla yleisillä käskykanta-arkkitehtuureilla löytyy sopivia atomisia käskyjä, jotka eivät valmistu, ennenkuin on varmistettu että muut eivät pääse sotkemaan tilannetta.

Ja JOS meillä ei olisi niitä atomisia käskyjä, sitten käytetään esim Petersenin algoritmia:


Atomiset operaatiot on hitaita, sen takia niitä vähemmän elämälle kriittisiä lukituksia voidaan tehdä muutenkin. Lukitukset olisi hyvä jättää käyttöjärjestelmän huolehdittavaksi niin siinä ne päivittyvät raudan mukana yleensä ongelmitta.
 
Välimuistikoherenssi on vain välimuistikoherenssi, eli välimuisti on aina ajantasalla alusta loppuun koska kaikki muut välimuistikopiot on invalidoitu ennenkuin välimuistiprotokolla antaa luvan kirjoittaa jaettuun dataan.

Juu, muut välimuistit on invalidoitu ennen kuin ne voivat kirjoittaa.

Mutta muistia ei vain kirjoiteta, vaan sitä myös luetaan.

Osoitetta, jonne joku ydin on juuri kirjoittanut, saa aivan hyvin toinen säie LUKEA seuraavalla kellojaksolla, ja saada sieltä vielä vanhan arvon.

Välimuisti on ajan tasalla tavalla, joka toteuttaa muistin konsistenttiussäännöt, mutta tämä ei tarkoita sitä, että kaikki välimuistit invalidoidaan sillä samalla kellojaksolla kun kirjoitus tapahtaa.

Jos meillä on välimuistikoherenssi niin välimuistista luettu data on aina ajantasalla.

Ajan tasalla oleminen ei lohduta jos se aika on väärä.

Esimerkki 1)
Säie B tietää ainoastaan, että se tarvii dataa jonka säie A tulee joskus kirjoittamaan osoitteeseen X.

Että se tietää, koska tämä "joskus" on, säikeiden A ja B pitää tehdä synkronointia keskenään.

Tällaisessa tilanteessa toki synkronoinniksi riittää joku hyvin yksinkertainen tai timestamp/laskuri, ei tarvita varsinaista lukkorakennetta.


Esimerkki 2)
Säie A ja säie B haluavat molemmat kirjoittaa 128 tavun kokoisen tietorakenteen (2 välimuistilinjaa).

Jos meillä ei ole synkronointia:

Vaikka säie A onnistuisi omimaan haltuunsa sen välimuistilinjan koko 64 tavun kirjoituksen ajaksi ja kirjoittamaan kaiken datansa siihen peräkkäin,
voi aivan hyvin käydä niin, että ensimmäinen säie tämän jälkeen stallaa/pysähtyy jostain syystä, esim. TLB-hudin, palveltavan keskeyksen tms takia.

Ja tässä välissä säie B käy sekä ylikirjoittamassa datan niihin 64 ekaan tavuun ETTÄ kirjoittaa ne 64 viimeisät tavua.

Tämän jälkeen säie A herää ja käy kirjoittamassa datansa 64 viimeiseen tavuun, toiseen välimuistilinjaan.

Nyt meillä on 128 tavun tietorakenne josta ensimmäiset 64 tavua on säikeeltä B ja viimeiset 64 tavua on säikeeltä A.

Tietorakenne on siis epäkonsistentissa tilassa. Tätä ei todellakaan yleensä haluta, että softa toimisi oikein.

Eikä tähän oikeasti tarvita edes kahta eri välimuistilinjaa, se keskeytys vaikka kahden sanan kirjoituksen välissä, yhdellä välimusitlinjalla johtaa samaan efektiin, tosin siten että sama välimusitilinja välissä siirtyy toiselle välimuistille.

Esimerkki 3:
Meillä on laskuri, sitä päivitetään monesta säikeestä. Aussa arvo on 0.

Ilman synkroinointia:

Ensin säie A lukee sen (saa arvon 0)
Sitten säie B lukee sen (saa arvon 0)
Sitten säie A laskee 0+1 = 1 ja kirjoittaa arvon 1
Siten säie B laskee 0+1 =1 ja kirjoittaa arvon 1.

Laskuria lisättiin 2 kertaa, mutta sen arvo lisääntyi vain yhdellä.


(oikeasta) säikeistä ei koskaan tiedetä, koska ne tarkkaanottaen ajautuvat, minkä takia ne tarvii synkronointia, ja jos vähintään toinen kirjoittaa dataa, jota toinenkin joko lukee tai kirjoittaa.

Ainostaan, jos molemmat vain lukee dataa, ei tarvita synkronointia.

Atomiset operaatiot on hitaita, sen takia niitä vähemmän elämälle kriittisiä lukituksia voidaan tehdä muutenkin. Lukitukset olisi hyvä jättää käyttöjärjestelmän huolehdittavaksi niin siinä ne päivittyvät raudan mukana yleensä ongelmitta.

Kaikki vaihtoehtoiset tavat tehdä oikeasti toimiva lukitus on hitaampia.

"tehdä muutenkin" toimii vain tilanteissa, joissa ei tarvita lukitusta, vaan joku muu, kevyempi synkronoinnin muoto.
 
Viimeksi muokattu:
Juu, muut välimuistit on invalidoitu ennen kuin ne voivat kirjoittaa.

Mutta muistia ei vain kirjoiteta, vaan sitä myös luetaan.

Osoitetta, jonne joku ydin on juuri kirjoittanut, saa aivan hyvin toinen säie LUKEA seuraavalla kellojaksolla, ja saada sieltä vielä vanhan arvon.

Välimuisti on ajan tasalla tavalla, joka toteuttaa muistin konsistenttiussäännöt, mutta tämä ei tarkoita sitä, että kaikki välimuistit invalidoidaan sillä samalla kellojaksolla kun kirjoitus tapahtaa.

Se MESI tuottaa edelleenkin ongelmia sisäistää. Se on hyvin yksinkertainen protokolla ja se siinä siis määritetään että kirjoittaa voi vain eksklusiiviseen tilaan - eli kirjoitushetkellä datasta ei ole kopioita muualla. Ja sääntöhän on nimenomaan pitämään muisti ehjänä, jos sääntö olisi joku muu kaksi kirjoitusta voisi osua samaan välimuistilinjaan yhtäaikaa ja raudalla pitäisi olla joku muu keino selvittää mikä data on jäävä ja mikä poistettava. MESI siis hoitaa vain muistin ja välimuistien yhtenäisyyden, muut monisäikeistyvän ohjelmoinnin ongelmat on vielä jäljellä.
 
Ja kun meillä on koherentti muisti niin synkronointia ei tarvita, tarvitaan vain se lukitus käsiteltäessä muiden threadien kanssa jaettua dataa, eli meillä on tieto siitä että ko. data on käsittelyssä toisessa threadissa eikä sitä voi ko. hetkellä edes lukea. Ja tämähän ei vaadi edes moniprosessorisysteemiä, ihan sama tilanne on jo aikajaetussa yhden prosessorin ajossakin, jaettua dataa ei vain voi käsitellä useammasta threadista yhtäaikaa jos siihen kirjoitetaan yhdenkin toimesta.

Jos käytetään synkronointia koko koherentti muisti on aivan turha ja tuottaa vain ylimääräistä overheadia.
 
Se MESI tuottaa edelleenkin ongelmia sisäistää.
Se on hyvin yksinkertainen protokolla ja se siinä siis määritetään että kirjoittaa voi vain eksklusiiviseen tilaan - eli kirjoitushetkellä datasta ei ole kopioita muualla.

MESI ei tuota ongelmia sisäistää, vaan sinulle tuottaa ongelmia sisäistää se, että MESI on esihistorialliselta ajalta, kun monta prosessoriydintä tarkoitti erillisiä prosessoripiirejä joita yhdisti yksi jaettu väylä, eikä sitä enää käytetä juuri missään enää. (Ehkä joku raspberry pi tms. todella low-end-rauta saattaa käyttää, mutta mikään missä suorituskyvyllä oikeasti on väliä, ei todellakaan käytä)

Se on nykyään korvattu esim. MOESI:lla tai MESIF:llä, tai jollain hakemistopohjaisella protokollalla.

AMD ei ole koskaan käyttänyt MESIä. Heti ensimmäisessä montaa prosessoria tukevassa prossumallissaan (Athlon MP) AMD käytti MOESIa.

Intel taas taisi vaihtaa MESIF:iin Nehalemissa, n. 9 vuotta sitten.

MOESIssa voi aivan hyvin olla yhdellä välimuistilla linja Owned-tilassa ja toisella välimusitilla sama välimuisti Shared-tilassa.

Owned-tilassa olevaan välimuistiin saa kirjoittaa, ja kirjoittajan pitää tällöin lähettää se kirjoitettu data muille välimuisteille. Mutta tämä datan siirtäminen muille välimuisteille ei tapahdu yhdessä kellojaksossa.

Ja sääntöhän on nimenomaan pitämään muisti ehjänä, jos sääntö olisi joku muu kaksi kirjoitusta voisi osua samaan välimuistilinjaan yhtäaikaa ja raudalla pitäisi olla joku muu keino selvittää mikä data on jäävä ja mikä poistettava. MESI siis hoitaa vain muistin ja välimuistien yhtenäisyyden, muut monisäikeistyvän ohjelmoinnin ongelmat on vielä jäljellä.

MESI ei tosin nykyaikana hoida enää yhtään mitään juuri missään.

Ja ei tässä puhuttu kahden kirjoituksen välisestä tilanteesta vaan luvun ja kirjoituksen välisestä tilanteesta.
 
MESI ei tuota ongelmia sisäistää, vaan sinulle tuottaa ongelmia sisäistää se, että MESI on esihistorialliselta ajalta, kun monta prosessoriydintä tarkoitti erillisiä prosessoripiirejä joita yhdisti yksi jaettu väylä, eikä sitä enää käytetä juuri missään enää. (Ehkä joku raspberry pi tms. todella low-end-rauta saattaa käyttää, mutta mikään missä suorituskyvyllä oikeasti on väliä, ei todellakaan käytä)

Se on nykyään korvattu esim. MOESI:lla tai MESIF:llä, tai jollain hakemistopohjaisella protokollalla.

AMD ei ole koskaan käyttänyt MESIä. Heti ensimmäisessä montaa prosessoria tukevassa prossumallissaan (Athlon MP) AMD käytti MOESIa.

Intel taas taisi vaihtaa MESIF:iin Nehalemissa, n. 9 vuotta sitten.

MOESIssa voi aivan hyvin olla yhdellä välimuistilla linja Owned-tilassa ja toisella välimusitilla sama välimuisti Shared-tilassa.

Owned-tilassa olevaan välimuistiin saa kirjoittaa, ja kirjoittajan pitää tällöin lähettää se kirjoitettu data muille välimuisteille. Mutta tämä datan siirtäminen muille välimuisteille ei tapahdu yhdessä kellojaksossa.

No älä nyt nolaa itseäsi. Mesi on tuo protokolla, alkuperäinen versio oli jo MOESI mutta O-tilan hyödyllisyys on aina ollut vähän kysymysmerkki, dirtyn linjankin kun voi myös siirtää toiselle ytimelle. Forward Intelillä on vain vähentämässä koherenssiliikennettä eli vain yksi jaetun datan omistaja jakaa sitä eteenpäin.

Mutta aivan samasta protokollasta siis kyse ja kyseisen protokollan tapa hoitaa muistikoherenssius on siis se että ennen cachelinjaan kirjoittamista protokolla invalidoi samat linjat muista cacheista. Enkä muunlaisia välimuistiprotokollia oikeastaan tiedä nykyään missään käytettävän.

Ja O-tila on siis sama kuin shared, siihen ei voi kirjoittaa. Shared-linjat voi poistaa cachesta ilman takaisinkirjoitusta joten jos dirtyn linjan jakaa yhden shared-tilan pitää olla sellaisessa muodossa että sitä ei voida poistaa cachesta ilman kirjoitusta muistiin, siksi se on tuo O.
 
Viimeksi muokattu:
Se on nykyään korvattu esim. MOESI:lla tai MESIF:llä, tai jollain hakemistopohjaisella protokollalla.

Eli sama protokolla ja nimi tulee mahdollisista linjojen tiloista, se ei ota kantaa toteutukseen. Eli hakemistopohjainen MESI on taulukko jossa on bitti per cachelinja osoittamassa onko linja käytössä jossain. Tai full-vector toteutuksessa myös missä ytimissä ko. linja on käytössä. Osoitteet voi toki pakata ja hakemiston ei tarvitse kattaa kaikkea, jos ei hakemisto pysty kertomaan ko. cachelinjan tilaa niin snoopataan kaikki mahdolliset paikat - esimerkiksi Intelin serveriprossuissa on monta mahdollista snooppitilaa ja mm. prosessorin snooppitaulukon lisäksi ECC-bitteihin voidaan kirjoittaa onko linja vapaa, jaettu tähän nodeen vai jaettu muualle eli tarviiko snoopata, ja jos tarvii niin riittääkö oma node vai pitääkö käydä kaikki läpi.

Ja siis koko koherenssi tarkoittaa että koko muistissa, välimuistit mukaanlukien ei ole tilannetta että samassa osoitteessa voisi olla kaksi erilaista arvoa. Koska em. tilanne vaatisi aika merkittävästi monimutkaisempaa logiikkaa selvittää mikä data on säilytettävä.
 
Mesi on tuo protokolla, alkuperäinen versio oli jo MOESI mutta O-tilan hyödyllisyys on aina ollut vähän kysymysmerkki, dirtyn linjankin kun voi myös siirtää toiselle ytimelle. Forward Intelillä on vain vähentämässä koherenssiliikennettä eli vain yksi jaetun datan omistaja jakaa sitä eteenpäin.

Eli jos dirty linja jaetaan toiselle ytimelle dirtynä ja invalidoidaan alkuperäinen kopio voi datan saanut ydin kirjoittaa siihen ilman että dataa tarvitsee invalidoida muilta ytimiltä - varsinkin lukitusdatan kanssa nopeampi vaihtoehto kuin jakaminen jättämällä kopio alkuperäiselle omistajalle.

AMD näköjään käyttää kumpaakin tapaa, eli käytetty protokolla on nykyään MDOEFSI, eli koherenssiprotokolla koittaa päätellä onko data jaetussa lukukäytössä vai vuorotellen kahden eri ytimen manipuloitavana, eli siis jaetaanko likainen linja Dirtynä ilman jäävää kopiota alkuperäiselle omistajalle vai jaettuna jolloin alkuperäiselle omistajalle jää kopio (O) ja uusi omistaja joutuu lähetttämään invalidointipyynnön ennen kuin voi kirjoittaa siihen.
 
No älä nyt nolaa itseäsi. Mesi on tuo protokolla, alkuperäinen versio oli jo MOESI mutta O-tilan hyödyllisyys on aina ollut vähän kysymysmerkki, dirtyn linjankin kun voi myös siirtää toiselle ytimelle.

Ei voi järkevästi jos käytössä on vain 4 tilaa, M , E , S ja I koska silloin joko
1) Meillä olisi kaksi eri välimuistia M-tilassa mikä olisi laitonta ja meillä olisi konflikti sen suhteen mitä tehdään takaisinkirjoiuksen kanssa sekä sen suhteen, kumpi siihen saa seuraavaksi kirjoittaa.
2) Se invalidoitaisiin siitä alkuperäisestä sen kirjoittaneesta välimuistista. Jos toinen vain lukee sitä, tämä olisi hirveää haaskausta, kun hyvää paikkaansapitävää dataa invalidoitaisiin, tulisi "turha" huti kun sitä dataa seuraavan kerran accessoitaisiin siitä alkuperäisestä välimuistist.

Forward Intelillä on vain vähentämässä koherenssiliikennettä eli vain yksi jaetun datan omistaja jakaa sitä eteenpäin.

Ei vaan mahdollistamassa sen, että sitä jaettua dataa ylipäätään voidaan lukea muille välimuisteille toisista välimuisteista eikä itse muistista. Saman datan voi lähettää vain yksi lähde kerrallaan. Ilman F-tilaa tulisi konflikti siitä, mistä toisesta välimuistista se lähetetään sitä kaipaavalle, kun pitäisi laajentaa myös S-tila vastaamaan snooppeihin, ja sitten tulisi monesta ERI paikasta "täältä löytyy"-signaali.

Mutta aivan samasta protokollasta siis kyse ja kyseisen protokollan tapa hoitaa muistikoherenssius on siis se että ennen cachelinjaan kirjoittamista protokolla invalidoi samat linjat muista cacheista. Enkä muunlaisia välimuistiprotokollia oikeastaan tiedä nykyään missään käytettävän.

Ja O-tila on siis sama kuin shared, siihen ei voi kirjoittaa. Shared-linjat voi poistaa cachesta ilman takaisinkirjoitusta joten jos dirtyn linjan jakaa yhden shared-tilan pitää olla sellaisessa muodossa että sitä ei voida poistaa cachesta ilman kirjoitusta muistiin, siksi se on tuo O.

Ne on eri protokollat joissa O-tilan olemassaolo tai olemattomuus muuttaa oleellisesti toiminnallisuutta silloin kun yksi lukee ja toinen kirjoittaa.

O-tila mahdollistaa optimoinnin, jossa O-tilassa olevaan kirjoitetaan heti eikä tarvi odotella mitään kuittausta siitä, että invalidoinnit on menneet perille, koska muut eivät kuitenkaan voi yrittää kirjoittaa niissä S-tilassa olevaan välimuistilinjaan ilman kuittausta muilta välimuisteilta. Mikäli joku yrittää ottaa välimuistilinjaa samaan aikaan omakseen, muut failaavat, O-tilassa oleva onnistuu.

ja invalidointisignaali (tai datan broadcastaus, jos toteutus on sellainen, että samalla lähettää uuden datan) voi saapua sitten joitain (tai jopa joitain kymmeniä) kellojaksoja myöhemmin.

Samaa optimointia ei voi tehdä MESI:lle, koska kaikki S-tilassa datan jakavat on siinä tasa-arvoisia, siinä pitää oikeasti varmistua, että se välimuistilinja saadaan omaksi.

MOESI on sarjallisesti konsistentti. Se tarkoittaa sitä, että kaikkein järjestelmässä tapahtuvien muistioperaatioden järjestys näyttää (kaikilla ytimille pyoirivlle softille) softalle samalta, kuin järjestelmässä, jossa mitäään välimuisteja ei olisi, mutta se ei tarkoita sitä, että joka ikinen kellojakso missään ei olisi kahta eri kopioita samasta datasta.

Tilanteessa, jossa siellä on samasta datasta kaksi eri versiota, toinen niistä on invalidoitumassa ja katoamassa välimuistista mutta se invalidointi voi tulla joitain kellojaksoja myöhässä. Se on tällöin matkalla kohti tilaa, jossa missään ei ole kahta kopioita samsata datasta, mutta ei ole vielä saavuttanut sitä tilaa.

Nykyisten prosessorien ja järjestelmien väylärakenne on monimutkainen, ja data vaan ei kulke joka paikkaan yhdessä kellojaksossa. Eikä viidessä. Eikä edes kymmenessä. Se, ettei aina tarvi odotella kuittausta voi tehdä monista kirjoituksista selvästi nopeampaa.

Ja siis koko koherenssi tarkoittaa että koko muistissa, välimuistit mukaanlukien ei ole tilannetta että samassa osoitteessa voisi olla kaksi erilaista arvoa.

Ei tarkoita.

Vaan se tarkoittaa sitä, että kaikille muistia käyttäville tahoille (käytännössä ytimille) näkymä muistiin on konsistentti välimuistista huolimatta. Tämä konsistenttiusvaatimus käytännössä tarkoittaa sitä, että tilannetta jossa samasta datasta on välimuisteissa monta eri versiota pyritään välttämään ja tämä tilanne ei koskaan ole pitkään voimassa. Mutta se voi olla hetkellisesti voimassa. Tällöin kuitenkin systeemillä on aina tarkka tieto siitä, mikä näistä kopioista on viimeisin joka pitää säilyttää ja se "vanhentunut versio" datasta katoaa sitten kun joku jo matkalla oleva välimuistin koherenttiusdatapaketti saavuttaa sen välimuistin missä se on.

Sen vanhan datan voi kuitenkin sieltä toisesta välimusitista lukea tällä välin siihen välimuistiin suoraan kytketty ydin. Tilanne, jossa se niin tekee tarkoittaa aina jompaa kumpaa seuraavista asioista, joko
1) se lukeva ydin käytännössä lukee jotain syknronointimuuttujaa, että "onko toinen vapauttanut lukon tai merkannut signaalin että se on valmis". Tällöin se saa tiedon, että ei ole, odottelee vähän kauemmin, yrittää kohta uudestaan ja saa silloin vähän myöhemmin päivitetyn arvon ja pääsee jatkamaan tai
2) Softan synkronoinnit on rikki. Tätä tilannetta ei kuitenkaan "kellojaksontarkka" tiukempi välimuistikoherenssikaan pelastaisi, softa bugaisi vaikka mitään välimuisteja ei olisi.

Tilanne, jossa softa yrittää "laillisesti lukea" toisen muuttaman dataa seuraavalla kellojaksolla ja saa vanhan "laittoman" arvon ei ole mahdollinen, koska se ei voi tietää, että sitä muuttaa saa lukea ennen kuin se on synkronoinnilla saanu tämän tiedon. Ja muistin konsistenttiussäännöt määrittelee, että se ensin tehty kirjoitus näkyy tälle toiselle ytimelle ennen kuin se synkronointi näkyy tälle, se "vanha data" data on invalidoitu siihen mennessä kun sen toinen ydin pystyy saamaan synkrponoinnilta tiedon, että "saa jatkaa" (se koherenssius on toteutettu siten, että konsistenttiusehto toteutuu)

Koska em. tilanne vaatisi aika merkittävästi monimutkaisempaa logiikkaa selvittää mikä data on säilytettävä.

Ei se vaadi mitään monimutkaista logiikka, se on päivänselvää niistä tiloista. S-tilassa olevaa dataa ei koskaan saa välittää muille välimuisteille eikä sitä koskaan kirjoiteta takaisin päämuistiin. Ja S-tilassa oleva välimuistilinja ei voi muuttua M tai O-tilaan jos joku muu välimuistii on jo jommassa kummassa näistä tiloista kommikoimatta tämän toisen välimuistin kanssa ensin. Tässä vaiheessa viimeistään huomataan, että muualla on jo samasta datasta uudempi versio.

AMD näköjään käyttää kumpaakin tapaa, eli käytetty protokolla on nykyään MDOEFSI, eli koherenssiprotokolla koittaa päätellä onko data jaetussa lukukäytössä vai vuorotellen kahden eri ytimen manipuloitavana, eli siis jaetaanko likainen linja Dirtynä ilman jäävää kopiota alkuperäiselle omistajalle vai jaettuna jolloin alkuperäiselle omistajalle jää kopio (O) ja uusi omistaja joutuu lähetttämään invalidointipyynnön ennen kuin voi kirjoittaa siihen.

Onko sinulla jossain linkkiä tähän protokollaan vai mutuiletko vaan miten LUULET sen toimivan?
 
Viimeksi muokattu:
O-tila mahdollistaa optimoinnin, jossa O-tilassa olevaan kirjoitetaan heti eikä tarvi odotella mitään kuittausta siitä, että invalidoinnit on menneet perille, koska muut eivät kuitenkaan voi yrittää kirjoittaa niissä S-tilassa olevaan välimuistilinjaan ilman kuittausta muilta välimuisteilta. Mikäli joku yrittää ottaa välimuistilinjaa samaan aikaan omakseen, muut failaavat, O-tilassa oleva onnistuu.

Onkos lähteitä että näin on jossain toimittu? Eli jos cache-koherenssi rikotaan siitä on seurauksia koodin toimivuuteen, eli esimerkiksi se lukituskoodi joka olettaa että cachesta luettu data on ajantasalla ei enää pädekään. Ihan alkuperäisessä dokumentaatiossa O ja S-tilat on ihan tasaveroisia, kumpaankin kirjoitus edellyttää muiden invalidointia ensin ihan kuten muissakin kirjoitustapauksissa. O tila on vain takaisinkirjotusta varten jotta linja ei voi poistua cachesta ilman takaisinkirjoitusta muistiin. Koherenssin määritys on ollut että luku osoitteeseen X joka tapahtuu kirjoituksen osoitteeseen X jälkeen saa nimenomaan tuon viimeisimmän kirjoituksen tuloksen eikä jotain vanhempaa. Tämä tapahtuu nimenomaan niin että muut cachet on invalidoitu ENNEN kirjoitusta ilman poikkeuksia.

MOESI on sarjallisesti konsistentti. Se tarkoittaa sitä, että kaikkein järjestelmässä tapahtuvien muistioperaatioden järjestys näyttää (kaikilla ytimille pyoirivlle softille) softalle samalta, kuin järjestelmässä, jossa mitäään välimuisteja ei olisi, mutta se ei tarkoita sitä, että joka ikinen kellojakso missään ei olisi kahta eri kopioita samasta datasta.

No miksi sitten yrität tehdä siitä jotain muuta? Eli luku osoitteeseen x saa viimeisimmän kirjoitetun tuloksen, ei määritelmä anna tähän poikkeuksia.

Onko sinulla jossain linkkiä tähän protokollaan vai mutuiletko vaan miten LUULET sen toimivan?

Toki.


 
No miksi sitten yrität tehdä siitä jotain muuta? Eli luku osoitteeseen x saa viimeisimmän kirjoitetun tuloksen, ei määritelmä anna tähän poikkeuksia.

Ei. Se saa viimeisen kirjoitetun tuloksen joka on tapahtunut "tapahtumahorisontin" sisällä.

"Tapahtumahorisontin ulkopuolella" voi olla tapahtunut uusi kirjoitus, josta mikään koherenttiusviesti ei ole vielä lukijalle ehtinyt, jolloin se saa vanhan arvon.

Ja jos data menee esim. yhdeltä CCD-piilastulta toiselle, tässä voi käytännössä kestää kymmeniä kellojaksoja.

Eri välimuistien välillä ei ole määritelty tarkkaa tiukkaa aikakäsitystä, vaan ainoastaan asioiden oikea järjestys, ja välimuistikoherenttius pakottaa asiat (konsistenttiussääntöjen mukaiseen) oikeaan järjestykseen.


Eli siis ollutkaan, vaan mutuilit.

Näistä linkeistä ensimmäinen on vuodelta 1993 ja puhuu ihan eri koherenttiusprotokollasta.

Se ei todellakan kerro Zenin MDOEFSI:stä.

Jälkimmäinen sen sijaan sanoo ainoastaan:

AMD Hot chips slides sanoi:
7-state coherence protocol: MDOEFSI ‒ D: Dirty, migratory sharing optimization

Eikä sisällä mitään tarkempia yksityiskohtia tästä. Toki tiedetään, mitä sanoja nuo kirjaimet tarkoittaa, mutta mikä tuo tarkka semantiikka sitten tuolla D:llä on, miten se esim. eroaa M:stä tai O:sta, siitä ei ole sanottu mitään. Tuossa 1993-vuoden paperissa mihin linkkasit ei ollut M-tilaa ollenkaan vaan M-tila oli käytännössä siinä nimetty D:ksi, sen D-tilan semantiikan perusteella ei voi sanoa varmaksi mitään tämän D-tilan semantiikasta (ja sen eroista M- ja O-tiloihin)
 
Viimeksi muokattu:
Ei. Se saa viimeisen kirjoitetun tuloksen joka on tapahtunut "tapahtumahorisontin" sisällä.

"Tapahtumahorisontin ulkopuolella" voi olla tapahtunut uusi kirjoitus, josta mikään koherenttiusviesti ei ole vielä lukijalle ehtinyt, jolloin se saa vanhan arvon.

Ja jos data menee esim. yhdeltä CCD-piilastulta toiselle, tässä voi käytännössä kestää kymmeniä kellojaksoja.

Eri välimuistien välillä ei ole määritelty tarkkaa tiukkaa aikakäsitystä, vaan ainoastaan asioiden oikea järjestys, ja välimuistikoherenttius pakottaa asiat (konsistenttiussääntöjen mukaiseen) oikeaan järjestykseen.

Muistin ollessa koherenttia on määritelmä aivan aukoton: Luku osoitteesta x kirjoituksen osoitteeseen x jälkeen antaa arvoksi tuon kirjoituksen arvon eikä mitään vanhempaa arvoa. MESI ja sen johdannaiset cache-coherenssiprotokollat on tehty täyttämään tuo määritelmä. Toki suorituskyvylle olisi paljonkin etua jos cache-koherenssista ei tarvitsisi välittää mutta se avaa samalla pandoran lippaan kaikenlaisille algoritmiongelmille, lukitus on vain yksi osa ongelmaa. En ole kuullut että cache-koherenssi olisi määritelty viimeaikoina uusiksi.
 
Huomautus - älä kirjoita toistuvia peräkkäisiä viestejä, vaan käytä foorumin lainaa-toimintoa, kiitos
Eikä sisällä mitään tarkempia yksityiskohtia tästä. Toki tiedetään, mitä sanoja nuo kirjaimet tarkoittaa, mutta mikä tuo tarkka semantiikka sitten tuolla D:llä on, miten se esim. eroaa M:stä tai O:sta, siitä ei ole sanottu mitään. Tuossa 1993-vuoden paperissa mihin linkkasit ei ollut M-tilaa ollenkaan vaan M-tila oli käytännössä siinä nimetty D:ksi, sen D-tilan semantiikan perusteella ei voi sanoa varmaksi mitään tämän D-tilan semantiikasta (ja sen eroista M- ja O-tiloihin)

No turha sun on noita lukea kun cache-koherenssiuskaan ei mene millään perille, se nyt ei ole mikään vaikea asia. Olet selittänyt asiasta ihan mitä sattuu mutua.

Mitä tulee tuohon semantiikkaan niin AMD selvästi kertoo että D: Dirty, migratory sharing optimization mistä myös tuo whitepaper kertoo. AMD vain on toteuttanut omansa omaamaan sekä likaisen linjan jakamisen että siirtämisen toiselle ytimelle, aivan luonnollinen kehitys.
 
No turha sun on noita lukea kun cache-koherenssiuskaan ei mene millään perille, se nyt ei ole mikään vaikea asia. Olet selittänyt asiasta ihan mitä sattuu mutua.

Minulle se on mennyt huomattavasti paremmin perille kuin sinulle, ja mutua siitä on täällä selittänyt sinä, en minä. Koska olet täysin jumissa tuossa ylitiukassa määritelmässäsi, joka ei ole sen todellinen määritelmä.

Mitä tulee tuohon semantiikkaan niin AMD selvästi kertoo että D: Dirty, migratory sharing optimization mistä myös tuo whitepaper kertoo.

Sinulla lienee suuria ongelmia ymmärtää, mitä sana "semantiikka" tarkoittaa.

Modified on myös likainen, Owned on myös likainen, ja likainen tila löytyy myös WB-välimuistista jossa ei ole mitään koherenttiutta.

Semantiikka tarkoittaa asioiden TARKKAA määrittelyä, ei tuollaista käsienheiluttelua että osataan vaan sanoa, mistä sanasta lyhenteen kirjain on peräisin.

Tuo muinainen paperi joka puhuu protokollasta jossa ei ole ollenkaan M- ja O-tiloja ei kerro ollenkaan noiden tilojen erosta D-tilaan zenillä.

AMD vain on toteuttanut omansa omaamaan sekä likaisen linjan jakamisen että siirtämisen toiselle ytimelle, aivan luonnollinen kehitys.

Kyllä se tiedetään jo, että sinulla ei ole hajuakaan sen todellisesta tarkasta semantiikasta, mutta et vaan millään voi myöntää tätä, ja esität tietäväsi tai yrität vähätellä sen tarkan semantiikan merkitystä.

Minäkään en sitä (vielä) tiedä, mutta en esitä tietäväni, tiedän mitä en tiedä enkä väitä tietäväni asioita joita en tiedä.

Asian osaa oikeasti siinä vaiheessa kun sen osaa tehdä/koodata.
 
Viimeksi muokattu:
Minäkään en sitä (vielä) tiedä, mutta en esitä tietäväni, tiedän mitä en tiedä enkä väitä tietäväni asioita joita en tiedä.

Asian osaa oikeasti siinä vaiheessa kun sen osaa tehdä/koodata.

No tämähän oli varmasti sarkasmia. Kukahan tässä on ollut pihalla kuin lumiukko siitä kuinka cache-koherentissa järjestelmässä kirjoitukset jaettuun dataan tehdään. Koherenssia tarkistellaan muulloinkin kuin L3-missien yhteydessä.

Ja jos cache-koherenssin määritelmä on ylitiukka niin annapas linkki johonkin jossa selvennetään kuinka löyhempien sääntöjen kanssa voidaan tulla toimeen? Esimerkiksi siitä että owned-tilaan voi kirjoittaa ilman muiden datojen invalidointia ensin. Kyllä, shared-tila muissa estää että samaan linjaan ei voi muut ytimet kirjoittaa mutta kun owned-linjoja voi olla enemmän kuin yksi niin useamman kanssa pelleillessä lähestytään hyvin nopeasti mahdollista deadlockkia tai muuta datan korruptiota.
 
Ja jos cache-koherenssin määritelmä on ylitiukka niin annapas linkki johonkin jossa selvennetään kuinka löyhempien sääntöjen kanssa voidaan tulla toimeen? Esimerkiksi siitä että owned-tilaan voi kirjoittaa ilman muiden datojen invalidointia ensin.

Vaihdetaan tila E-tilaksi, ja broacatataan paketti joka invalidoi sen niiltä keillä se oli S-tilassa. Ja tehdään oma kirjoitus HETI eikä odoteta että invalidointipaketit menee perille ja niistä saadaan kuittaus. Muualta data invalidoituu sitten myöhemmin kun invalidointipaketit menevät perille.

Tässä välissä muut voivat LUKEA mutta eivät kirjoittaa tämän välimuistilinjan sisältämää dataan(nsa). Jos ne yrittävät kirjoittaa, niiden pitää saada linja itselleen mitä ne eivät voi saada ennen kuin saavat tiedon muualla tapahtuneesta kirjoituksesta. Jolloin niiden kirjoitus jumittaa, ne saavat invalidointipaketin, niiden välimuisti invalidoidaan, niille tulee write miss ja muualla kirjoitettu data kopioidaan niille ennen kuin ne pystyvät kirjoittamaan, ja kirjoitukset menevät oikeaan järjestykseen.

Kyllä, shared-tila muissa estää että samaan linjaan ei voi muut ytimet kirjoittaa mutta kun owned-linjoja voi olla enemmän kuin yksi niin useamman kanssa pelleillessä lähestytään hyvin nopeasti mahdollista deadlockkia tai muuta datan korruptiota.

Vain yhdellä välimuistilla voi olla sama linja owned-tilassa. Se on omistamisen pointti.

Ja deadlock ei ole datan korruptiota.
 
Viimeksi muokattu:
Vaihdetaan tila E-tilaksi, ja broacatataan paketti joka invalidoi sen niiltä keillä se oli S-tilassa. Ja tehdään oma kirjoitus HETI eikä odoteta että invalidointipaketit menee perille ja niistä saadaan kuittaus. Muualta data invalidoituu sitten myöhemmin kun invalidointipaketit menee perille.

Tässä välissä muut voivat LUKEA mutta eivät kirjoittaa tämän välimuistilinjan sisältämää dataan(nsa). Jos ne yrittävät kirjoittaa, niiden pitää saada linja itselleen mitä ne eivät voi saada ennen kuin saavat tiedon muualla tapahtuneesta kirjoituksesta.

Joku muukin kuin sun mutuilu kiitos. Eli jos koherentin määritelmä on luku osoitteeseen x kirjoituksen osoitteeseen x jälkeen saa tuon kirjoituksen arvon tässä on ristiriita eli cache ei ole koherentti. Missään en ole nähnyt määriteltävän cache-koherenttiutta muuten.


Vain yhdellä välimuistilla voi olla sama linja owned-tilassa. Se on omistamisen pointti.

No en sitä tarkoittanut vaan tietenkin että useampia linjoja voi olla owned-tilassa. Muistin ollessa koherenttia vältytään melkoisen suurelta määrältä ongelmia joita syntyy kun muisti ei ole koherenttia, ja tälläinen tilanne syntyy jos dataa keskenään vaihtavilla prosessoreilla on cachet epäsynkroonissa.
 
Joku muukin kuin sun mutuilu kiitos. Eli jos koherentin määritelmä on luku osoitteeseen x kirjoituksen osoitteeseen x jälkeen saa tuon kirjoituksen arvon tässä on ristiriita eli cache ei ole koherentti. Missään en ole nähnyt määriteltävän cache-koherenttiutta muuten.

Mistä niitä määritelmiäsi olet oikein lukenut?

Legendaarisen Pattersonin ja Hennessyn Computer Organization & Design-kirjan toisessa editiossa puhutaan kyllä välimuistikoherenttiudesta, mutta ei sanota sille ollenkaan tarkkaa määritelmää.

Mutta, jospa aloittaisit vaikka lukemalla wikipediasta sivun "cache coherence"


niin sieltä niitä määritelmiä löytyy vaikka millä mitalla, vaihtoehtoisia mm.

määritelmä A)

1) Kirjoitus mihin tahansa välimuistiin tarvii välittää muille välimuisteille (huom: ei ota kantaa, KOSKA)
2) Kaikki ytimet näkee accessit samaan osoitteeseen samassa järjestyksessä (huom: järjestys koskee vain sitä, koska kukin säie ne NÄKEE; ei koska tapahtuu)

(Se, että kaikki ytimet näkee kaikki accessit samssa järjestyksessä johtaa siihen, että se jonkun muuttama data pitää välittää muille ennen kuin joku muu saa kirjoittaa, jotta kirjoitusten järjestys näky samana kaikille)

määritelmä B)

1) Jos prosessori itse kirjoittaa muistipaikkaan X, ja sen jälkeen lukee muistipaikasta X, eikä kukaan muu prosessori kirjoita samaan muistipaikkan välissä, se saa saman datan kuin mitä itse kirjoitti
2) Jos Prosessori P1 lukee osoitetta X sen jälkeen kun prosessori P2 on kirjoittanut siihen, eikä mikään prosessori ole kirjoittanut osoitteeseen X tässä välissä, ja kirjoituksen ja luvun välillä on riittävästi aikaa, sen täytyy palauttaa arvo jonka P2 sinne kirjoitti.

määritelmä C)

Kirjoitusten samaan osoitteeseen pitää olla sarjallisia. Jos muistiosoite X koskaan saa arvot A ja B, tässä järjestyksessä, sieltä lukeminen palauttaa nämä arvot aina samassa järjestyksessä, ei ole mahdollista että joku voi lukea sieltä ensin arvon B ja sitten arvon A.

Huom. Tässäkään ei oteta kantaa järjestykseen eri luvuille eri prosessorien välillä vaan siihen, että jokaiselle prosessille A:n ja B: järjestykset on samat.

Määritelmä D)

"the cache coherent system must appear to execute all threads’ loads and stores to a single memory location in a total order that respects the program order of each thread".

Missään näistä ei puhuta mitään mistään absoluuttisesta seinäkelloajasta ja accessien pakottamiseen säikeiden välillä sen mukaan tiukkaan järjestykseen. Vaan puhutaan siitä, missä järjestyksessä eri ytimet/prosessorit/säikeet näkee asioiden tapahtuvan.

Vielä ziljoonannen kerran: Monen prosessorin järjestelmässä EI ole mitään absoluuttista seinäkelloaikaa jonka mukaan voitaisiin verrata eri säikeiden tekemien asioiden absoluuttista järjestystä. Jokaisella säikeellä on oma aikakäsityksensä. Voidaan verrata vain sitä järjestystä, missä kukin ne NÄKEE, ja tämän "kullekin näkyvän järjestyksen" pitää täsmätä, että kaikki NÄKEE kirjoitukset samaan osoitteeseen samassa järjestyksessä.


No en sitä tarkoittanut vaan tietenkin että useampia linjoja voi olla owned-tilassa. Muistin ollessa koherenttia vältytään melkoisen suurelta määrältä ongelmia joita syntyy kun muisti ei ole koherenttia, ja tälläinen tilanne syntyy jos dataa keskenään vaihtavilla prosessoreilla on cachet epäsynkroonissa.

Piirissä, jossa on miljardeja transistoreita asiat vaan on keskenään "epäsynkassa" koska kaiken pitäminen synkassa olisi todella, todella hidasta.

Mutta ne ei ole liian epäsynkassa, vaan hallitusti epäsynkassa, siten että muistin konsistenttiusehdot säilyy.

Ja jos kunkin säikeen kirjoitukset välimuisteissa eri osoitteisiin pidetään järjestyksessä(kuten esim. x86n konsistenttiussäännöt pakottavat), mitään deadlockeja ei tule, TAI jos niitä on, ne on sellaisia, että ne tulisi vaikka mitään välimuistia ei olisi.
 
Viimeksi muokattu:
Vielä ziljoonannen kerran: Monen prosessorin järjestelmässä EI ole mitään absoluuttista seinäkelloaikaa jonka mukaan voitaisiin verrata eri säikeiden tekemien asioiden absoluuttista järjestystä. Jokaisella säikeellä on oma aikakäsityksensä. Voidaan verrata vain sitä järjestystä, missä kukin ne NÄKEE, ja tämän "kullekin näkyvän järjestyksen" pitää täsmätä, että kaikki NÄKEE kirjoitukset samaan osoitteeseen samassa järjestyksessä.

Tapahtumajärjestys. Eli kun tallennus vaatii muiden cachejen invalidoinnin ennen tallennusta säilyy muistin ohjelmanmukainen järjestys. Mitä tapahtuu jos koherenssiprotokolla antaa kirjoittaa osoitteseen ja invalidointi lähtee samalla - prosessori kirjoittaa seuraavat jonossa olevat tallennukset ja jos prosessori johon tämä invalidointi on lähtenyt onkin lataamassa samaan aikaan tätä jälkimmäisen kirjoituksen cachelinjaa jota sillä ei aikaisemmin cachessaan ollut se saa tämän tuloksen käyttöönsä ennen kuin tuon ensimmäisenä kirjoitetun tuloksen. Eli ainakin TSO on täysin turha jos koherenssiprotokolla ei toimi tiukkojen sääntöjen puitteissa.
 
Tapahtumajärjestys. Eli kun tallennus vaatii muiden cachejen invalidoinnin ennen tallennusta säilyy muistin ohjelmanmukainen järjestys.

Koherenttiudella ei ratkota konsistenttiusongelmia, ei vaikka siitä tehdään "ylitiukka", jos itse konsistenttiutta ei ole hanskattu jotenkin.
Sillä "ylitiukalla kohjerenssiudella" ainoastaan hidastetaan asioita turhaan.

Eikä missään järkevässä systeemissä edelleenkään ole mitään kaikille yhteistä aikaa jonka mukaan tuon "ennen" voi määritellä.

On vain järjestys, jossa kukin näkee kirjoitukset. Ja tämän järjestyksen pitää olla sama samalle osoitteelle, jotta systeemi on välimuistikoherentti.

Sitten kun puhutaan kirjoituksista ERI osoitteisiin, puhutaan muistin konsistenttiudesta. joka on eri asia kujn (väli) muistin koherenttius.

Mitä tapahtuu jos koherenssiprotokolla antaa kirjoittaa osoitteseen ja invalidointi lähtee samalla - prosessori kirjoittaa seuraavat jonossa olevat tallennukset
ja jos prosessori johon tämä invalidointi on lähtenyt onkin lataamassa samaan aikaan tätä jälkimmäisen kirjoituksen cachelinjaa jota sillä ei aikaisemmin cachessaan ollut se saa tämän tuloksen käyttöönsä ennen kuin tuon ensimmäisenä kirjoitetun tuloksen.

Sillä, koska se data fyysisesti saapuu sille ei ole mitään väliä, vaan väliä on sillä, 1) missä järjestyksessä ne sen datan saavat latauskäskyt on sen alkuperäisessä käskyvuossa. Tämä käskyjen järjestys käskyvuossa on ainoa aikakäsitys, mikä säikeillä on. KAIKKI järjestys ja aika mitataan ainoastaan tämän perusteella. 2) Miltä tallennuksilta on peräisin arvot, jotka saadaan, mikä niiden keskenäinen järjestys on, mikä näiden tallennuskäskyjen alkuperäinen järjestys on.

Tässä tapauksesas: Mikäli molemmat lataukset saa muutetun arvon, mitään ongelmaa ei ole. Kaikki näkyy lukijalle oikeassa järjestyksessä, molemmat luvut saavat arvot jotka on sallitun semantiikan mukaisia.

Kun kirjoittajan päässä kaikki kirjoitukset kirjoitetaan välimuistiin järjestyksessä, ainoa tilanne missä voi tulla ongelmia on se, että lataukset saapuvat eri järjestyksessä - ja tällä latausten järjestyksellä ei ole välimuistikoherenttiuden kanssa MITÄÄN tekemistä.

Käytännössä ainoa ei-tiviaali ongelmatilanne esiintyy, kun:

Prosessori B lukee muuttujat X ja Y, mutta X:n esim. osoitteenlaskenta tarvii jotain dataa jota ei ole vielä saatu, ja lataus osoitteeseen X jää odottamaan osoitetta. Yn osoite sen sijaan saadaan laskettua heti. Suoritetaan lataus Y. Sillä, mistä se tulee, tuleeko se paikallisesta välimuistista vai toisesta välimuistista, ei ole väliä.

Tällä välin prosessori A kirjoittaa osoitteisiin X ja Y, ja tieto näistä kirjoituksista myös tulee ytimelle B. Tämän jälkeen prosessori B saa vihdoin X:n osoitteen laskettua ja tekee latauksen, ja saa A:n kirjoittaman uuden arvon muuttujalle X.

Se, millainen aikakäsitys koherenttiusprotokollalla on ei vaikuta yhtään mitenkään tähän ongelmaan. Tämä on puhdas konsistenttiusongelma, joka tulee niiden latausten uudelleenjärjestämisesta.

Ja tämä pitää ratkaista jotenkin, ihan riippumatta siitä millainen koherenttiusprotokolla on käytössä. Eli siellä on joku logiikka pitämässä huolen, että tätä ongelmaa ei tapahdu.

Eli ainakin TSO on täysin turha jos koherenssiprotokolla ei toimi tiukkojen sääntöjen puitteissa.

Koherenttiudelle on tiukat säännöt, ne säännöt vaan on löysemmät kuin mitä sinä kuvittelit(vai edelleen kuvittelit?) niiden olevan. Koherenttius ottaa kantaa vain samaan osoitteeseen tuleviin accesseihin.

Halutun konsistenttiusmallin ylläpitämiseen voi sitten olla lisämekanismeja (jotka käytännössä on läheisessä yhteydessä konsistenttiuslogiikkaan).
Mutta ylitiukat globaalliin aikaan pohjautuvat "koherenttiussäänöt" millään tavalla ratkaise konsistenttiusongelmia. kts esimerkkini yllä.



X86n konsistenttiussäännöt sanoo että suorituksen pitää aina tuottaa sama tulos kuin minkä se tuottaisi tilanteessa, jossa 1) latauksia tai ei uudelleenjärjesteltäisi toisten (saman säikeen) latausten kanssa 2) tallennuksia ei uudelleenjärjesteltäisi toisten (saman säikeen) tallennusten kanssa 3) tallennuksia ei saa uudelleenjärjestellä niitä vanhempien (saman säikeen) latausten kanssa (sen siijaan uuden latauksen saa uudelleenjärjestelllä vanhemman latauksen kanssa, jos näiden välillä ei ole datariippuvuutta) 4) Talletuksilla samaan osoitteeseen on täydellinen järjestys == systeemi on koherentti) 5) Lukkoflagin omaavilla käskyillä on koko järjestelmässä täydellinen järjestys 6) lataus- tai tallennuskäskyjä ei saa järjestellä lukkokäskyjen kanssa.

Tässä siis säännöt 1+2 yhdessä kieltävät ydintä B näkemästä toisen ytimen A tallennuksia eri osoitteisiin eri järjestyksessä.

Mutta, mikäli ytimet A ja B kirjoittavat eri osoitteisiin X ja Y, ytimet C ja D saavat nähdä nämä eri järjestyksessä.
 
Viimeksi muokattu:
Eikä missään järkevässä systeemissä edelleenkään ole mitään kaikille yhteistä aikaa jonka mukaan tuon "ennen" voi määritellä.

Ei ole kyse mistään yhteisestä ajasta, ennen meinaa että ko. muistiosoitteen vanhemmat arvot on invalidoitu kaikista paikoista ennen uuden arvon kirjoittamista. Ko säännön toteuttamalla muisti on aivan kokoajan koherentissa tilassa, ts. millään hetkellä muistista ei ole luettavissa samasta osoitteesta kahta eri arvoa.

Eli kun puhe on MESI-protokollasta se on ns. write exclusive-protokollasta, eli kirjoitus onnistuu vain eksklusiiviseen cachelinjaan. Jos tila ei ole eksklusiivinen se hankitaan(invalidoimalla kaikki muut kopiot) ennenkuin protokolla antaa luvan kirjoittaa. MESI:n toteuttavassa protokollassa muisti on täysin koherenttia joka ikinen kellojakso joka ikiselle muistista lukevalle prosessorille.

Tässä siis säännöt 1+2 yhdessä kieltävät ydintä B näkemästä toisen ytimen A tallennuksia eri osoitteisiin eri järjestyksessä.

TSO antaa hyvin paljon rajoituksia raudalle, ja niistä ei ole mitään hyötyä jos muistikoherenssiprotokolla antaa yhtään löysää. Eli siis koherenssiprotokollan on varmistuttuva tavalla tai toisella että cachelinjat näkyvät kirjoitusjärjestyksessä. Aivan simppelein ratkaisu on antaa lupa kirjoitukselle vasta invalidoinnin jälkeen.

No tuohan olisi helppo testata, eli jos siis kirjoitus sallitaan rinnakkain invalidoinnin kanssa kirjoitusnopeus on ihan sama jaetussa tilassa oleviin cachelinjoihin kuin eksklusiiviseen. Jos invalidointi tehdään ennen kirjoitusta kirjoitusnopeus on paljon huonompi. Pikaisesti vain en löytänyt nykyprossuille tehtyä write-invalidate testiä, kumma kun ei ketään ole näyttänyt kiinnostavan.
 
Viimeksi muokattu:
Tämä ketju vastaa pitkälti omaakin käsitystä, että koodin rinnakkaistamisessa on helposti edessä melkoisesti päänsärkyä ja on vähintäänkin kohtalainen riski saada aikaiseksi haasteellisia bugeja.

Harvemmin uutta versiota jostain koodista ruvetaan tekemään kokonaan puhtaalta pöydältä rinnakkaistuksen ehdoilla, vaan lähtökohtana joku olemassaoleva paketti, joka saattaa osittain olla hyvinkin vanhaa. Jos koodi tekee mitään tärkeää, voi olla tarpeen osoittaa, että se toimii oikein. Tämmöiseen kun tekee jonkin purkkarinnakkaistuksen, niin voipa olla tekemätön paikka osoittaa, että rinnakkaistettu versio toimisi aina oikein. Rinnakkaistuksen aiheuttamat virhetoiminnot voi olla hyvinkin salakavalia ja vaikeasti todettavia.
 
Tällainen perustietotason kyssäri kun aloin pohtimaan lueskeltuani kerta toisen jälkeen miten "XYZ on hyvin suoritinintensiivinen mutta vaihtaminen parempaan ei välttämättä auta suhteessa niin paljoa koska käyttää vain yhtä ydintä laskentaan".

Onko monen ytimen hyödyntämisessä joku erityinen ohjelmointipuolen haaste, että sitä ei vakiona tungeta kaikkeen peleistä alkaen jo niiltä ajoilta kun moniytimiä alkoi esiintymään? Eikö tällaista voi mitenkään käyttistasolla tai erikseen hommaan tehdyllä "välimiessoftalla" hoitaa jotenkin "käänteisvirtualisoimalla" useammat ytimet yhdeksi sen ohjelmiston silmissä silloin kun ko. softa alkaa kuormittamaan sitä yhtä ydintä lähes tappiin saakka? Ymmärtääkseni etenkin monet fysiikkaa paljon mallintavat pelitkin hyötyisivät siitä ja prosessori voi olla vajaakäytöllä pullonkaula.
Tässä olikin aikaisemmin monia hyviä vastauksia, mutta erittäin vahvasti yksinkertaistaen on olemassa erilaisia tehtäviä ja näistä tehtävistä on olemassa enemmän tai vähemmän tietoa systeemin eri tasoilla. Yleensä vähemmän ja siksi tällaiset automaattiset rinnakkaistamiset eivät toimi aina.

Mitä taas tehtäviin tulee niin ajattele esim. analogiana työtehtävä jossa meillä on varaston pihalla 20 laatikkoa ja ne pitää kantaa varastoon. Tuollaisen tehtävän saa hyvin rinnakkaistettua 20 työntekijään asti ja yhdellä sen tekeminen taas olisi helvetin hidasta. Toisaalta taas jos pihalla onkin vain yksi iso laatikko jonka sisällä on toinen laatikko ja jonka sisällä taas on kolmas laatikko jne. ja tarkoituksena on päästä käsiksi "viimeiseen" laatikkoon niin tuollaisessa hommassa 1 työntekijä avaisi laatikkoa ja 19 tyyppiä tuijottaisi sivusta monttu auki.

Puheentunnistuksessa taas esim. äänen muuttaminen sanoiksi pitäisi olla aika helposti rinnakkaistettavissa (eri asia onko se sitten sen arvoista), koska esim. kielen sanat ovat samoja sanoja riippumatta siitä mitä on aikaisemmin sanottu. Mutta sitten kun pitää ymmärtää mitä käyttäjä sanoi niin lauseen sanat muodostavat loogisen jonon ja tällöin edeltävät sanat vaikuttavat siihen miten seuraavat sanat tulee tulkita. En ole tosin äänentunnistuksen kanssa henk. koht. työskennellyt joten tämä oli vain naiivi arvaus. Voi olla että asia ei ole näin suoraviivainen käytännössä.
 

Statistiikka

Viestiketjuista
261 317
Viestejä
4 534 957
Jäsenet
74 789
Uusin jäsen
anykanen

Hinta.fi

Back
Ylös Bottom