DynamickýPřekladPrakticky

Z Denik

(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
(II. Jak fungují moderní překladače?)
(X. Štěpán Šindelář: Volání nativních knihoven z Javy pomocí Truffle NFI)
 
(Není zobrazeno 72 mezilehlých verzí.)
Řádka 1: Řádka 1:
-
Seminář na [[apidesign:MatFyzu|MatFyz]] pro letní semestr 2019, který pokračuje na jaře 2021.
+
Seminář [https://d3s.mff.cuni.cz/teaching/nswi176/ NSWI176] na [[apidesign:MatFyzu|MatFyz]]u v letním semestru 2019, který pokračoval i na jaře 2021, kdy bylo jeho [https://stream.cuni.cz/cs/Detail/0/12041 čtrnáct dílů zaznamenáno] do více než dvaceti hodin záznamu.
-
== Dynamický Překlad Prakticky ==
 
-
Jaký je nejrychlejší programovací jazyk? Může být [[apidesign:JavaScript|JavaScript]] rychlejší než [[apidesign:C|Céčko]]? Existuje jednoduchý způsob, jak si napsat jazyk, který bude opravdu rychlý? Musíme opravdu psát všechny knihovny znovu a znovu? Jak se implementuje debugger? A jak profiler? Kolik to dá práce? To jsou otázky, na které v průběhu semináře budeme hledat a nalezneme odpovědi.
 
-
Budeme používat [[GraalVM]], což je nejrychlejší virtuální stroj, který shodou okolností pomáhá vyvíjet tým z pražské pobočky [[apidesign:OracleLabs|OracleLabs]]. Díky tomu to bude seminář praktický, přibližující nejnovější trendy ve vývoji virtuálních strojů. Žádná otázka nebude tabu - o [[GraalVM]] víme úplně vše!
+
=== I. Představujeme nejrychlejší univerzální virtuální stroj ===
-
Cílem bude ukázat si na výhody a zádrhele dynamického překladu. Pochopit, co překladač ve skutečnosti dělá a naučit se dorozumět se s ním - tedy programovat tak, abyste z dynamického překladu v [[GraalVM]] získali co nejvíce. Máte-li vlastní programovací jazyk, vezměte si jej s sebou - uděláme jej rychlejší!
+
[https://stream.cuni.cz/cs/Detail/0/12041 Záznam úvodní přednášky]. Začínáme historií [[NetBeans]], protože se k přednášce na [[MatFyz]]u určitě hodí. Nemůže chybět zmínka o návrhu [[API]] a mé knížce [http://practical.apidesign.org Practical API Design], aby bylo zřejmé, proč se tomuto kurzu říká ''Practical Dynamic Compilation''! Následuje takové to tradiční povídání o tom, co [[GraalVM]] umí a jak je snadné a jednoduché to nainstalovat (pomocí utilitky '''gu'''), použít a jak strašně rychle pak lze počítat [https://github.com/jtulach/sieve Eratosthénovo síto] v libovolném jazyce. Není to nic převratného, ale pokud jste to ještě někdo neviděl, tak je to vhodná upoutávka k záznamům dalších lekcí.
-
A pokud to někoho bude opravdu bavit, tak může pokračovat v létě při studijní stáži v [[apidesign:OracleLabs|OracleLabs]] v Jinonicích.
+
Je naše [[GraalVM]] implementace '''Ruby''' 10-krát rychlejší než jakákoli jiná? Jak dlouho může trvat vypsat všechna prvočísla? Co je vstupem a co je výstupem [[GraalVM|Graal]] překladače? Jakým nástrojem můžeme zkoumat, co [[GraalVM|Graal]] překladač vlastně uvnitř dělá? Jak napsat vlastní jazyk? Jak vložit implementaci existujícího dynamického jazyka do vlastního Java programu? Dá se to potom také ladit? V [[NetBeans]]? Ve Chrome Dev Tools? Má cenu psát interpretr Céčka?
 +
=== II. Jak fungují moderní překladače? ===
-
== Osnova přednášek ==
+
V [https://stream.cuni.cz/cs/Detail/12042/12041 záznamu druhé přednášky] si nejprve dokončíme úvod z minula a povíme si, jak se ''zbavit Javovské virtuální mašiny''! Dynamický překlad je skvělý, ale vyžaduje spoustu metadat. Naštěstí můžeme [[GraalVM]] využít na překlad ''Java kódu'' do '''EXáče'''! To je důležitý střípek v tom, jak [[GraalVM]] ekosystém funguje. Ale protože nás primárně bude zajímat překlad dynamických jazyků, tak si hned také představíme základní trik, který z dynamických jazyků dělá něco, z čeho lze vygenerovat efektivní strojový kód. Pořádně to prodiskutujeme a pak...
-
=== I. Představujeme nejrychlejší univerzální virtuální stroj ===
+
Od 35-té minuty následuje skutečné povídání o moderních překladačích: Jak vlastně překládat Javu, Céčko a jiné staticky typované jazyky? Pro osvěžení, co to vlastně  překladače jsou a jak fungují, nám výborně poslouží [https://chrisseaton.com/truffleruby/jokerconf17/ přednáška kolegy Chrise Seatona]. Opravdu je lepší psát překladač v C++ než v Javě? Chcete psát překladač a nebo vás baví psát vlastní garbage collector!? Nevynalézejte znovu kolo a raději si vyklonujte [https://github.com/oracle/graal/ graal repozitoř]. Vaše oblíbené IDE (ať [http://netbeans.org NetBeans] nebo [https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm-pack VSCode] či [https://docs.oracle.com/en/graalvm/enterprise/21/docs/tools/igv/ Ideal Graph Visualizer] a nebo i jiné) ty zdrojáky bez problémů otevře. Pak už můžete přidávat breakpointy do zdrojáků překladače, spouštět si vaše programy a koukat, jak se překládají. Můžete si i změnit sémantiku překladu, vypsat si ladící hlášky či něco podobného. Jak vaše aplikace, tak váš překladač jsou v Javě a ve vašem vývojovém prostředí se chovají úplně stejně. Avšak ne jen laděním je živ překládající inženýr! My milujeme grafy z překladače, které radostně zkoumáme v [https://docs.oracle.com/en/graalvm/enterprise/21/docs/tools/igv/ IGV]. Stahujte, zkoumejte jednotlivé fáze překladu a bezostyšně přeskakujte mezi IR grafy různých fází, vašimi zdrojáky, zdrojáky překladače. Bez [https://docs.oracle.com/en/graalvm/enterprise/21/docs/tools/igv/ IGV] ani ránu!
-
[https://stream.cuni.cz/cs/Detail/0/12041 Záznam úvodní přednášky]. Začínáme historií [[NetBeans]], protože se k přednášce na [[MatFyz]]u určitě hodí. Nemůže chybět zmínka o návrhu [[API]] a mé knížce [http://practical.apidesign.org Practical API Design], aby bylo zřejmé, proč se tomuto kurzu říká ''Practical Dynamic Compilation''! Následuje takové to tradiční povídání o tom, co [[GraalVM]] umí a jak je snadné a jednoduché to nainstalovat (pomocí utilitky '''gu'''), použít a jak strašně rychle pak lze počítat [https://github.com/jtulach/sieve Eratesthénovo síto] v libovolném jazyce. Není to nic převratného, ale pokud jste to ještě někdo neviděl, tak je to vhodná upoutávka k záznamům dalších lekcí.
+
=== III. Jak překládají moderní překladače? ===
-
Je naše [[GraalVM]] implementace '''Ruby''' 10-krát rychlejší než jakákoli jiná? Jak dlouho může trvat vypsat všechna prvočísla? Co je vstupem a co je výstupem [[GraalVM|Graal]] překladače? Jakým nástrojem můžeme zkoumat, co [[GraalVM|Graal]] překladač vlastně uvnitř dělá? Jak napsat vlastní jazyk? Jak vložit implementaci existujícího dynamického jazyka do vlastního Java programu? Dá se to potom také ladit? V [[NetBeans]]? Ve Chrome Dev Tools? Má cenu psát interpretr Céčka?
+
[https://stream.cuni.cz/cs/detail/12199/12041 Třetí díl záznamu] zahajuje pět minut technických problémů, ale pak již následuje vytvoření Maven projektu v [https://docs.oracle.com/en/graalvm/enterprise/21/docs/tools/igv/ IGV] a jeho zkoumání ze všech možných úhlů. Použijte ''-Dgraal.Dump=:1'' a ''-Dgraal.PrintGraph=Network'' a pojďme se podívat na grafy překladu. S gettery, které se inlinují či neinlinují. Prozkoumejme, jak vypadá IR graf výpočtu průměru. Se smyčkou či bez ní. Jak funguje bytecode parser? Jak se generuje assembler? Jak si můžeme vypsat strojový kód z příkazové řádky? Třída '''Phase''' a její implementace poskytují různé optimalizace: Kanonikalizace uzlů. Znovupoužití hodnot. Eliminace zámků. Jak může debugger spolupracovat s [https://docs.oracle.com/en/graalvm/enterprise/21/docs/tools/igv/ IGV]? Přes '''graph.getDebug().forceDump(...)'''. Tomáš Zezula nám představí GraphBuilderPluginy a dostane domácí úkol...
-
=== II. Jak fungují moderní překladače? ===
+
=== IV. Promluvte si s překladačem: Direktivy ===
 +
 
 +
[https://stream.cuni.cz/cs/detail/12485/12041 Čtvrtá část záznamu] zkoumá k čemu všemu lze [[GraalVM|Graal překladač]] vlastně použít. Začínáme ukázkou Tomáše Zezuly používající '''GraphBuilderPlugin''' k nahrazení '''SecurityManager'''u no-op konstantou (do 12-té minuty). Takže místo [https://openjdk.java.net/jeps/411 JEP-411], který se snaží '''SecurityManager''' smazat, bychom jej tam mohli nechat a jen eliminovat jakoukoli zátěž, která je s ním spojená, nepoužívá-li se. Zajímavé, že?
 +
 
 +
Propagace konstant je důležitá optimalizace, kterou budeme hojně používat při práci s [https://github.com/JaroslavTulach/talk2compiler Talk 2 Compiler] demo projektem. A můžeme začít s Trufflem. Co je to '''RootNode.execute'''? Co je to '''CallTarget'''? To je způsob jak z Java módu běhu a překladu přeskočit do "Truffle překladu". Jak se liší Truffle IGV graf od klasického IGV grafu z Javy? Má '''final''' vliv v Javě? A má jej při Truffle překladu? Překlad pro "instanci" RootNodu. Lze používat '''CompilationFinal''' a měnit hodnotu takového políčka - natrénujte si svůj kód na hodnoty, které skutečně používáte. Dejte si ale pozor, ať ten kód natrénujete správně! Kdykoli měníte '''@CompilationFinal''' pole, tak nezapomeňte zavolat '''transferToInterpreterAndInvalidate()'''!  Použijte '''TruffleBoundary''' na vyskočení z "Truffle módu" do "normální" Javy. Tím zabráníte inlinování příliš velkého množství kódu z mnoha metod.
 +
 
 +
=== V. Promluvte si s překladačem: Profily, bioinformatika a předpoklady ===
 +
 
 +
Opakování je matka moudrosti a tudíž [https://stream.cuni.cz/cs/Detail/12569/12041 pátá část záznamu] stručně shrne specifika ''Truffle překladu'' a pak pokračuje ve vysvětlování různých dynamických optimalizačních triků. Spekulujme na to, že se nějaký parametr nemění. Trochu program natrénujeme a jen sledujeme, jak se vše zoptimalizuje. A abychom nemuseli pořád psát to samé, tak použijeme profily: '''ConditionProfile''' či '''ValueProfile''' či '''BranchProfile''' či '''createCountingProfile()'''.
 +
 
 +
Ač tyto triky používáme primárně pro psaní interpretrů, tak jsou obecně užitečné. Pojďme se tedy mrknout, jak si promluvit s překladačem a zrychlit nějakou úlohu z ''bioinformatiky''. Vezmeme si '''BooleanNetwork''' a zkusme ji nějak rychle prohledat. Když porovnáme klasickou (HotSpot) Javu a kód přeložený v Truffle módu, tak Truffle je o 20% rychlejší. Stačí použít direktivu '''@ExplodeLoop'''. Máte-li velké datové struktury, které chcete prohledávat, tak "částečné vyhodnocování" v Truffle módu, je přesně to, co byste měli prozkoumat!
 +
 
 +
'''Assumption''' (předpoklad) lze použít pro globální spekulaci. Díky tomu je možné přenastavením nějakého stavu zinvalidovat všechny již přeložené kódy, které na tomto stavu závisí. Nakonec si ještě zkusíme napsat polymorfní keš na prohledávání telefonního seznamu. Ale k tomu bude potřeba se ještě vrátit v příští lekci.
 +
 
 +
=== VI. Promluvte si s překladačem: Keše, abstraktní syntaktické stromy a DSL ===
 +
 
 +
[https://stream.cuni.cz/cs/Detail/12658/12041 Šestá část] pokračuje zkoumáním keší. Jak kontrolovat velikost generovaného kódu? Co všechno do keše přidávat a kdy s tím již přestat? Mají se kešovat jen nenulové výsledky či i '''null''' hodnoty? Nakonec jsme se do toho opět trochu zamotali: problémem bylo, že jsme používali '''null''' pro dva významy - nenaplněnou keš a keš s neexistující hodnotou. Nakonec se to vyřešilo, ale je vidět, že udělat chybu nemusí být zase tak složité.
 +
 
 +
Od 13-té minuty se vrháme na syntaktické stromy. Vytvoříme tradičně košatý strom interpretru na sčítání čísílek z pole. Necháme to přeložit a hle, celá ta struktura zmizí a zbyde jen pár instrukcí strojového kódu. No čekali byste to? Což nás dostává k otázce, jaký je vztah či rozdíl mezi programem a daty? Je paměť příliš drahá na ukládání programů? Asi již ne, ale stále zde nějaký rozdíl je. Ve většině případů totiž lze spekulovat na to, že program se měnit nebude a že se budou měnit jen data. Což se také v Trufflu a jeho '''Node''' podtřídách dělá.
 +
 
 +
Co dál? Ve většině interpretrů se používá více datových typů. A dělat stále '''instanceof''' zpomaluje. Je třeba "přebarvit uzly" podle dat, které zpracovávají. Jde to dělat ručně, ale mnohem jednodušší je použít "Truffle DSL" - doménově specifický jazyk, který nás nechá psát, jen to důležité a většinu kódu dogeneruje. Základem tohoto jazyka jsou takzvané "specializace".
 +
 
 +
=== VII. Promluvte si s překladačem: Více DSL, práce s pamětí, kontrola běhu a knihovny ===
 +
 
 +
[https://stream.cuni.cz/cs/Detail/12831/12041 Sedmá část] ukazuje jak definovat "typový systém" dynamického jazyka. Kontrolní otázka: Jaký asi je typový systém JavaScriptu? Ne, nedělám si legraci, něco takového vážně existuje!
-
V [https://stream.cuni.cz/cs/Detail/12042/12041 záznamu druhé přednášky] si nejprve dokončíme úvod z minula a povíme si, jak se ''zbavit Javovské virtuální mašiny''! Dynamický překlad je skvělý, ale vyžaduje spoustu metadat. Naštěstí můžeme [[GraalVM]] využít na překlad ''Java kódu'' do '''EXáče'''! Ale protože nás primárně bude zajímat překlad dynamických jazyků, tak si představíme základní trik, který z dynamických jazyků dělá něco, z čeho lze vygenerovat efektivní strojový kód. Pořádně to prodiskutujeme a pak...
+
Jak v dynamickém jazyku pracovat se zásobníkem? Používejte '''VirtualFrame''' a specializace k ukládání lokálních proměnných. Chcete naimplementovat '''return'''? Vyhoďte '''ControlFlowException'''. Ten samý trik lze použít na '''break''' či '''continue''' a dokonce i na implementaci tail-rekurzivního volání.
-
Od 35-té minuty pak následuje skutečné povídání o moderních překladačích: Jak vlastně překládat Javu, Céčko a jiné staticky typované jazyky? Než se opravdu vrhneme na překlad dynamických jazyků, tak bychom si měli osvěžit, co to vlastně  překladače jsou a jak fungují. Výborně nám k tomu poslouží [https://chrisseaton.com/truffleruby/jokerconf17/ přednáška kolegy Chrise Seatona].  
+
Specializace (pevného seznamu) typů v každém nodu/uzlu? Neomezený seznam datových typů a ke každému umět získat jejich nody/uzly? Použijte knihovny! Což je kód: '''Library extends Node'''. Pojďme použít knihovnu jako "abstraktní datový typ" a nadefinujme si jednu popisující typ "pole". Pak už je jednoduché přidávat další a další implementace "pole".
 +
Nakonec si ukážeme, jak opravdu zaregistrovat implementaci vašeho jazyka. Tedy podědit od '''TruffleLanguage''' a použít '''@Registration''' anotaci. Pak již lze používat obecné '''org.graalvm.polyglot''' API a komunikovat s naším jazykem, tak jako s každým jiným Trufflím jazykem.
-
* What is a JIT compiler?
+
=== VIII. Domluvte se mezi jazyky a vašimi datovými strukturami ===
-
* Why write a JIT compiler in Java?
+
-
* Setting up Graal
+
-
* The JVM compiler interface
+
-
* The Graal graph
+
-
* From bytecode to machine code
+
-
** The bytecode parser and graph builder
+
-
** Emitting assembly
+
-
** Assembly out
+
-
* Optimisations
+
-
** Canonicalisation
+
-
** Global value numbering
+
-
** Lock coarsening
+
-
* Practicalities
+
-
** Register allocation
+
-
** Scheduling
+
-
* What can you use Graal for?
+
-
** A final-tier compiler
+
-
** Your own specific optimisations
+
-
** Ahead-of-time compilation
+
-
** Truffle
+
-
* Summary
+
-
=== III. Talk 2 Compiler: Directives ===
+
[https://stream.cuni.cz/cs/Detail/13019/12041 Osmé pokračování] našeho kurzu se věnuje interoperabilitě mezi jednotlivými Truffle jazyky. A nejen mezi jazyky. Také si ukážeme, jak vystavit vaši vlastní datovou strukturu a nechat ji efektivně zpracovávat pomocí libovolného Trufflího jazyka. Není to ani moc práce a funguje to skvěle a rychle. Hlavně si kvůli něčemu takovému nepište vlastní jazyk!
-
Walk-thru [https://github.com/JaroslavTulach/talk2compiler Talk 2 Compiler] demo project:
+
Posledních dvacet minut je pak věnováno dokončení povídání o správě paměti v dynamických jazycích. Garbage collector si vezmeme z Javy a pak už jen použijeme '''Shape'''/near classes/téměř třídy. Ty se pak stanou spíše součástí "kódu" nežli součástí dat.
-
* Use `CallTarget` & `RootNode` to enter partial evaluation mode
+
-
* Use `mvn test -Pigv` to send graphs to IGV
+
-
* Install maven modules to IGV to show connection between graph and source
+
-
* Follow the README:
+
-
** `warmWelcome`
+
-
** `transferToInterpreter`
+
-
** Rewrite to use profiles
+
-
* Show how to write own language
+
-
=== IV. Talk 2 Compiler: Assumptions & Caches ===
+
=== IX. Štěpán Šindelář: Reimplementace skutečných jazyků ===
-
* Explain [https://github.com/JaroslavTulach/talk2compiler/commit/a457bc242427a448b309a6ce028fc697ca52478f assumptions]
+
[https://stream.cuni.cz/cs/Detail/13512/12041 Devátého pokračování] se ujal Štěpán Šindelář a rozhovořil se o tom, jak pomocí Trufflu naimplementovat '''Python''' a '''R'''ko.
-
** `warmWelcome` with assumptions
+
-
* ExplodeLoop [https://github.com/JaroslavTulach/talk2compiler/commit/82713014e621caeae0d2577141e066c0c84874cb example]
+
-
** `Chain`
+
-
=== V. Talk 2 Compiler: Nodes & Specializations ===
+
Opakování praktických aspektů toho jak integrovat vlastní programovací jazyk do GraalVM a Truffle ekosystému: launchery - nativni vs. JVM mód, Java embedding - více kontektů a sdílený engine (AST).
-
* [https://github.com/JaroslavTulach/talk2compiler/commit/f316b428d5474a60b6eec760f2d54c67b7d397f1 Interpreter for reading array elements]
+
V čem je re-implementace existujících programovacích jazyků složitá: chybějící/neexistující dokumentace, nejasný kontrakt ("observable surface" jazyka) - například je chování garbage collectoru součástí kontraktu?, problematický design C API pro nativní extenze, který odkrývá příliš mnoho implementačních detailů. Demonstrace těchto problémů na Pythonu a R (GraalPython a R). Povídání o tom jak ve FastR optimalizujeme lazy evaluaci argumentů v Rku.
-
** Name the method `executeCompute` to work better with DSL
+
-
** Let it work with `int` and `double`
+
-
* Rewrite using [https://github.com/JaroslavTulach/talk2compiler/commit/af9d269aafc1c3fb8d82f0a3db6437bedbcf40a6 specializations]
+
-
=== VI. Memory Management ===
+
=== X. Štěpán Šindelář: Volání nativních knihoven z Javy pomocí Truffle NFI ===
-
* Garbage Collector
+
V [https://stream.cuni.cz/cs/Detail/13652/12041 desátém pokračování] se Štěpán rozhovořil o zajímavém použítí Truffle interop: o volání do Céčkových knihoven z Javy.
-
* VirtualFrame
+
-
** Descriptor
+
-
* DynamicObject
+
-
** Shape
+
-
=== VII. Graal Self ===
+
Přednáška navazovala na tu předchozí o re-implementaci skutečných jazyků. Většina z nich poskytuje API pro volání C runtin a pro volání zpět z C. Na jednoduchém demo jazyce jsme si ukázali jak lze C API implementovat pomocí Truffle NFI (native function interface) a Graal LLVM (code name Sulong).
-
* Let's look at [https://github.com/JaroslavTulach/SelfGraal real language]
+
=== XI. Vygenerujte si EXáč z vaší Java apky ===
-
* PE parser
+
-
* Interop
+
-
=== VIII. JIT vs. AOT překlad ===
+
[https://stream.cuni.cz/cs/Detail/13766/12041 Jedenáctý příběh] je věnován ukázce toho, jaká je Java skvělý ''systémový jazyk''. Nejprve si vychválíme jazyk Go a podíváme se na to, co by Java ještě potřebovala, aby byla stejně dobrá. Ukážeme si jak takovou "native image" pomocí NetBeans ladit. To by jako základní ukázka mohlo stačit.
-
* [http://wiki.apidesign.org/wiki/Go Go, Java, go!]
+
Od čtyřicáté minuty se zaměříme na to, jak napsat Java JNI metody (ty, které volají do systému) v Javě. Ano, opět Java nad Javou. Díky tomu, že si část naší Java aplikace přeložíme do nativní knihovny, tak pak můžeme efektivněji pracovat s daty z jiných Céčkových knihoven.
-
* jargraal vs. libgraal
+
-
* Using native-image to [https://github.com/JaroslavTulach/matrixultimate implement `native` methods]
+
-
=== IX. Interop mezi jazyky ===
+
Na závěr (od 65-té minuty) nám Tomáš Zezula poví o rozdílu mezi ''jargraalem'' a ''libgraalem''. O tom, jak překládá Graal překladač napsaný v Javě do nativní knihovny. Jaké překážky u toho musel překonat a jaké to má výsledné výhody.
-
* Messages. "Mounting" trees.
+
=== XII. Více o Java EXáčích  ===
-
* Exposing [https://github.com/JaroslavTulach/heapdump data structures] to languages
+
-
=== X. Tools & Instruments ===
+
[https://stream.cuni.cz/cs/Detail/13992/12041 Dvanáctá část] představí [https://www.graalvm.org/docs/tools/dashboard/ GraalVM Dashboard] - nástroj na zkoumání obsahu vygenerovaného pomocí Native Image nástroje. To pak použijeme k tomu, abychom si předpočítali pár tisíc prvočísel dopředu, uložili je do snímku paměti v EXáči a při dalším startu je mohli hned využít.
-
* Making your language "toolable"
+
Od jednadvacáté minuty si pak probereme frameworky, které GraalVM Native Image podporují:
-
** Source section
+
* [https://helidon.io/docs/latest/#/se/guides/02_quickstart Helidon CE] - funguje víceméně samo
-
** Tags
+
* [https://helidon.io/docs/latest/#/mp/guides/02_quickstart Helidon MP] - ukazuje, jak napsat vlastní '''@Feature''' a vynutit initializaci CDI již během AOT překladu
-
** Show how to debug in NetBeans
+
* [https://micronaut.io Micronaut] - eliminuje reflektivní hledání/volání tím, že jej provede již při '''javac''' překladu
-
* Writing an instrument
+
* Quarkus - také implementace MP
-
** Debugger, profiler, code coverage, language server protocol, NetBeans
+
* Spring - již také podporuje Native Image a díky tomu je teď celý Spring lepší
-
* node.js
+
-
** Mixing Java and JavaScript & co.
+
-
=== XI. Static Languages with LLVM ===
+
V šedesáté minutě nastupuje Tomáš Zezula a rozpovídá se o ''izolátech'' - oddělených paměťových prostorech v jednom procesu.
-
* Sulong - interpret C, Rust, atd.
+
=== XIII. Debugger, profiler a spol. pro každý jazyk ===
-
* Truffle NFI
+
-
=== XII. Writing bytecode interpreter ===
+
Motto [https://stream.cuni.cz/cs/Detail/14087/12041 třináctého pokračování] je: hlavně neztrácejte čas psaním debuggeru! A profileru! A nástroje na code coverage! A vůbec. Prostě si napište vlastní jazyk, přidejte pár metadat a GraalVM již všechny tyto nástroje dodá sama. Ať už to má být debugger ve VSCode, v NetBeans či v Chrome prohlížeči.
-
* Espresso - Java interpreter
+
Přidat nálepky/taggy do interpretru nějakého jazyka je lehké. Kupodivu je lehké napsat si i vlastní instrument. Stačí podědit po '''TruffleInstrument''' třídě a zaregistrovat ji pomocí anotace. Kdo by však chtěl psát instrumenty v Javě, že?
-
* Sulong - bitcode interpreter
+
-
=== XIII. Real Language Problems ===
+
Mrkněme se tudíž na [https://github.com/oracle/graal/blob/1afe68c64d25b4b5bd2bd150afd760bc39b799ee/tools/docs/Insight.md GraalVM Insight] a pišme instrumenty v JavaScriptu, Pythonu a vůbec libovolném jazyce, který GraalVM podporuje. Pište si podmíněné breakpointy do Céčka v JavaScriptu!
-
* implementace FFI jazyku jako Ruby/Python/R
+
=== XIV: GraalVM Insight a jak přispívat do projektů ===
-
* yield in JavaScriptu
+
-
* lazy evaluation in R
+
-
=== Appendix A: Contributing To Open Source ===
+
Ve [https://stream.cuni.cz/cs/Detail/14142/12041 čtrnácté části] pojďme nejprve dokončit povídání o [https://github.com/oracle/graal/blob/1afe68c64d25b4b5bd2bd150afd760bc39b799ee/tools/docs/Insight.md GraalVM Insight]u, který spojuje dvě unikátní vlastnosti [[GraalVM]]: interop a instrumentaci.
-
* Overview of the repositories
+
Napište si dynamickou podmínku do svého programu a v kritické situaci vygenerujte '''.hprof''' soubor - snímek paměti, zásobníku, atd. Takový soubor můžete analyzovat ve [http://visualvm.github.io/ VisualVM], ale také jej lze zpracovat pomocí dynamických jazyků. A nejen to, také jej lze přehrát v libovolném debuggeru. Ať žije post-mortem ladění!
-
* Python, JavaScriptem, Ruby, FastR, Espresso
+
-
* mx tooling
+
-
* Signing OCA
+
-
https://github.com/jtulach/bf
+
Od pětačtyřicáté minuty pak následuje povídání o tom, jak přispívat do Open Source projektů. Původně jsem tuto přednášku napsal pro NetBeans, ale zda se obecně platná. Doporučuji ji zvláště, budete-li chtít zápočet. Ten se totiž dává za přijatý pull request do nějaké GraalVM repozitoře. Nezapomeňte podepsat [https://oca.opensource.oracle.com/ OCA] - bez toho to nejde.
-
https://www.youtube.com/watch?v=FJY96_6Y3a4
+

Aktuální verze z 2. 7. 2021, 16:51

Seminář NSWI176 na MatFyzu v letním semestru 2019, který pokračoval i na jaře 2021, kdy bylo jeho čtrnáct dílů zaznamenáno do více než dvaceti hodin záznamu.


Obsah

[editovat] I. Představujeme nejrychlejší univerzální virtuální stroj

Záznam úvodní přednášky. Začínáme historií NetBeans, protože se k přednášce na MatFyzu určitě hodí. Nemůže chybět zmínka o návrhu API a mé knížce Practical API Design, aby bylo zřejmé, proč se tomuto kurzu říká Practical Dynamic Compilation! Následuje takové to tradiční povídání o tom, co GraalVM umí a jak je snadné a jednoduché to nainstalovat (pomocí utilitky gu), použít a jak strašně rychle pak lze počítat Eratosthénovo síto v libovolném jazyce. Není to nic převratného, ale pokud jste to ještě někdo neviděl, tak je to vhodná upoutávka k záznamům dalších lekcí.

Je naše GraalVM implementace Ruby 10-krát rychlejší než jakákoli jiná? Jak dlouho může trvat vypsat všechna prvočísla? Co je vstupem a co je výstupem Graal překladače? Jakým nástrojem můžeme zkoumat, co Graal překladač vlastně uvnitř dělá? Jak napsat vlastní jazyk? Jak vložit implementaci existujícího dynamického jazyka do vlastního Java programu? Dá se to potom také ladit? V NetBeans? Ve Chrome Dev Tools? Má cenu psát interpretr Céčka?

[editovat] II. Jak fungují moderní překladače?

V záznamu druhé přednášky si nejprve dokončíme úvod z minula a povíme si, jak se zbavit Javovské virtuální mašiny! Dynamický překlad je skvělý, ale vyžaduje spoustu metadat. Naštěstí můžeme GraalVM využít na překlad Java kódu do EXáče! To je důležitý střípek v tom, jak GraalVM ekosystém funguje. Ale protože nás primárně bude zajímat překlad dynamických jazyků, tak si hned také představíme základní trik, který z dynamických jazyků dělá něco, z čeho lze vygenerovat efektivní strojový kód. Pořádně to prodiskutujeme a pak...

Od 35-té minuty následuje skutečné povídání o moderních překladačích: Jak vlastně překládat Javu, Céčko a jiné staticky typované jazyky? Pro osvěžení, co to vlastně překladače jsou a jak fungují, nám výborně poslouží přednáška kolegy Chrise Seatona. Opravdu je lepší psát překladač v C++ než v Javě? Chcete psát překladač a nebo vás baví psát vlastní garbage collector!? Nevynalézejte znovu kolo a raději si vyklonujte graal repozitoř. Vaše oblíbené IDE (ať NetBeans nebo VSCode či Ideal Graph Visualizer a nebo i jiné) ty zdrojáky bez problémů otevře. Pak už můžete přidávat breakpointy do zdrojáků překladače, spouštět si vaše programy a koukat, jak se překládají. Můžete si i změnit sémantiku překladu, vypsat si ladící hlášky či něco podobného. Jak vaše aplikace, tak váš překladač jsou v Javě a ve vašem vývojovém prostředí se chovají úplně stejně. Avšak ne jen laděním je živ překládající inženýr! My milujeme grafy z překladače, které radostně zkoumáme v IGV. Stahujte, zkoumejte jednotlivé fáze překladu a bezostyšně přeskakujte mezi IR grafy různých fází, vašimi zdrojáky, zdrojáky překladače. Bez IGV ani ránu!

[editovat] III. Jak překládají moderní překladače?

Třetí díl záznamu zahajuje pět minut technických problémů, ale pak již následuje vytvoření Maven projektu v IGV a jeho zkoumání ze všech možných úhlů. Použijte -Dgraal.Dump=:1 a -Dgraal.PrintGraph=Network a pojďme se podívat na grafy překladu. S gettery, které se inlinují či neinlinují. Prozkoumejme, jak vypadá IR graf výpočtu průměru. Se smyčkou či bez ní. Jak funguje bytecode parser? Jak se generuje assembler? Jak si můžeme vypsat strojový kód z příkazové řádky? Třída Phase a její implementace poskytují různé optimalizace: Kanonikalizace uzlů. Znovupoužití hodnot. Eliminace zámků. Jak může debugger spolupracovat s IGV? Přes graph.getDebug().forceDump(...). Tomáš Zezula nám představí GraphBuilderPluginy a dostane domácí úkol...

[editovat] IV. Promluvte si s překladačem: Direktivy

Čtvrtá část záznamu zkoumá k čemu všemu lze Graal překladač vlastně použít. Začínáme ukázkou Tomáše Zezuly používající GraphBuilderPlugin k nahrazení SecurityManageru no-op konstantou (do 12-té minuty). Takže místo JEP-411, který se snaží SecurityManager smazat, bychom jej tam mohli nechat a jen eliminovat jakoukoli zátěž, která je s ním spojená, nepoužívá-li se. Zajímavé, že?

Propagace konstant je důležitá optimalizace, kterou budeme hojně používat při práci s Talk 2 Compiler demo projektem. A můžeme začít s Trufflem. Co je to RootNode.execute? Co je to CallTarget? To je způsob jak z Java módu běhu a překladu přeskočit do "Truffle překladu". Jak se liší Truffle IGV graf od klasického IGV grafu z Javy? Má final vliv v Javě? A má jej při Truffle překladu? Překlad pro "instanci" RootNodu. Lze používat CompilationFinal a měnit hodnotu takového políčka - natrénujte si svůj kód na hodnoty, které skutečně používáte. Dejte si ale pozor, ať ten kód natrénujete správně! Kdykoli měníte @CompilationFinal pole, tak nezapomeňte zavolat transferToInterpreterAndInvalidate()! Použijte TruffleBoundary na vyskočení z "Truffle módu" do "normální" Javy. Tím zabráníte inlinování příliš velkého množství kódu z mnoha metod.

[editovat] V. Promluvte si s překladačem: Profily, bioinformatika a předpoklady

Opakování je matka moudrosti a tudíž pátá část záznamu stručně shrne specifika Truffle překladu a pak pokračuje ve vysvětlování různých dynamických optimalizačních triků. Spekulujme na to, že se nějaký parametr nemění. Trochu program natrénujeme a jen sledujeme, jak se vše zoptimalizuje. A abychom nemuseli pořád psát to samé, tak použijeme profily: ConditionProfile či ValueProfile či BranchProfile či createCountingProfile().

Ač tyto triky používáme primárně pro psaní interpretrů, tak jsou obecně užitečné. Pojďme se tedy mrknout, jak si promluvit s překladačem a zrychlit nějakou úlohu z bioinformatiky. Vezmeme si BooleanNetwork a zkusme ji nějak rychle prohledat. Když porovnáme klasickou (HotSpot) Javu a kód přeložený v Truffle módu, tak Truffle je o 20% rychlejší. Stačí použít direktivu @ExplodeLoop. Máte-li velké datové struktury, které chcete prohledávat, tak "částečné vyhodnocování" v Truffle módu, je přesně to, co byste měli prozkoumat!

Assumption (předpoklad) lze použít pro globální spekulaci. Díky tomu je možné přenastavením nějakého stavu zinvalidovat všechny již přeložené kódy, které na tomto stavu závisí. Nakonec si ještě zkusíme napsat polymorfní keš na prohledávání telefonního seznamu. Ale k tomu bude potřeba se ještě vrátit v příští lekci.

[editovat] VI. Promluvte si s překladačem: Keše, abstraktní syntaktické stromy a DSL

Šestá část pokračuje zkoumáním keší. Jak kontrolovat velikost generovaného kódu? Co všechno do keše přidávat a kdy s tím již přestat? Mají se kešovat jen nenulové výsledky či i null hodnoty? Nakonec jsme se do toho opět trochu zamotali: problémem bylo, že jsme používali null pro dva významy - nenaplněnou keš a keš s neexistující hodnotou. Nakonec se to vyřešilo, ale je vidět, že udělat chybu nemusí být zase tak složité.

Od 13-té minuty se vrháme na syntaktické stromy. Vytvoříme tradičně košatý strom interpretru na sčítání čísílek z pole. Necháme to přeložit a hle, celá ta struktura zmizí a zbyde jen pár instrukcí strojového kódu. No čekali byste to? Což nás dostává k otázce, jaký je vztah či rozdíl mezi programem a daty? Je paměť příliš drahá na ukládání programů? Asi již ne, ale stále zde nějaký rozdíl je. Ve většině případů totiž lze spekulovat na to, že program se měnit nebude a že se budou měnit jen data. Což se také v Trufflu a jeho Node podtřídách dělá.

Co dál? Ve většině interpretrů se používá více datových typů. A dělat stále instanceof zpomaluje. Je třeba "přebarvit uzly" podle dat, které zpracovávají. Jde to dělat ručně, ale mnohem jednodušší je použít "Truffle DSL" - doménově specifický jazyk, který nás nechá psát, jen to důležité a většinu kódu dogeneruje. Základem tohoto jazyka jsou takzvané "specializace".

[editovat] VII. Promluvte si s překladačem: Více DSL, práce s pamětí, kontrola běhu a knihovny

Sedmá část ukazuje jak definovat "typový systém" dynamického jazyka. Kontrolní otázka: Jaký asi je typový systém JavaScriptu? Ne, nedělám si legraci, něco takového vážně existuje!

Jak v dynamickém jazyku pracovat se zásobníkem? Používejte VirtualFrame a specializace k ukládání lokálních proměnných. Chcete naimplementovat return? Vyhoďte ControlFlowException. Ten samý trik lze použít na break či continue a dokonce i na implementaci tail-rekurzivního volání.

Specializace (pevného seznamu) typů v každém nodu/uzlu? Neomezený seznam datových typů a ke každému umět získat jejich nody/uzly? Použijte knihovny! Což je kód: Library extends Node. Pojďme použít knihovnu jako "abstraktní datový typ" a nadefinujme si jednu popisující typ "pole". Pak už je jednoduché přidávat další a další implementace "pole".

Nakonec si ukážeme, jak opravdu zaregistrovat implementaci vašeho jazyka. Tedy podědit od TruffleLanguage a použít @Registration anotaci. Pak již lze používat obecné org.graalvm.polyglot API a komunikovat s naším jazykem, tak jako s každým jiným Trufflím jazykem.

[editovat] VIII. Domluvte se mezi jazyky a vašimi datovými strukturami

Osmé pokračování našeho kurzu se věnuje interoperabilitě mezi jednotlivými Truffle jazyky. A nejen mezi jazyky. Také si ukážeme, jak vystavit vaši vlastní datovou strukturu a nechat ji efektivně zpracovávat pomocí libovolného Trufflího jazyka. Není to ani moc práce a funguje to skvěle a rychle. Hlavně si kvůli něčemu takovému nepište vlastní jazyk!

Posledních dvacet minut je pak věnováno dokončení povídání o správě paměti v dynamických jazycích. Garbage collector si vezmeme z Javy a pak už jen použijeme Shape/near classes/téměř třídy. Ty se pak stanou spíše součástí "kódu" nežli součástí dat.

[editovat] IX. Štěpán Šindelář: Reimplementace skutečných jazyků

Devátého pokračování se ujal Štěpán Šindelář a rozhovořil se o tom, jak pomocí Trufflu naimplementovat Python a Rko.

Opakování praktických aspektů toho jak integrovat vlastní programovací jazyk do GraalVM a Truffle ekosystému: launchery - nativni vs. JVM mód, Java embedding - více kontektů a sdílený engine (AST).

V čem je re-implementace existujících programovacích jazyků složitá: chybějící/neexistující dokumentace, nejasný kontrakt ("observable surface" jazyka) - například je chování garbage collectoru součástí kontraktu?, problematický design C API pro nativní extenze, který odkrývá příliš mnoho implementačních detailů. Demonstrace těchto problémů na Pythonu a R (GraalPython a R). Povídání o tom jak ve FastR optimalizujeme lazy evaluaci argumentů v Rku.

[editovat] X. Štěpán Šindelář: Volání nativních knihoven z Javy pomocí Truffle NFI

V desátém pokračování se Štěpán rozhovořil o zajímavém použítí Truffle interop: o volání do Céčkových knihoven z Javy.

Přednáška navazovala na tu předchozí o re-implementaci skutečných jazyků. Většina z nich poskytuje API pro volání C runtin a pro volání zpět z C. Na jednoduchém demo jazyce jsme si ukázali jak lze C API implementovat pomocí Truffle NFI (native function interface) a Graal LLVM (code name Sulong).

[editovat] XI. Vygenerujte si EXáč z vaší Java apky

Jedenáctý příběh je věnován ukázce toho, jaká je Java skvělý systémový jazyk. Nejprve si vychválíme jazyk Go a podíváme se na to, co by Java ještě potřebovala, aby byla stejně dobrá. Ukážeme si jak takovou "native image" pomocí NetBeans ladit. To by jako základní ukázka mohlo stačit.

Od čtyřicáté minuty se zaměříme na to, jak napsat Java JNI metody (ty, které volají do systému) v Javě. Ano, opět Java nad Javou. Díky tomu, že si část naší Java aplikace přeložíme do nativní knihovny, tak pak můžeme efektivněji pracovat s daty z jiných Céčkových knihoven.

Na závěr (od 65-té minuty) nám Tomáš Zezula poví o rozdílu mezi jargraalem a libgraalem. O tom, jak překládá Graal překladač napsaný v Javě do nativní knihovny. Jaké překážky u toho musel překonat a jaké to má výsledné výhody.

[editovat] XII. Více o Java EXáčích

Dvanáctá část představí GraalVM Dashboard - nástroj na zkoumání obsahu vygenerovaného pomocí Native Image nástroje. To pak použijeme k tomu, abychom si předpočítali pár tisíc prvočísel dopředu, uložili je do snímku paměti v EXáči a při dalším startu je mohli hned využít.

Od jednadvacáté minuty si pak probereme frameworky, které GraalVM Native Image podporují:

  • Helidon CE - funguje víceméně samo
  • Helidon MP - ukazuje, jak napsat vlastní @Feature a vynutit initializaci CDI již během AOT překladu
  • Micronaut - eliminuje reflektivní hledání/volání tím, že jej provede již při javac překladu
  • Quarkus - také implementace MP
  • Spring - již také podporuje Native Image a díky tomu je teď celý Spring lepší

V šedesáté minutě nastupuje Tomáš Zezula a rozpovídá se o izolátech - oddělených paměťových prostorech v jednom procesu.

[editovat] XIII. Debugger, profiler a spol. pro každý jazyk

Motto třináctého pokračování je: hlavně neztrácejte čas psaním debuggeru! A profileru! A nástroje na code coverage! A vůbec. Prostě si napište vlastní jazyk, přidejte pár metadat a GraalVM již všechny tyto nástroje dodá sama. Ať už to má být debugger ve VSCode, v NetBeans či v Chrome prohlížeči.

Přidat nálepky/taggy do interpretru nějakého jazyka je lehké. Kupodivu je lehké napsat si i vlastní instrument. Stačí podědit po TruffleInstrument třídě a zaregistrovat ji pomocí anotace. Kdo by však chtěl psát instrumenty v Javě, že?

Mrkněme se tudíž na GraalVM Insight a pišme instrumenty v JavaScriptu, Pythonu a vůbec libovolném jazyce, který GraalVM podporuje. Pište si podmíněné breakpointy do Céčka v JavaScriptu!

[editovat] XIV: GraalVM Insight a jak přispívat do projektů

Ve čtrnácté části pojďme nejprve dokončit povídání o GraalVM Insightu, který spojuje dvě unikátní vlastnosti GraalVM: interop a instrumentaci.

Napište si dynamickou podmínku do svého programu a v kritické situaci vygenerujte .hprof soubor - snímek paměti, zásobníku, atd. Takový soubor můžete analyzovat ve VisualVM, ale také jej lze zpracovat pomocí dynamických jazyků. A nejen to, také jej lze přehrát v libovolném debuggeru. Ať žije post-mortem ladění!

Od pětačtyřicáté minuty pak následuje povídání o tom, jak přispívat do Open Source projektů. Původně jsem tuto přednášku napsal pro NetBeans, ale zda se obecně platná. Doporučuji ji zvláště, budete-li chtít zápočet. Ten se totiž dává za přijatý pull request do nějaké GraalVM repozitoře. Nezapomeňte podepsat OCA - bez toho to nejde.