Programavimas

Kaip pagreitinti kodą naudojant procesoriaus talpyklas

Centrinio procesoriaus talpykla sumažina atminties vėlavimą, kai duomenys pasiekiami iš pagrindinės sistemos atminties. Kūrėjai gali ir turėtų pasinaudoti procesoriaus talpykla, kad pagerintų programų našumą.

Kaip veikia procesoriaus talpyklos

Šiuolaikiniai procesoriai paprastai turi tris talpyklos lygius, pažymėtus L1, L2 ir L3, o tai rodo tvarką, kuria procesorius juos tikrina. Centriniai procesoriai dažnai turi duomenų talpyklą, instrukcijų talpyklą (kodui) ir vieningą talpyklą (bet kam). Prieiga prie šių talpyklų yra daug greitesnė nei prieiga prie RAM: Paprastai L1 talpykla yra maždaug 100 kartų greitesnė nei RAM prieigai prie duomenų, o L2 talpykla yra 25 kartus greitesnė nei RAM, norint pasiekti duomenis.

Kai jūsų programinė įranga veikia ir jai reikia gauti duomenų ar instrukcijų, pirmiausia patikrinamos procesoriaus talpyklos, tada lėtesnė sistemos RAM ir galiausiai daug lėtesni diskų įrenginiai. Štai kodėl norite optimizuoti kodą, kad pirmiausia ieškotumėte to, ko greičiausiai reikės iš procesoriaus talpyklos.

Jūsų kodas negali nurodyti, kur yra duomenų instrukcijos ir duomenys - tai daro kompiuterio aparatinė įranga, todėl negalite priversti tam tikrų elementų į procesoriaus talpyklą. Tačiau galite optimizuoti savo kodą, kad gautumėte L1, L2 arba L3 talpyklos dydį sistemoje, naudodami „Windows Management Instrumentation“ (WMI), kad optimizuotumėte, kai jūsų programa pasiekia talpyklą, taigi ir jos veikimą.

Centriniai procesoriai niekada nepasiekia talpyklos baitų. Vietoj to, jie skaito atmintį talpyklos eilutėse, kurios yra atminties dalys, kurių dydis paprastai yra 32, 64 arba 128 baitai.

Šis kodų sąrašas parodo, kaip galite gauti L2 arba L3 procesoriaus talpyklos dydį savo sistemoje:

public static uint GetCPUCacheSize (string cacheType) {try {using {ManagementObject managementObject = new ManagementObject ("Win32_Processor.DeviceID = 'CPU0'")) {return (uint) (managementObject [cacheType]); }} gaudyti {grąžinti 0; }} static void Main (string [] args) {uint L2CacheSize = GetCPUCacheSize ("L2CacheSize"); uint L3CacheSize = GetCPUCacheSize ("L3CacheSize"); Console.WriteLine ("L2CacheSize:" + L2CacheSize.ToString ()); Console.WriteLine ("L3CacheSize:" + L3CacheSize.ToString ()); Pultas.Skaitykite (); }

„Microsoft“ turi papildomų dokumentų apie „Win32_Processor“ WMI klasę.

Programavimas našumui: kodo pavyzdys

Kai kaminoje yra objektų, virš galvos nėra šiukšlių surinkimo. Jei naudojate su kaupu susijusius objektus, visada reikia mokėti už kartų šiukšlių surinkimą, norint surinkti ar perkelti daiktus į kaupą arba sutankinti kaupo atmintį. Geras būdas išvengti šiukšlių surinkimo pridėtinių yra naudoti struktūras, o ne klases.

Talpyklos geriausiai veikia, jei naudojate nuoseklią duomenų struktūrą, pvz., Masyvą. Nuoseklus užsakymas leidžia procesoriui skaityti į priekį ir spekuliaciškai skaityti į priekį, tikintis, ko greičiausiai bus prašoma toliau. Taigi algoritmas, kuris nuosekliai pasiekia atmintį, visada yra greitas.

Jei atmintį pasiekiate atsitiktine tvarka, kiekvieną kartą, kai naudojatės atmintimi, procesoriui reikia naujų talpyklos eilučių. Tai sumažina našumą.

Šis kodo fragmentas įgyvendina paprastą programą, iliustruojančią struktūros naudojimo pranašumus klasėje:

 struct RectangleStruct {public int width; public int aukštis; } klasė RectangleClass {public int width; public int aukštis; }

Šis kodas apibūdina struktūrų masyvo naudojimą prieš klasių masyvą. Iliustracijos tikslais naudojau milijoną objektų abiem, bet paprastai jūsų programoje nereikia tiek daug objektų.

static void Main (string [] args) {const int dydis = 1000000; var structs = naujas RectangleStruct [dydis]; var klasės = nauja RectangleClass [dydis]; var sw = naujas chronometras (); sw.Pradėti (); for (var i = 0; i <dydis; ++ i) {struktūra [i] = naujas RectangleStruct (); struktūros [i]. plotis = 0 struktūros [i]. aukštis = 0; } var structTime = sw.ElapsedMilliseconds; sw.Reset (); sw.Pradėti (); for (var i = 0; i <dydis; ++ i) {klasės [i] = nauja RectangleClass (); klasės [i]. plotis = 0; klasės [i] .aukštis = 0; } var classTime = sw.ElapsedMilliseconds; sw.Stop (); Console.WriteLine ("Laikas, kurį užima klasių masyvas:" + classTime.ToString () + "milisekundės."); Console.WriteLine ("Laikas, kurį užtrunka struktūrų masyvas:" + structTime.ToString () + "milisekundės."); Pultas.Skaitykite (); }

Programa yra paprasta: sukuria 1 milijoną objektų objektų ir saugo juos masyve. Tai taip pat sukuria 1 milijoną klasės objektų ir juos saugo kitame masyve. Savybių plotis ir aukštis kiekvienam egzemplioriui priskiriami nuliui.

Kaip matote, naudojimas talpyklai tinkamomis struktūromis suteikia didžiulį našumą.

Geresnės procesoriaus talpyklos naudojimo taisyklės

Taigi, kaip parašyti kodą, kuris geriausiai naudoja procesoriaus talpyklą? Deja, stebuklingos formulės nėra. Tačiau yra keletas nykščio taisyklių:

  • Venkite naudoti algoritmus ir duomenų struktūras, kurios rodo netaisyklingą atminties prieigą; vietoj to naudokite linijines duomenų struktūras.
  • Naudokite mažesnius duomenų tipus ir tvarkykite duomenis, kad neliktų lygiavimo skylių.
  • Apsvarstykite prieigos modelius ir pasinaudokite linijinėmis duomenų struktūromis.
  • Pagerinkite erdvinį lokalumą, kuris maksimaliai naudoja kiekvieną talpyklos eilutę, kai tik ji bus susieta su talpykla.