Programmēšana

Kā paātrināt kodu, izmantojot CPU kešatmiņas

Procesora kešatmiņa samazina atmiņas latentumu, kad datiem piekļūst no galvenās sistēmas atmiņas. Izstrādātāji var un vajadzētu izmantot CPU kešatmiņas priekšrocības, lai uzlabotu lietojumprogrammas veiktspēju.

Kā darbojas CPU kešatmiņas

Mūsdienu centrālajiem procesoriem parasti ir trīs kešatmiņas līmeņi, apzīmēti ar L1, L2 un L3, kas atspoguļo to, kādā secībā CPU tos pārbauda. Procesoriem bieži ir datu kešatmiņa, instrukciju kešatmiņa (kodam) un vienota kešatmiņa (jebkuram). Piekļuve šīm kešatmiņām ir daudz ātrāka nekā piekļuve RAM: Parasti L1 kešatmiņa ir aptuveni 100 reizes ātrāka nekā RAM piekļuvei datiem, un L2 kešatmiņa ir 25 reizes ātrāka nekā RAM piekļuvei datiem.

Kad programmatūra darbojas un tai ir jāievada dati vai instrukcijas, vispirms tiek pārbaudīti CPU kešatmiņas, pēc tam lēnāka sistēmas operatīvā atmiņa un visbeidzot daudz lēnākie diskdziņi. Tāpēc vēlaties optimizēt kodu, lai vispirms meklētu to, kas, iespējams, būs nepieciešams no CPU kešatmiņas.

Jūsu kods nevar norādīt, kur atrodas datu instrukcijas un dati - to dara datora aparatūra, tāpēc dažus elementus nevar iespiest CPU kešatmiņā. Bet jūs varat optimizēt kodu, lai izgūtu L1, L2 vai L3 kešatmiņas lielumu sistēmā, izmantojot Windows pārvaldības instrumentāciju (WMI), lai optimizētu, kad lietojumprogramma piekļūst kešatmiņai un tādējādi arī tās veiktspējai.

Procesori nekad nepiekļūst kešatmiņas baitam pēc baita. Tā vietā viņi nolasa atmiņu kešatmiņas rindās, kas ir atmiņas gabali, kuru lielums parasti ir 32, 64 vai 128 baiti.

Šis kodu saraksts parāda, kā sistēmā var izgūt L2 vai L3 procesora kešatmiņas lielumu:

public static uint GetCPUCacheSize (string cacheType) {mēģiniet {izmantojot (ManagementObject managementObject = new ManagementObject ("Win32_Processor.DeviceID = 'CPU0'"))) {return (uint) (managementObject [cacheType]); }} noķert {atgriezt 0; }} static void Main (string [] args) {uint L2CacheSize = GetCPUCacheSize ("L2CacheSize"); uint L3CacheSize = GetCPUCacheSize ("L3CacheSize"); Console.WriteLine ("L2CacheSize:" + L2CacheSize.ToString ()); Console.WriteLine ("L3CacheSize:" + L3CacheSize.ToString ()); Konsole. Lasīt (); }

Korporācijai Microsoft ir papildu dokumentācija par Win32_Processor WMI klasi.

Programmēšana veiktspējai: koda piemērs

Ja kaudzē ir objekti, virs galvas nav atkritumu savākšanas. Ja izmantojat objektus, kuru pamatā ir kaudze, vienmēr ir jāmaksā par atkritumu savākšanu paaudzēs, lai savāktu vai pārvietotu objektus kaudzē vai saspiestu kaudzes atmiņu. Labs veids, kā izvairīties no atkritumu savākšanas, ir nodarbību vietā izmantot struktūras.

Kešatmiņas vislabāk darbojas, ja izmantojat secīgu datu struktūru, piemēram, masīvu. Secīga pasūtīšana ļauj centrālajam procesoram lasīt uz priekšu un arī spekulatīvi lasīt uz priekšu, gaidot to, kas, iespējams, tiks pieprasīts tālāk. Tādējādi algoritms, kas secīgi piekļūst atmiņai, vienmēr ir ātrs.

Ja piekļūstat atmiņai nejaušā secībā, CPU ir nepieciešamas jaunas kešatmiņas līnijas katru reizi, kad piekļūstat atmiņai. Tas samazina veiktspēju.

Šis koda fragments ievieš vienkāršu programmu, kas ilustrē struktūras izmantošanas priekšrocības klasē:

 struct TaisnstūrisSavienojums {public int width; public int augstums; } klase RectangleClass {public int width; public int augstums; }

Šis kods profilē struktūru masīva izmantošanu klašu masīvā. Ilustrācijas nolūkos abiem esmu izmantojis miljonu objektu, taču parasti jūsu lietojumprogrammā nav nepieciešams tik daudz objektu.

static void Main (string [] args) {const int size = 1000000; var structs = jauns RectangleStruct [izmērs]; var klases = jauns RectangleClass [izmērs]; var sw = jauns hronometrs (); sw.Sākt (); for (var i = 0; i <izmērs; ++ i) {struktūras [i] = jauns Taisnstūris (); struktūras [i] .platums = 0 struktūras [i] .augstums = 0; } var structTime = sw.ElapsedMilliseconds; sw.Reset (); sw.Sākt (); for (var i = 0; i <izmērs; ++ i) {klases [i] = jauns RectangleClass (); klases [i]. platums = 0; klases [i] .augstums = 0; } var classTime = sw.ElapsedMilliseconds; sw.Stop (); Console.WriteLine ("Laiks, kas aizņemts ar masīvu klasēm:" + classTime.ToString () + "milisekundes."); Console.WriteLine ("Laiks, ko prasa virkņu masīvs:" + structTime.ToString () + "milisekundes."); Konsole. Lasīt (); }

Programma ir vienkārša: tā izveido 1 miljonu objektu objektu un glabā tos masīvā. Tas arī rada 1 miljonu klases objektu un glabā tos citā masīvā. Īpašumu platumam un augstumam katrā instancē tiek piešķirta nulle.

Kā redzat, kešatmiņai draudzīgu struktūru izmantošana nodrošina milzīgu veiktspējas pieaugumu.

Noteikumi labākai CPU kešatmiņas lietošanai

Tātad, kā jūs rakstāt kodu, kas vislabāk izmanto CPU kešatmiņu? Diemžēl nav burvju formulas. Bet ir daži īkšķa noteikumi:

  • Izvairieties no tādu algoritmu un datu struktūru izmantošanas, kuriem piemīt neregulāri atmiņas piekļuves modeļi; tā vietā izmantojiet lineāras datu struktūras.
  • Izmantojiet mazākus datu tipus un sakārtojiet datus, lai nebūtu nevienas izlīdzināšanas cauruma.
  • Apsveriet piekļuves modeļus un izmantojiet lineāro datu struktūru priekšrocības.
  • Uzlabojiet telpisko lokalizāciju, kas maksimāli izmanto katru kešatmiņas līniju, kad tā ir kartēta ar kešatmiņu.
$config[zx-auto] not found$config[zx-overlay] not found