Ohjelmointi

Kuinka nopeuttaa koodia suorittimen välimuistien avulla

Suorittimen välimuisti vähentää muistiviivettä, kun tietoja käytetään pääjärjestelmän muistista. Kehittäjät voivat ja heidän pitäisi hyödyntää suorittimen välimuistia sovellusten suorituskyvyn parantamiseksi.

Kuinka suorittimen välimuistit toimivat

Nykyaikaisilla suorittimilla on tyypillisesti kolme välimuistitasoa, nimeltään L1, L2 ja L3, mikä heijastaa järjestystä, jossa CPU tarkistaa ne. Suorittimilla on usein datavälimuisti, käskyvälimuisti (koodia varten) ja yhtenäinen välimuisti (mihin tahansa). Näiden välimuistien käyttö on paljon nopeampaa kuin RAM-muistin käyttö: Tyypillisesti L1-välimuisti on noin 100 kertaa nopeampi kuin RAM tiedonsiirtoon ja L2-välimuisti on 25 kertaa nopeampi kuin RAM tiedonsiirtoon.

Kun ohjelmistosi suoritetaan ja sen on haettava tietoja tai ohjeita, tarkistetaan ensin suorittimen välimuistit, sitten hitaampi järjestelmän RAM ja lopuksi paljon hitaammat levyasemat. Siksi haluat optimoida koodisi etsimään mitä todennäköisesti tarvitaan ensin suorittimen välimuistista.

Koodisi ei voi määrittää, missä dataohjeet ja tiedot sijaitsevat - tietokonelaitteisto tekee niin - joten et voi pakottaa tiettyjä elementtejä suorittimen välimuistiin. Mutta voit optimoida koodisi hakemaan järjestelmän L1-, L2- tai L3-välimuistin koon Windows Management Instrumentation (WMI) -toiminnon avulla optimoidaksesi, kun sovelluksesi käyttää välimuistia ja siten sen suorituskykyä.

Suorittimet eivät koskaan käytä välimuistin tavua tavuina. Sen sijaan he lukevat muistin välimuistiriveillä, jotka ovat yleensä muistinpaloja kooltaan 32, 64 tai 128 tavua.

Seuraava koodiluettelo kuvaa, kuinka voit hakea L2- tai L3-suorittimen välimuistin koon järjestelmässäsi:

public static uint GetCPUCacheSize (string cacheType) {yritä {käyttää (ManagementObject managementObject = uusi ManagementObject ("Win32_Processor.DeviceID = 'CPU0'"))) {return (uint) (managementObject [cacheType]); }} saalis {paluu 0; }} staattinen void Main (merkkijono [] args) {uint L2CacheSize = GetCPUCacheSize ("L2CacheSize"); uint L3CacheSize = GetCPUCacheSize ("L3CacheSize"); Console.WriteLine ("L2CacheSize:" + L2CacheSize.ToString ()); Console.WriteLine ("L3CacheSize:" + L3CacheSize.ToString ()); Konsoli.Lue (); }

Microsoftilla on lisätietoja Win32_Processor WMI -luokasta.

Suorituskyvyn ohjelmointi: Esimerkkikoodi

Kun pinossa on esineitä, roskakorin yläpuolella ei ole mitään. Jos käytät kasapohjaisia ​​objekteja, sukupolvien roskakoriin liittyy aina kustannuksia esineiden keräämisestä tai siirtämisestä kasaan tai kasan muistin tiivistämisestä. Hyvä tapa välttää roskien keräystä on käyttää rakenteita luokkien sijaan.

Välimuistit toimivat parhaiten, jos käytät peräkkäistä tietorakennetta, kuten taulukkoa. Peräkkäisen tilauksen avulla keskusyksikkö voi lukea eteenpäin ja lukea myös spekulatiivisesti ennakoiden, mitä todennäköisesti seuraavaksi pyydetään. Siten algoritmi, joka käyttää muistia peräkkäin, on aina nopea.

Jos käytät muistia satunnaisessa järjestyksessä, CPU tarvitsee uusia välimuistirivejä joka kerta, kun käytät muistia. Se heikentää suorituskykyä.

Seuraava koodinpätkä toteuttaa yksinkertaisen ohjelman, joka kuvaa strukturin käytön etuja luokassa:

 struct RectangleStruct {julkinen sis. leveys; julkisen sisäkorkeus; } luokka RectangleClass {julkinen sis. leveys; julkisen sisäkorkeus; }

Seuraava koodi profiloi ryhmärakenteiden käytön suorituskykyä luokkaryhmää vastaan. Havainnollistamiseksi olen käyttänyt miljoonaa kohdetta molempiin, mutta yleensä et tarvitse niin monta kohdetta sovelluksessasi.

staattinen void Main (merkkijono [] args) {const int koko = 1000000; var structs = uusi RectangleStruct [koko]; var-luokat = new RectangleClass [koko]; var sw = uusi sekuntikello (); sw.Start (); for (var i = 0; i <koko; ++ i) {rakentaa [i] = uusi RectangleStruct (); rakenteet [i] .leveys = 0 rakenteet [i] .korkeus = 0; } var structTime = sw.ElapsedMillisekuntia; sw.Reset (); sw.Start (); for (var i = 0; i <koko; ++ i) {luokat [i] = uusi RectangleClass (); luokat [i]. leveys = 0; luokat [i] .korkeus = 0; } var classTime = sw.ElapsedMillisekuntia; sw.Stop (); Console.WriteLine ("Aika luokkaryhmillä:" + classTime.ToString () + "millisekuntia."); Console.WriteLine ("Aika joukkoilla rakenteilla:" + structTime.ToString () + "millisekuntia."); Konsoli.Lue (); }

Ohjelma on yksinkertainen: Se luo miljoonan objektin rakennetta ja tallentaa ne matriisiin. Se luo myös miljoonan luokan objektia ja tallentaa ne toiseen ryhmään. Ominaisuuksien leveydelle ja korkeudelle annetaan nolla-arvo kussakin esiintymässä.

Kuten näette, välimuistiystävällisten rakenteiden käyttö tarjoaa valtavan suorituskyvyn.

Nyrkkisäännöt paremmalle suorittimen välimuistin käytölle

Joten miten kirjoitat koodin, joka käyttää parhaiten suorittimen välimuistia? Valitettavasti ei ole maagista kaavaa. Mutta on joitain nyrkkisääntöjä:

  • Vältä sellaisten algoritmien ja tietorakenteiden käyttöä, joilla on epäsäännöllisiä muistin käyttömalleja; käytä sen sijaan lineaarisia tietorakenteita.
  • Käytä pienempiä tietotyyppejä ja järjestele tiedot siten, ettei kohdistusreikiä ole.
  • Harkitse pääsymalleja ja hyödynnä lineaarisia tietorakenteita.
  • Paranna paikkatietoa, joka käyttää kutakin välimuistiriviä mahdollisimman paljon, kun se on yhdistetty välimuistiin.
$config[zx-auto] not found$config[zx-overlay] not found