Zig kompilatora izstrādātājs Matthew Lugg publicēja profilēšanas datus par inkrementālo pārbūvi. Grafiskā lietotne Fizzy no nulles kompilējas apmēram piecās sekundēs, bet pēc vienas funkcijas rediģēšanas pārbūve prasa 50 līdz 70 milisekundes. Viens no mērījumiem rāda 37 milisekundes. Sešas no tām ir īstais kompilēšanas darbs, bet 31 aiziet atsauču grafa apstaigāšanai.
Atsauču grafs nosaka, kuras deklarācijas programmā tiek izmantotas. Ja mainīta viena rinda funkcijas ķermenī, grafs paliek tāds pats, tomēr Zig to pārrēķina no nulles katrā atjauninājumā. Lugg to nosauc par galveno atlikušo optimizācijas vietu.
katrs fails apstrādājams atsevišķi
Kompilācija sākas ar faila nolasīšanu, parsēšanu par sintakses koku un pārveidošanu par ZIR (Zig Intermediate Representation). Šo posmu Zig jau vairākus gadus dara paralēli un kešo pa failiem, jo viena faila rezultāts ir tīra funkcija no šī faila satura. Kopīga stāvokļa starp failiem nav.
ZIR glabājas plakanos masīvos, tāpēc to var ierakstīt diskā vai nolasīt ar vienu sistēmas izsaukumu. Visa Zig kompilatora pirmkoda parsēšana un ZIR ģenerēšana prasa apmēram 920 milisekundes. Inkrementālā solī no jauna jāapstrādā tikai tie faili, kuros kaut kas mainījies.
ko kompilators uzskata par vienību
Semantiskā analīze ir sarežģītākā inkrementālā daļa. Tā strādā ar vienībām, kas mazākas par failu. Zig izšķir četras:
- konteinera līmeņa deklarācijas tips;
constdeklarācijas vērtība;- struktūras vai apvienojuma izkārtojums, tas ir, izmērs un izlīdzinājums;
- izpildlaika funkcijas ķermenis.
Katrai vienībai kompilators pieraksta divas lietas: no kurām citām vienībām tā atkarīga un kuru pirmkoda apgabalu jaucējsummas tā nolasīja. Kad kāda jaucējsumma mainās, atkarīgās vienības tiek atzīmētas atkārtotai analīzei.
Funkciju ķermeņiem ienākošo atkarību nav. Neviena cita vienība nevar būt atkarīga no tā, kas notiek funkcijas iekšienē, tāpēc funkcijas pārrēķins nekad neizplatās tālāk pa grafu. Tas ir arī iemesls, kāpēc parasts rediģējums parasti aizķer vienu vienību.
Martā Lugg pārstrādāja tipu izšķiršanu un kompilatora iekšējo atkarību grafu no cikliska pārveidoja par aciklisku. Zig izstrādes žurnālā tas aprakstīts kā labojums pārmērīgai analīzei: atjauninājumi darīja darbu, kas nebija vajadzīgs. Par pašreizējo stāvokli Lugg raksta tieši:
Inkrementālā kompilācija vēl nav stabila. Iespējami kļūdu paziņojumi par kodu, kurā kļūdu nav, kā arī nepareizi sakompilēts kods.
Aprīlī žurnālā parādījās vēl viens ieraksts: inkrementālā kompilācija sāka strādāt arī ar LLVM aizmugursistēmu. Ieguvums ir ātrāka kļūdu atgriešana tajos brīžos, kad kods vēl nemaz nekompilējas. Semantiskā analīze notiek inkrementāli neatkarīgi no tā, kas ģenerē mašīnkodu, tāpēc kļūdu sarakstu var atgriezt vēl pirms koda ģenerēšanas. Ar LLVM aizmugursistēmu inkrementāls paliek tikai analīzes posms. Mašīnkodu LLVM joprojām ģenerē no jauna.
linkeris raksta tieši izvadfailā
Vispārīgie inkrementālie linkeri salīdzina vecos un jaunos objektfailus. Tas ir dārgi un tāpēc reti dod solītos ieguvumus.
Zig jaunais ELF linkeris salīdzināšanu nedara. Izvadfails tiek attēlots atmiņā caur abstrakciju MappedFile. Faila apgabalus linkeris pārvalda kā mezglus. Kad funkcijas mašīnkods mainās, mezglam tiek piešķirta jauna vieta vai mainīts izmērs. Adresu piešķiršanu un relokāciju uzlikšanu linkeris atliek līdz brīdim, kad citu darbu vairs nav.
Mezgli aug eksponenciāli, tāpēc sekcijas jāpārvieto reti. 30. maijā Lugg izstrādes žurnālā rakstīja, ka jaunais linkeris jau spēj uzbūvēt pašu Zig kompilatoru ar ieslēgtām LLVM un LLD bibliotēkām. Uz x86_64 Linux inkrementāla pārbūve strādā arī tad, kad klāt tiek linkētas ārējas bibliotēkas vai C pirmkods, bez papildu izmaksām.
kur paliek 31 milisekunde
Tracy profilētāja izvads vienam 37 milisekunžu atjauninājumam sadalās šādi:
computeAliveFiles, importu grafa apstaigāšana: ap 1 ms;updateZirRefs, veco un jauno ZIR atsauču sasaiste: ap 1 ms;- semantiskā analīze: 1,2 ms;
- koda ģenerēšana: 240 mikrosekundes;
- linkēšana: 170 mikrosekundes;
resolveReferencesInner, atsauču grafa apstaigāšana: 31 ms.
Piecas no sešām pozīcijām kopā ir aptuveni 3,6 milisekundes. Visu pārējo apēd viens posms, kas atbild uz jautājumu, kuras deklarācijas programmā vispār tiek izmantotas. Šo atbildi vajag kļūdu paziņojumiem un koda ģenerēšanai. Pašlaik to rēķina no nulles arī tad, kad grafs nav mainījies.
kas vajadzīgs, lai izmēģinātu
Inkrementālais režīms strādā uz x86_64 Linux. Pārējās aizmugursistēmas tam vēl nav pietiekami nobriedušas. Automātiskā kešošana nav ieviesta, tāpēc karogs jāpadod pašam:
zig build --watch -fincremental
Var ieslēgt arī tikai vienam izpildfailam: pievieno build.zig opciju, uzstādi exe.incremental = true un palaid zig build -Dincremental.
Versijā 0.16.0 pilnu ainu neredzēs, jo tajā vēl nav vajadzīgo linkera funkciju. Šobrīd vajadzīgs kompilators no master zara. Laidiens 0.16.0 iznāca aprīlī pēc astoņiem mēnešiem darba: 1183 revīzijas no 244 dalībniekiem. Pašuzturētā x86_64 aizmugursistēma tajā kompilē apmēram piecas reizes ātrāk par LLVM. Inkrementālais režīms ir nākamais ātruma solis, kad tas kļūs pietiekami stabils, lai to ieslēgtu pēc noklusējuma.
Andrew Kelley 30. jūnijā izstrādes žurnālā rakstīja, ka jūlijā viņam ir divas konferences, tāpēc atlikušos 0.17.0 darbus viņš nepabeigs ātrāk par augusta sākumu.
Avoti
- Zig’s Incremental Compilation Internals, mlugg.co.uk
- Zig Devlog 2026, ziglang.org
- 0.16.0 Release Notes, ziglang.org
Komentāri
Šim rakstam vēl nav komentāru. Esi pirmais, kurš dalās ar savu viedokli.