Programiranje

Kako pospešiti kodo s pomočjo predpomnilnikov CPU

Predpomnilnik CPU zmanjša zakasnitev pomnilnika, ko do podatkov dostopate iz glavnega sistemskega pomnilnika. Razvijalci lahko in bi morali izkoristiti predpomnilnik CPU za izboljšanje zmogljivosti aplikacije.

Kako delujejo predpomnilniki CPU

Sodobni CPU imajo običajno tri ravni predpomnilnika, označene z L1, L2 in L3, kar odraža vrstni red, v katerem jih CPU preverja. CPU imajo pogosto podatkovni predpomnilnik, predpomnilnik navodil (za kodo) in poenoten predpomnilnik (za kar koli). Dostop do teh predpomnilnikov je veliko hitrejši od dostopa do RAM-a: Običajno je predpomnilnik L1 približno 100-krat hitrejši od RAM-a za dostop do podatkov, predpomnilnik L2 pa 25-krat hitrejši od RAM-a za dostop do podatkov.

Ko se programska oprema zažene in mora vnesti podatke ali navodila, se najprej preverijo predpomnilniki procesorja, nato počasnejši sistemski RAM in na koncu veliko počasnejši diskovni pogoni. Zato želite optimizirati kodo, da najprej iz predpomnilnika CPU poiščete tisto, kar je verjetno potrebno.

Vaša koda ne more določiti, kje so podatkovna navodila in podatki - računalniška strojna oprema to počne -, zato nekaterih elementov ne morete vsiliti v predpomnilnik CPU. Lahko pa optimizirate kodo, da pridobite velikost predpomnilnika L1, L2 ali L3 v vašem sistemu z uporabo Windows Management Instrumentation (WMI), da optimizirate, kdaj vaša aplikacija dostopa do predpomnilnika in s tem do njegove učinkovitosti.

CPU nikoli ne dostopajo do bajta po bajtu. Namesto tega berejo pomnilnik v predpomnilniških vrsticah, ki so koščki pomnilnika, ki so običajno veliki 32, 64 ali 128 bajtov.

Naslednji seznam kod ponazarja, kako lahko v svojem sistemu pridobite velikost predpomnilnika procesorja L2 ali L3:

javni statični uint GetCPUCacheSize (niz cacheType) {poskusite {z uporabo (ManagementObject managementObject = new ManagementObject ("Win32_Processor.DeviceID = 'CPU0'")) {return (uint) (managementObject [cacheType]); }} ulov {vrnitev 0; }} static void Main (string [] args) {uint L2CacheSize = GetCPUCacheSize ("L2CacheSize"); uint L3CacheSize = GetCPUCacheSize ("L3CacheSize"); Console.WriteLine ("L2CacheSize:" + L2CacheSize.ToString ()); Console.WriteLine ("L3CacheSize:" + L3CacheSize.ToString ()); Console.Read (); }

Microsoft ima dodatno dokumentacijo o razredu Win32_Processor WMI.

Programiranje za izvedbo: Primer kode

Ko imate predmete v svežnju, ni nobenega odvoza smeti. Če uporabljate predmete, ki temeljijo na kopici, je z zbiranjem ali premikanjem predmetov na kopici ali stiskanjem pomnilnika kopice vedno treba plačati generacijsko zbiranje smeti. Dober način, da se izognemo režijskim stroškom za zbiranje smeti, je uporaba struktur namesto razredov.

Predpomnilniki najbolje delujejo, če uporabljate zaporedno strukturo podatkov, na primer matriko. Zaporedni vrstni red omogoča CPU, da lahko bere naprej in tudi špekulativno bere v pričakovanju, kaj bo verjetno zahtevano v nadaljevanju. Tako je algoritem, ki zaporedno dostopa do pomnilnika, vedno hiter.

Če dostopate do pomnilnika v naključnem vrstnem redu, CPU potrebuje nove vrstice predpomnilnika vsakič, ko dostopate do pomnilnika. To zmanjšuje zmogljivost.

Naslednji delček kode izvaja preprost program, ki ponazarja prednosti uporabe strukture nad razredom:

 struct RectangleStruct {širina javnega int; višina javnega int; } class RectangleClass {public int širina; višina javnega int; }

Naslednja koda profilira uspešnost uporabe niza struktur proti nizu razredov. Za ponazoritev sem za oba uporabil milijon predmetov, vendar običajno v vaši aplikaciji ne potrebujete toliko predmetov.

statična praznina Main (string [] args) {const int size = 1000000; var structs = nov RectangleStruct [velikost]; razredi var = nov RectangleClass [velikost]; var sw = nova štoparica (); sw.Start (); for (var i = 0; i <size; ++ i) {structs [i] = new RectangleStruct (); structs [i] .breadth = 0 structs [i] .height = 0; } var structTime = sw.ElapsedMilliseconds; sw.Reset (); sw.Start (); for (var i = 0; i <size; ++ i) {classes [i] = new RectangleClass (); razredi [i] .breadth = 0; razredi [i] .height = 0; } var classTime = sw.ElapsedMilliseconds; sw.Stop (); Console.WriteLine ("Čas, ki ga traja niz razredov:" + classTime.ToString () + "milisekunde."); Console.WriteLine ("Čas, ki ga vzame niz struktur:" + structTime.ToString () + "milisekunde."); Console.Read (); }

Program je preprost: ustvari milijon predmetov struktur in jih shrani v matriko. Ustvari tudi milijon predmetov razreda in jih shrani v drugo polje. Širina in višina lastnosti imata za vsak primerek vrednost nič.

Kot lahko vidite, uporaba predpomnilnikom prijaznih struktur prinaša velik dobiček v zmogljivosti.

Pravila za boljšo uporabo predpomnilnika procesorja

Torej, kako napišem kodo, ki najbolje uporablja CPU predpomnilnik? Čarobne formule žal ni. Obstaja pa nekaj pravil:

  • Izogibajte se uporabi algoritmov in podatkovnih struktur, ki kažejo nepravilne vzorce dostopa do pomnilnika; namesto tega uporabite linearne podatkovne strukture.
  • Uporabite manjše vrste podatkov in razporedite podatke, tako da ne bo nobenih luknj za poravnavo.
  • Upoštevajte vzorce dostopa in izkoristite linearne podatkovne strukture.
  • Izboljšajte prostorsko lokacijo, ki vsako vrstico predpomnilnika v največji meri uporabi, ko je preslikana v predpomnilnik.
$config[zx-auto] not found$config[zx-overlay] not found