ARMin ja x86:n muistinsuojaus (jos ne noin suomeksi käännetään) on erilainen ja tästä voi tulla ongelmia käännökseen.
Nyt taitaa mennä termit "muistinsuojaus" ja "muistin konsistenttiussäännöt" sekaisin. Muistinsuojaus on kyllä ihan samanlainen sivupohjainen virtuaalimuisti, ainoana erona että ARM tukee myös sivukokoja 16 kiB ja 64 kiB joita x86 ei tue (ja Apple todennäkjöisesti kohtelee x86ssa käytettyä 4 kiB sivukokoa toisen luokan kansalaisena, vaikak ARMv8 sitä tukeekin).
Seuraava tekstisi liittyy muistin konsistenttiuteen, ei muistinsuojaukseen:
x86:n out-of-order varmistaa aina tiettyjen operaatioiden tapahtuvan tietyssä järjestyksessä mitä tulee muistikirjoituksiin ja lukemisiin, mutta ARMissa ei näin vahvaa suojausta ole. Täten ohjelmat, jotka on testattu toimivaksi x86:lla eivät välttämättä toimi oikein ARMilla, vaikka ne kääntyisivätkin. Luin hiljattain oikein hyvin selitetyn artikkelin aiheesta, joten en sen enempää tähän koske:
Examining ARM vs X86 Memory Models with Rust, mutta samaa x86:n ajatusta olen itse käyttänyt myös Javassa, jossa JVM huolehtii muistioperaatioiden uudelleen järjestelystä hyvin vastaavalla tavalla kuin x86.
Tuota voi käyttää paljon hyväkseen nimittäin suorituskykyä vaativissa operaatioissa, kun voidaan jättää turhia operaatioita välistä pois.
Joo, mutta tuon x86n muistikonsistanttiussääntöjen tiukkuuden hyödyntäminen "normaaleissa user-tilan softissa" on asia minkä pitäisi olla melko harvinaista; Niiden softien määrä joka näitä hyödyntää pitäisi olla hyvin pieni. Enemmän tätä hyödynnetään käyttiksen/säikeistyskirjaston/tulkin(esim. javascript-python) synkronointiprimitiivien toteutuksessa.
Ja tuo sen tason optimointi, että käytännössä yleensä koodari on ensin kuitenkin kirjoittanut koodista "turvallisen" version, jossa kutsutaan jotain järjestelmän synkronointiprimitiivejä, ja sitten vasta jälkikäteen tehnyt tuon optimoinnin, että tajunnut että ne synkronointipriomitiivit voi nimenomaan x86lla ottaa pois juuri tuossa tilanteessa, koska x86n tiukat muistinkonsistenttiussäännöt.
ELi jos se koodi oli alunperin kunnolla kirjoitettu, siellä on jo joku koodi tyyliin
#if (!defined(i386) && !defined(__x64_64))
lock(foo);
#endif
do_something_which_breaks_on_relaxed_memory_ordering();
#if (!defined(i386) && !defined(x64_64))
unlock(foo);
#endif
TAI
#if (defined(i386) || defined(x64_64))
#define myfence
#else
#define myfence something_that_really_implements_fence();
#endif
ja itse koodi
do_first_part_of_something
myfence()
do_second_part_of_something
Jolloin se jo toimii heittämällä ARMilla.
Ongelma tämä on lähinnä binäärikäännökselle, koska se on alunperin käännetty x86lle ja silloin sinne ei ole näitä ARMilla tarvittavia synkronointiprimitiivejä laitettu.
Toki on tietysti myös huonosti kirjoitettua monisäikeistä softaa, jossa ei ole oikeasti mietitty
yhtään tuota muistin konsistenttiutta ja testattu vaan se on x86lla sattunut toimimaan tuurilla oikein, ja se on riittänyt softan julkaisuun ja levittämiseen.
Toinen ongelma tulisi jos ohjelmisto käyttää hyväkseen AVX512 operaatioita, joille ei ole vastaavuuksia ARMilla.
Mistähän yksittäisistä operaatiosta tarkkaan ottaen puhut?
Tällöin ne vektorioperaatiot suoritetaankin yhtäkkiä skalaarina ja suorituskyky voi tippua helposti murto-osaan.
Tähän ei riitä että ARMissa on vektoriprosessointiin käskykannat, kun tarvitaan tietynlaisia käskyjä jotta tiettyjen operaatioiden suorittaminen onnistuu. Esim. AVX512 koodia ei voi kääntää AVX2:lle ja vain kuvitella että suorituskyky tippuisi suhteessa leveyteen, koska sieltä puuttuu esim. tietyt masking operaatiot joilla voi tehdä myös primitivisiä ehtoja.
ARMv8.2:ssa on SVE2 joka on selvästi kehittyneempi kuin AVX-512.
Mikään todellinen ohjelma ei sisällä pelkästään mitään hardkoodattuja AVX512-intrinsiccejä vaan siellä on aina joku
#ifdef __AVX512__
AVX512_intrinsic_code_here();
#else of __SOME_OTHER_SIMD_EXTENSION__
some_other_intrinsic_code_path_here.
#else
simple_loop__or_manually_unrolled_scalar_here;
#endif
SVE(2)ssa on
kehittyneemmät maskaustoiminnot kuin AVX512ssa.
Niin kehittyneet, että melkein minkä tahansa loopin voi kirjoittaa ihan looppina ja kääntäjä pystyy sen vektoroimaan SVE2lla jos loopissa ei vaan ole iteraatioiden välisiä riippuvuuksia; SVE2lla ei ole esim. mitään rajoituksia iteraatiomäärän jaollisuuden suhteen; Looppi voidaan vaan vektoroida ja sinne alkuun lisätään vaan yksi vertailukäsky joka maskaa viimeisellä kierroksella ulos ne iteraatiot, joita ei kuulu suorittaa, eikä haittaa vaikka ne "ylimääräiset linjat" accessoisi muistia jota ei saa accessoida (paitsi mahdollisina sivukanavahyökkäysrajapintoina
, se page fault ignorataan jos sen aiheuttaa vektorilinja joka ei ole aktiivinen.
Eli on aika hyvät saumat, että siitä täysin "optimoimattomasta looppiversiosta" generoituu oikein tehokasta rinnakkaista SVE2-koodia.
Eli mainituissa kuvankäsittely ja äänenkäsittelyohjelmistoissa tällaisia ongelmia voi tulla suorituskyvyn suhteen, koska ARMilla ei ole yksinkertaisesti yhtä kattavaa vektorirajapintaa.
Tietosi ovat vanhentuneita, SVE2 on maailman kehittynein CPUita varten tarkoitettu vektorikäskykanta.
SItä ei toki vielä nykyisin markkinoilla olevissaa puhelimissa olevissa ARM-ytimissä ole, mutta eiköhän sen Apple toteuta omiin "oikeiden tietokoneidensa" ytimiin;
Ensimmäinen SVE:tä tukeva prossu tuli vajaat 2 vuotta sitten (se fujitsun supertietokoneprossu), ja SVE2 korjasi SVEstä ne puutteet, joiden takia sitä ei heti otettu "kännykkäytimiin".
Muistioperaatio-ongelmia voi tulla melkein missä tahansa ohjelmassa ja niiden metsästäminen vasta hauskaa onkin.
Ei voi missä tahansa softassa ; Muistin konsistenttius voi olla ongelma ainoastaan monella säikeellä, saman säikeen sisällä käytettynä muistioperaatiot pysyvät aina tiukasti järjestyksessä ARMillakin.