Na twitteru se kolem porovnání zveřejněného AWSkem strhl trošku flame war, ale mimo prázdných výkřiků že všichni jsou pitomci se tam objevili i celkem konstruktivní komentáře zabývající se rozdíly v kódu který pro test použili. Je s podivem že pro porovnání programovacích jazyků použili kousky kódu které se liší mnohem více než by bylo nutné. Vypadá to mírně podezřele. Ale jo, obecně ty výsledky sedí na další podobné benchmarky, plus mínus vycházejí podobně. Céčko na vrcholu žebříčku asi není překvapením, jen prostě vyměníte svůj čas jako programátora za strojový čas mašiny, ale Python naspodu mě hodně překvapil. To bych nepředpokládal.
Pudl bude zakopaný v tom, že ty benchmarky jsou malé, jednoúčelové a vysoce optimalizované prográmky. Pokud by se člověk pokusil přepsat do C nebo Rustu nějakou větší aplikaci, tak nejen že to bude mnohem náročnější na údržbu, ale nejspíš ani to zlepšení energetické efektivity nebude tak zázračné.
A pak by se mělo započítat i to o kolik víc energie spálí programátor při vývoji a debugovaní v nízkoúrovňovém jazyce :-)
Neříkám, že je problém napsat velkou aplikaci v nízkoúrovňovém jazyce. Jen že to je víc kódu. A čím víc kódu, tím víc tam bude funkcí, které by zvládl optimalizovat i vysokoúrovňový jazyk (protože málokterá aplikace je celá CPU-heavy), takže ten rozdíl v efektivitě může vyjít úplně jinak než u malého benchmarku.
Praktický příklad, kde na jedné straně bude (předem kompilovaný do nativního kódu*) Rust a na druhé straně jiný jazyk s JITem, který bude při dlouhém běhu a dostatku RAM rychlejší, z fleku nevytáhnu. Nabízí se ale jiná zajímavá srovnání:
a. GraalVM JIT vs. native-image. Máme srovnání stejného se stejným, jednou JIT, jednou kompletní překlad před spuštěním. JIT žere víc RAM a spuštění trvá déle, ale jakmile máme spuštěno a zahřáto, typicky je to rychlejší než native-image.
b. Teoreticky bychom podobné srovnání mohli udělat i pro Rust, protože GraalVM umí LLVM (Sulong). Takže bychom mohli mít Rust s low-level JITem. Prakticky tu může být více problémů a neznámých, a přecejen Sulong – jakkoli je zajímavý – asi nebude tím hlavním tahounem GraalVM.
EDIT: Důvod, proč JIT může být rychlejší, je, že JIT si může dovolit dělat i různé spekulativní optimalizace (pokud optimalizace selže, může to deoptimalizovat a klidně zkompilovat znovu) a statistiky za běhu.
*) Obecně to není jediná možnost u Rustu, ale tiše jsem předpokládat, že to máte na mysli.
27. 2. 2022, 00:17 editováno autorem komentáře
Co myslíte tím „v praxi“?
a Najdete-li vhodnou aplikaci kompatibilními s native-image, můžete porovnat AOT a JIT celkem snadno. Není to Rust, ale je to srovnávání srovnatelného.
b. Myslím, že kdybych tomu věnoval pár hodin, najdu případ, kdy Rust pod Sulongem bude výkonnější díky JIT, i kdyby jinak byl Sulong pomalejší než LLVM. (Nevím, jak si proti sobě stojí.) Ale byl by to syntetický benchmark…
c. Nejvíc „v praxi“ by to bylo na reálných aplikacích, ale tak je dost problém srovnávat srovnatelné. Najdete dvě aplikace, jedna v Rustu, druhá třeba v Javě, každá bude dost možná napsaná úplně jinak (zvlášť bude-li to netriviální aplikace) atd. Ve výsledku by za tím rozdílem mohlo stát něco úplně irelevantního.
Juliu moc neznám, IIRC má dynamické typy. Tím spíš ale potřebuje JIT, aby byla Rustu vůbec konkurenceschopná. Při AOT kompilaci by kompilátor věděl dost málo o konkrétních typech, a bez toho lze ten kód přeložit dost genericky, třeba u operace + nebude jasné, jestli jde o součet celých čísel, floatů, nějaký mix, nebo třeba spojení řetězců. Samozřejmě, může to odvodit pro některé specifické případy, ale obecně ne. A kdyby to měl odvozovat obecně pro hromadu případů, generoval by obrovský kód, a stejně by to nejspíš bylo málo.
To samo o sobě ale jen říká, že Julia potřebuje JIT, aby mohla s Rustem vůbec soupeřit, nevysvětluje, jak může Rust předehnat. To bych hledal ve spekulativních optimalizacích, kde JIT může třeba volání virtuální metody přeložit jako statický dispatch, a teprve v případě potřeby z toho udělat dynamický dispatch. Nevím, jestli zrovna toto bude nejčastější problém v Rustu, je to spíše ukázka, kde JIT může nabrat výhodu.
Ne, v Julii není mezi AOT a JIT vůbec žádný rozdíl, viz “type stability”. A protože má multimetody, všechna volání funkcí se škatulkují už při (prvním) překladu ve všech případech. Má hodně silný typový systém s abstraktními, generickými a součtovými typy, takže informací k tomu má dostatek. Pro překlad používá LLVM a jeho optimalizace. Prostě funguje úplně jinak, než Java (mnohem lépe).
Tak ma napadá:
Prepisovať niečo do C-čka iba kvôli energetickej úspornosti? Prečo nie do assembleru?
Nasledne ten kód treba udržovať a ďalej rozvíjať ... nie?
Keď sa už bavíme o efektivite, tak v neprospech Javy hovorí aj to, že spotrebúva oveľa viac pamäte ako kompilované jazyky. Takže tým by sa ušetrilo možno ešte viac energie - je nutné vyrobiť a prevádzkovať (refreshovať) násobne viac RAM!
Sú aj iné dôležité parametre ako energetická účinnosť. Napr. spoľahlivosť, udržovateľnosť a pod.
Robím v oblasti priemyselnej automatizácie (SCADA systémy). Primárne v jazyku Ada, človek sa viac napíše ako v C-čku, na druhej strane kód je oveľa čitateľnejší (aj cudzí), bezpečnejší a mnoho chýb odchytí už kompilátor. Ďalšie runtime checky .. za cenu CPU výkonu - ale to každý akceptuje radšej ako nejaké padanie kvôli prepisovaniu pamäte za hranicou poľa. Takže tie checky nikdy nevypíname a sme za ne vďační.
25. 2. 2022, 19:38 editováno autorem komentáře
To s tou pamětí je trefný postřeh, nevím jak datová centra, ale energetická náročnost RAM (refrešování) bývala důvodem, proč iPhony mívaly paměti poměrně málo. Z toho pak vyplynulo, že Apple nechtěl na iOS tracing GC, aby aplikace nežraly té paměti moc (na macOS ObjC tracing GC volitelně mělo). Teď už to asi hraje menší roli, ale Swift má taky jen ARC.
SPARK je super, ale použiteľný pre embedded systémy a podobne. Má dosť silné obmedzenia (teraz hovorím z pohľadu SCADA systémov - do tej "rozumnej podmnožiny" sa bohužiaľ nezmestíme). Pekné je, že sa dá kombinovať SPARK / ADA (niektoré procedúry/funkcie môžu byť SPARKové, s overenou korektnosťou, zvyšok ADA).
SPARK/ADA sa použila aj pri programovaní študentských cube-satov:
https://blog.adacore.com/ten-years-of-using-spark-to-build-cubesat-nano-satellites-with-students
https://www.youtube.com/watch?v=YlnfyToUwv4
Tu:
https://youtu.be/YlnfyToUwv4?t=461
píšu, že majú cca 10 tisíc riadkov kódu. Ok, my máme vyše 2.5 milióna (bez prázdnych riadkov a komentárov).
Tu:
https://youtu.be/YlnfyToUwv4?t=89
hovorí o tom, že z 12 univerzitných CubeSatov sa ozvali po vypustení iba 4, z nich dlhodobe (vyše 2 rokov) fungoval iba ich SPARKový. Ostatné boli programované v C-čku a jeden z nich pošiel v priebehu dňa, druhý do týždňa a tretí vydržal 4 mesiace.
Záleží na aplikaci. V praxi u databázově orientovaných aplikací, kterých si myslím, že minimálně hodně ne-li většina, se mnohem víc energie spálí na: a) chybějících indexech (ať jednoduchých nebo složených), bordelu v databázi (bavíme se o úrovních normalizace), špatné konfiguraci operačního systému - huge pages, transparent huge pages, atd atd, neoptimálně nastavené virtualizaci - nikdy bych nevěřil, co dokáže neoptimálně nastavený proxmox. Nějaký Python nebo Java pak hraje naprosto zanedbatelnou roli.
Prosím nešiřte informace o článku, který nemá žádnou vědeckou ani technickou úroveň. Viz např. https://twitter.com/_rsc/status/1496352325157457922
Navíc pro kód mimo hodně speciální nasazení jsou navíc mikro-benchmarky úplně mimo mísu, protože opravdu nebudu psát CRUD aplikaci ve Fortranu a nejspíš ani v C, ale řada podniků se rozhodne pro Javu, C#, TypeScript, možná Python nebo Ruby a ty progresivnější třeba Clojure/ ClojureScript.
Je to opravdu dětinská diskuze a mimo mísu. Malé zefektivnění ve Windows, Linuxu, Chromiu nebo přímo v jednotlivých jazycích budou mít nedozírně větší efekt. Lidi ale nebudou fluidně přecházet mezi aplikacemi, jazyky a operačními systémy, protože opravdu nejde jen o rychlost/ efektivitu běhu.
Jenom připomenu, co normální firma/ inženýr bude dělat, když je aplikace pomalá:
- Zamyslí se/ použije nástroje a naměří/ nebo aspoň nacítí si nějaká data. Většina aplikací je prostě pomalá a je celkem jasné proč. Např. příšerně neefektivní přístup k problému, tahání dat "ideálně" přes síť a ještě např. synchronním způsobem, vyhledávání, procházení velkého objemu dat, často zbytečně.
- Když našel úzké hrdlo, podívá se, jak by ho mohl opravit. Např. zredukovat problém, použít lepší algoritmus, dodat správný index do databáze, lepší dotaz, používat batching, cache, lepší knihovnu/ napsat si funkci lépe sám, lepší nastavení systému...
- Podívá se, jestli už je to lepší. Otestuje správnost.
- Případně opakuje a řeší další problémy.
Následující body v různém pořadí, podle problému, peněz, času a obecně možností:
- Když dojde k tomu, že to je jazykem, podívá se, jestli nemůže kritickou sekci vyčlenit do efektivnější implementace/ volání vyladěné knihovny/ systému. Podobně jako NumPy + Python, obcházení React.Js v kritickém místě apod.
- Lepší hardware/ víc hardware (např. load-balancing)
- možná úplně jiné uchopení problému potenciálně v jiném jazyce
Prostě nějaké přepisy jsou u větších projektů opravdu až na posledních příčkách TODO, když je výkon/ efektivita neuspokojivá. V drtivé většině případů se prostě jen dělají nesmysly, ten výpočet/ aplikaci možná ani nikdo nepotřebuje a dělá se to automaticky z historických nebo jiných pseudo-důvodů. Často se čeká někde na DNS, nebo je špatně nastavený systém/ chybí index/ dotaz je složitý a DB se nepomohlo jej schroupat efektivněji. Často chybí cache na již hotovou práci/ aby se zbytečně netahala. Je špatný algoritmus.
Možná výpočet přerušuje agresivní logging/ monitoring nebo něco, kde se draze přepíná kontext a výkon jde do háje. To už jsem taky zažil, systém nevykonával vlastně vůbec aplikaci, ale monitoring. Možná je pro webovou apku nevhodná knihovna/ framework nebo neefektivní implementace v prohlížeči (např. SVG vs PNG/ canvas/ WebGL). Prostě tento druh problémů.
Obecně, dobrý programátor/ inženýr má nějakou intuici, jestli je výkon dostatečný nebo ne. Když to splňuje explicitní/ implicitní zadání, tak nikdo kromě těch nejspecifičtějších/ největších nasazení výkon neřeší. V nejhorším se koupí o facku větší server/ osadí novější chip a jde se dělat něco, co má hodnotu.