Whew Programming Languages Use the Least Electricity?
Kunnen gegevens over energieverbruik ons iets vertellen over de kwaliteit van onze programmeertalen?
Laatst jaar besloot een team van zes onderzoekers in Portugal van drie verschillende universiteiten deze vraag te onderzoeken, en brachten uiteindelijk een paper uit getiteld “Energy Efficiency Across Programming Languages.” Ze onderzochten de oplossingen van 10 programmeerproblemen die in 27 verschillende talen waren geschreven, terwijl ze zorgvuldig in de gaten hielden hoeveel elektriciteit elke taal verbruikte – evenals de snelheid en het geheugengebruik.
Specifiek gebruikten ze 10 problemen uit het Computer Language Benchmarks Game, een gratis softwareproject voor het vergelijken van prestaties dat een standaardset eenvoudige algoritmische problemen omvat, evenals een raamwerk voor het uitvoeren van tests. (Het was vroeger bekend als “The Great Computer Language Shootout.”) “Dit stelde ons in staat om een vergelijkbare, representatieve en uitgebreide set programma’s te verkrijgen… samen met de compilatie/uitvoeringsopties, en compilerversies.”
Het was belangrijk om een verscheidenheid aan benchmarktests uit te voeren omdat uiteindelijk de resultaten varieerden afhankelijk van welke test er werd uitgevoerd. Zo bleek de C-taal over het algemeen het snelst en ook het energiezuinigst. Maar in de benchmark test waarbij een DNA database werd gescand voor een bepaalde genetische sequentie, was Rust het meest energie-efficiënt – terwijl C op de derde plaats kwam.
Maar zelfs binnen diezelfde test hangt de “beste” taal af van wat je criterium is. Voor die test bleek C ook slechts de op een na snelste taal te zijn (wederom, achter Rust). Maar Rust zakte maar liefst negen plaatsen als de resultaten werden gesorteerd op geheugengebruik. En hoewel Fortran de op een na energiezuinigste taal was voor deze test, zakte het ook een volle zes posities wanneer de resultaten in plaats daarvan werden gesorteerd op uitvoeringstijd.
Een snellere taal is niet altijd de meest energiezuinige.
De onderzoekers merken op dat ze de richtlijnen van het CLBG-project over compilerversies en de beste optimaliseringsvlaggen “strikt hebben opgevolgd”. Het stroomverbruik werd gemeten met een tool van Intel – de Running Average Power Limit tool – waarbij elk programma niet één keer, maar 10 keer werd uitgevoerd, “om de impact van koude starts en cache-effecten te beperken, en om de consistentie van de metingen te kunnen analyseren en uitschieters te vermijden.” (Om deze reden melden zij dat “de gemeten resultaten vrij consistent zijn”). Voor extra consistentie waren alle tests op een desktop waarop Linux Ubuntu Server 16.10 draaide (kernel versie 4.8.0-22-generic), met 16GB RAM en een 3.20GHz Haswell Intel Core i5-4460 CPU.
In hun paper noemen de onderzoekers enkele interessante resultaten.
“Lisp, gemiddeld, verbruikt 2.27x meer energie (131.34J) dan C, terwijl het 2.44x meer tijd kost om uit te voeren (4926.99ms), en 1.92x meer geheugen (126.64Mb) nodig heeft in vergelijking met Pascal.”
Ze hebben ook de resultaten vergeleken van gecompileerde talen versus geïnterpreteerde talen (met een aparte categorie voor talen die op virtuele machines draaien). En de paper bevat ook een aparte vergelijking van de verschillende programmeer paradigma’s – met inbegrip van zowel functioneel en imperatief programmeren, plus object-georiënteerd programmeren en scripting.
Is Sneller Groener?
De paper nam een harde kijk op de gemeenschappelijke veronderstelling dat een sneller programma altijd minder energie zal gebruiken, erop wijzend dat het niet zo eenvoudig is als de wet van de natuurkunde die zegt E(nergy) = T(time) x P(ower). Dit komt deels doordat energie niet in een consistent tempo wordt verbruikt, zo merken de onderzoekers op, wat van invloed kan zijn op het werk van andere onderzoekers die onderzoeken of de draaitijd van een programma invloed heeft op het energieverbruik. (“Conclusies over deze kwestie lopen soms uiteen…”) In een van hun benchmark tests duurde het 55 procent minder lang om een Chapel programma uit te voeren dan een gelijkwaardig programma geschreven in Pascal – en toch verbruikte dat Pascal programma 10 procent minder energie.
Dus hoewel er nog steeds een algemeen geloof is dat het energieverbruik omlaag gaat als programma’s sneller lopen, stellen de onderzoekers ondubbelzinnig dat “een snellere taal niet altijd het meest energie-efficiënt is.”
Het kan een moeilijke vraag zijn om te beantwoorden, omdat stroomverbruik wordt beïnvloed door vele factoren (waaronder de kwaliteit van de compiler en welke bibliotheken worden gebruikt). Maar uiteindelijk waren de onderzoekers zelfs in staat om het energieverbruik uit te splitsen op basis van de vraag of het werd verbruikt door de CPU of DRAM – met als conclusie dat het grootste deel van de energie (ongeveer 88 procent) werd verbruikt door de CPU, gemiddeld, ongeacht of het benchmarkprogramma werd gecompileerd, geïnterpreteerd of op een virtuele machine werd uitgevoerd.
Interessant is dat geïnterpreteerde talen een iets grotere variatie vertoonden, waarbij de CPU soms wel 92.90 procent van de energie of zo weinig als 81,57 procent.
Na bestudering van hun resultaten concludeerden de onderzoekers ook dat de relatie tussen piekgebruik van DRAM en energieverbruik “bijna niet bestaat.”
Het onderzoek biedt wat meer inzicht in de eeuwige vraag: is sneller groener? Ja, het is waar dat “de top vijf meest energie-efficiënte talen hun rang behouden wanneer ze worden gesorteerd op uitvoeringstijd en met zeer kleine verschillen in zowel energie- als tijdwaarden.”
In feite, voor negen van de 10 benchmarkproblemen, kwam de topscore (voor zowel snelheid als energie-efficiëntie) van een van de top drie algemeen snelste en meest energie-efficiënte talen – wat de onderzoekers niet verbaasde. “Het is algemeen bekend dat deze top drie talen (C, C++, en Rust) bekend staan als zwaar geoptimaliseerd en efficiënt voor uitvoeringsprestaties, zoals onze gegevens ook laten zien.”
Maar je ziet niet dezelfde volgorde wanneer je de andere 24 talen rangschikt naar hun run-time als wanneer je ze rangschikt naar energie-efficiëntie. “Slechts vier talen behouden dezelfde energie- en tijdrangorde (OCaml, Haskel, Racket en Python), terwijl de rest volledig wordt geschud.”
En zelfs op individuele benchmarktests zijn er gevallen waarin snel presterende talen niet de meest energie-efficiënte zijn.
De voordelen van gecompileerde talen
Er waren nog andere interessante resultaten. Gecompileerde talen “hebben de neiging” het energiezuinigst en het snelst te zijn – en hun paper kan dat verschil zelfs kwantificeren met een getal. “Gemiddeld verbruikten gecompileerde talen 120J om de oplossingen uit te voeren, terwijl deze waarde voor een virtuele machine en geïnterpreteerde talen respectievelijk 576J en 2365J was.”
De onderzoekers pasten dezelfde precisie toe bij het vergelijken van de uitvoeringstijden, en concludeerden dat gemiddeld, “gecompileerde talen 5103ms duurden, virtuele machinetalen 20623ms, en geïnterpreteerde talen 87614ms.”
Van de top vijf talen in beide categorieën, waren er vier gecompileerd. (De uitzondering? Java.)
Energieverbruik | Run-tijd | |
C | 57J | 2019 ms |
Rust | 59J | 2103 ms |
C++ | 77J | 3155 ms |
Ada | 98J | 3740 ms |
Java | 114J | 3821 ms |
De vijf traagste talen waren allemaal geïnterpreteerde talen: Lua, Python, Perl, Ruby en Typescript. En de vijf talen die de meeste energie verbruikten, waren ook geïnterpreteerd: Perl, Python, Ruby, JRuby, en Lua.
Maar tegelijkertijd, bij het manipuleren van strings met reguliere expressie, blijken drie van de vijf meest energie-efficiënte talen geïnterpreteerde talen te zijn (TypeScript, JavaScript, en PHP), “hoewel ze de neiging hebben niet erg energie-efficiënt te zijn in andere scenario’s.”
Gebouwde talen namen ook de top vijf slots voor de minste hoeveelheid gebruikte geheugenruimte in.
Taal | Gebruikte geheugenruimte |
Pascal | 66Mb |
Go | 69Mb |
C | 77Mb |
Fortran | 82Mb |
C++ | 88Mb |
“Gemiddeld, hadden de gecompileerde talen gemiddeld 125Mb nodig, de virtuele machinetalen 285Mb en de geïnterpreteerde 426Mb”, aldus het rapport van de onderzoekers. Ondertussen eisten geïnterpreteerde talen vier van de vijf onderste plaatsen op, wat betekent dat ze de meeste geheugenruimte verbruikten: JRuby, Dart, Lua, en Perl. (Hoewel Erlang geen geïnterpreteerde taal is, zou het ook in de onderste vijf staan, tussen Dart en Lua).
“Gesorteerd op hun programmeer paradigma, hadden de imperatieve talen 116Mb nodig, de object-georiënteerde 249Mb, de functionele 251Mb, en tenslotte de scripting 421Mb.”
In feite, bij het vergelijken van de verschillende paradigma’s, kwam imperatief programmeren vaak als winnaar uit de bus. De benchmark programma’s gebruikten gemiddeld ook veel minder energie – en liepen veel sneller – dan de benchmark programma’s voor object-georiënteerde, functionele, en scripting paradigma’s.
Energieverbruik | Run-time | |
Imperatief | 125J | 5585ms |
Object-georiënteerd | Object-georiënteerd | |
Object-georiënteerd | 879J | 32965ms |
Functioneel | 1367J | 42740ms |
Scripting | 2320J | 88322 ms |
Maar er zijn een heleboel factoren om rekening mee te houden. “Het is duidelijk dat verschillende programmeerparadigma’s en zelfs talen binnen hetzelfde paradigma een totaal verschillende impact hebben op energieverbruik, tijd en geheugen,” schrijven de onderzoekers. Welke van die factoren het belangrijkst is, hangt echter af van je scenario. (Achtergrond taken, bijvoorbeeld, hebben niet altijd de snelste runtime nodig.)
En sommige toepassingen vereisen de overweging van twee factoren – bijvoorbeeld energiegebruik en uitvoeringstijd. In dat geval “is C de beste oplossing, omdat het dominant is in beide afzonderlijke doelstellingen,” schrijven de onderzoekers. Als je probeert tijd te besparen en tegelijkertijd minder geheugen te gebruiken, zijn C, Pascal en Go “gelijkwaardig” – en hetzelfde geldt als je alle drie de variabelen in de gaten houdt (tijd, energiegebruik en geheugengebruik). Maar als je alleen maar energie wilt besparen en tegelijkertijd minder geheugen wilt gebruiken, kun je het beste kiezen voor C of Pascal.
Aan het eind van de paper voegen de onderzoekers toe dat ze voor verdere studie willen onderzoeken of het totale geheugengebruik in de loop der tijd beter correleert met het energieverbruik.
Ze delen hun gegevens online, suggererend dat dit het voor toekomstige onderzoekers gemakkelijker maakt om bijvoorbeeld .NET-talen of JVM-talen te vergelijken. Voor ontwikkelaars die werken met mobiele toepassingen, Internet-of-Things-systemen, of andere apps die putten uit beperkte stroomvoorzieningen, is stroomverbruik een grote zorg.
Maar uiteindelijk kan de studie programmeurs ook opzadelen met het ding dat ze het meest haten: ambiguïteit. De onderzoekers melden dat als je op zoek bent naar één enkele beste programmeertaal, “deze vraag geen concreet en ultiem antwoord heeft.
“Hoewel de meest energie-efficiënte taal in elke benchmark bijna altijd de snelste is, is het een feit dat er geen taal is die consequent beter is dan de andere,” concluderen de onderzoekers. “De situatie waarin een taal gebruikt gaat worden is een kernaspect om te bepalen of die taal de meest energie-efficiënte optie is.”