In meiner Freude den JIT-Compiler lauffähig zu haben habe ich gleich zwei recht blöde Dinge übersehen. ^^
The Bad News: Wir sind langsamer als gedacht.
Der User Darksider3 sprach mich vor einiger Zeit darauf an, dass wir ja relativ kleine Laufzeiten haben, die im Falle von Java ja auch auf die Anlaufzeiten von Java zurückzuführen sein könnten. Die Fibinacci-Zahlen wie beschrieben zu berechnen ist schon sehr, sehr teuer und die Reihe von 1 bis 30, das hat in der guten alten Zeit schon viele meiner Computer ins Schwitzen gebracht. Die AST-Version schwitzte dabei ja auch noch ganz gut, also hielt ich die Aussage für ausreichend und konnte mir auch sehr gut vorstellen, dass sich Genesys auch bei längeren Laufzeiten weiter absetzen kann.
Auch wenn er mich nicht sehen konnte, wie ich mir dabei gedanklich auf die Stirn schlug... das nicht getestet zu haben, nervte mich schon. Also habe ich die Werte von 1 bis 40 berechnet, was schon massiv mehr Zeit kostet:
Java braucht hier 1,35 Sekunden - und Genesys 4,85 Sekunden.
Das mit den 30 war also dumm gelaufen, bis 33 (190ms statt 205ms bei Java) ist Genesys schneller, bei 34 (303ms) liegt Java (230ms) dann vorne. Von da an vergrößert sich der Abstand zu Genesys mit jeder weiteren Iteration.
Entsprechend mache ich den Benchmark nun zusätzlich mit Fibunacci-Zahlen bis 40. Wenn ich Java hier überhole, werde ich grundsätzlich vorne liegen.
The Good News: Wir sind schneller als gedacht - aber noch nicht schnell genug.
Ich baue Debug-Informationen in den ausführbaren Code ein. Das sind einfache Texte, die mir mein Disassembler anzeigt um mir zu sagen, wo ich mich in dem Wust aus Assembler gerade befinde. Diese werden von der CPU einfach übersprungen. Sprünge sind nichts, was ein Programm schnell macht und vor allem sind Debug-Versionen nicht unbedingt optimal, um Benchmarks zu machen. Das fiel mir die Tage auch wie Schuppen von den Augen, so dass ich mir die alte Version aus dem Repository zurückholte und die Funktion, welche die Debug-Informationen schreibt, zu deaktivieren.
Ergebnis: Statt 55ms läuft das Programm nun 30ms - fast eine Verdopplung der Ausführungsgeschwindigkeit.
Nimmt man die raus, verdoppelt sich die Ausführungsgeschwindigkeit nahezu. Finde ich gut.
Code: Alles auswählen
30 40 (Werte gemessen auf einem Xeon X5675)
Java 139ms 1350ms
Genesys 55ms 4850ms // mit Debug-Informationen
Genesys 30ms 2200ms // ohne
C (opt) 12ms 650ms
Python 2.7 570ms 59950ms
Die Frage nach der Startgeschwindigkeit ist damit raus. Was bedeutet das im Alltag?
Erstens: Das Programm ist extrem kurz und da gibt's noch reichlich Potential, mit überschaubaren Änderungen deutliche Fortschritte zu machen, wie man C sieht.
Zweitens: Im Alltag laufen Programme gar nicht im Bereich von hunderten Millisekunden, sofern sie keine komplexen Berechnungen machen. Das sieht man sehr schön an Python (2.7), das für viele Aufgaben bereits reicht, aber bei Berechnungen selbst komplett in die Knie geht. Genesys hat keine nennenswerte Startphase und wird später auch native Executables rausspucken - in den gemessenen Werten ist auch immernoch der komplette Kompiliervorgang enthalten, bevor das Programm starten kann.
Von daher bin ich mit der Performance doch noch ganz zufrieden.