Java vs. C. Performance-Vergleich



  • Steffo schrieb:

    Werde auch gleich Performancetests durchführen...

    Ich vermute, Du wirst über die Java-Performance entsetzt sein. 😃



  • Wird interessant, ob der Java Compiler shoot inlined und merkt, dass er kein Point erstellen muss.



  • HereIGo schrieb:

    Wird interessant, ob der Java Compiler shoot inlined und merkt, dass er kein Point erstellen muss.

    Ich denke nicht, dass er das macht. Ich habe in Java immer die Erfahrung gemacht, dass man kurzlebige Objekte eher vermeiden sollte. Bei C++ ist das hingegen nicht wichtig.



  • Also ich habe das mal mit Java 6 kompiliert (hat jemand Java 7 installiert?!) und mit gcc -03 getestet:

    [steffo@localhost performance]$ time ./pi-cpp
    3.14159
    
    real	0m2.598s
    user	0m2.595s
    sys	0m0.004s
    [steffo@localhost performance]$ time java Main
    3.14159053
    
    real	0m4.468s
    user	0m4.075s
    sys	0m0.474s
    

    Hier kommt die C++ Version ohne gcc-Optimierung (konnte ich mir nicht verkneifen :D):

    [steffo@localhost performance]$ time ./pi-cpp
    3.14159
    
    real	0m32.149s
    user	0m32.122s
    sys	0m0.009s
    

    Liebe Grüße
    Steffo



  • Michael E. schrieb:

    Steffo schrieb:

    Michael E. schrieb:

    Auch Javaprogramme, die nicht Swing benutzen, werden als langsam empfunden.

    Z. B.?

    Man sollte den Spieß umdrehen und nach schnellen Javaprogrammen fragen 😉

    http://www.heli-x.net/ Die Version 0.9 gibts kostenlos. http://www.heli-x.net/download.shtml
    Fühlt sich eigentlich nie wie Java an.



  • Steffo schrieb:

    Also ich habe das mal mit Java 6 kompiliert (hat jemand Java 7 installiert?!) und mit gcc -03 getestet:

    [steffo@localhost performance]$ time ./pi-cpp
    3.14159
    
    real	0m2.598s
    user	0m2.595s
    sys	0m0.004s
    [steffo@localhost performance]$ time java Main
    3.14159053
    
    real	0m4.468s
    user	0m4.075s
    sys	0m0.474s
    

    [/code]

    Oh, interessant. Ich hätte gedacht, dass Java da wesentlich schlechter abschneidet. Kannst Du das auch nochmal mit Werten überpüfen, die eine Größenordnung größer sind. Benchmarks, die 2-3 Sekunden dauern, zeigen in Java zu einem großen Anteil das Laden der JVM.

    Außerdem kommt hier die nächste Herausforderung. Da wird Java ein echtes Problem bekommen:

    Sortiere ein Array mit 300.000 Point-Objekten nach ihrem Abstand vom Ursprung.

    Java wird da aus folgendem Grund ein Problem bekommen: Es gibt in Java einen Overhead für jedes Objekt, der 8 Byte groß ist. Zudem steckst Du nicht die Objekte in das Array, sondern nur Zeiger auf diese Objekte. Auch nochmal 8 Byte. Deshalb sind Java-Objekte einfach viel größer als C++ Objekte. Du sprengst den Cache damit früher, brauchst mehr Speicher und so weiter.



  • HereIGo schrieb:

    Wird interessant, ob der Java Compiler shoot inlined und merkt, dass er kein Point erstellen muss.

    Anscheinend ist das der Fall! 😮 😮 😮
    War es nicht so, daß Java eine Exception schmeißen muß, wenn es integer-Überläufe gibt? Die würden vielleicht das Bißchen mehr an Laufzeit erklären. Kann mir kaum vorstellen, daß new nebst Garbage-Collection so billig ist. Ok, new ist sehr billig, klar. Oder war genug Speicer da, daß kein gc-Lauf überhaupt nötig war?

    Naja, prinzipiell ist es möglich, einen Optimierer zu schreiben, der erkennt, daß gar kein Point erstellt werden muß. Und prinzipiell ist es möglich, einen Optimierer zu schreiben, der erkennt, daß da noch keine Überläufe entstehen können. Wir messen hier nicht Sprachen aus, sondern nur derzeitige Implementierungen.

    Ich hatte vermutet, Jave würde abkacken. Das ist nicht der Fall. 100% mehr ist nichts. Diese langsamen gefühlten Java-Oberflächen haben weit mehr als 1000%. Also daran lag es wohl nicht. Aber am Code liegt es auch nicht, mag ich meinen. Was ich da so gelesen habe, war einfach, zielstrebig, offensichtlich richtig, elegant und bescheiden, offensichtlich schnell. Ich würde mir wünschen, C++-Programmierer würden so gut coden. Warum Java-Anwendungen so unglaublich oft endlos lahm sind, mir ist es ein Rätsel.

    ps: Bitte immer mit -march=native testen. Der Java-Jitter darf ja auch den Prozesssor kennen.



  • Steffo: Kannst du mal die final aus dem Point raus machen und schauen, ob das was ändert?



  • Ich habe mal dem Pi-Konstruktor 100000 als Parameter übergeben, wobei sowohl bei der C++- als auch bei der Java-Version Blödsinn rauskommt (es kommt kein PI, sondern eine Zahl kleiner 0 raus):

    [steffo@localhost performance]$ time ./pi-cpp
    -1.003
    
    real	4m19.205s
    user	4m18.967s
    sys	0m0.114s
    
    [steffo@localhost performance]$ time java Main
    -1.0029964730543903
    
    real	6m40.989s
    user	6m41.627s
    sys	0m1.991s
    

    ps: Bitte immer mit -march=native testen. Der Java-Jitter darf ja auch den Prozesssor kennen.

    Das mache ich extra nicht. Weshalb? Zeig mir mal Software, die auf diese Weise kompiliert wird. Das wird man in der Praxis kaum finden. Die Software, die auf deinem Computer läuft wurde garantiert nicht so kompiliert, es sei denn du benutzt Gentoo. Die Stärke von Java ist ja gerade, dass es zur Laufzeit optimieren kann.

    Steffo: Kannst du mal die final aus dem Point raus machen und schauen, ob das was ändert?

    Kommt gleich. 😉

    L. G.
    Steffo



  • HereIGo schrieb:

    Steffo: Kannst du mal die final aus dem Point raus machen und schauen, ob das was ändert?

    Bei new Pi(10000):

    [steffo@localhost performance]$ time java Main
    3.14159053
    
    real	0m4.682s
    user	0m4.292s
    sys	0m0.523s
    

    Liebe Grüße
    Steffo



  • Steffo schrieb:

    ps: Bitte immer mit -march=native testen. Der Java-Jitter darf ja auch den Prozesssor kennen.

    Das mache ich extra nicht. Weshalb? Zeig mir mal Software, die auf diese Weise kompiliert wird. Das wird man in der Praxis kaum finden. Die Software, die auf deinem Computer läuft wurde garantiert nicht so kompiliert, es sei denn du benutzt Gentoo. Die Stärke von Java ist ja gerade, dass es zur Laufzeit optimieren kann.

    Ich kann doch auf der CD 12 verschiedene game.exe Dateien anbieten und vom Installer die passende auf die Platte rotzen. Nu werd mal nicht kindisch. Die exe ist so klein, davon kann man 100 draufrotzen, ohne zu leiden. Daß es unüblich ist, ist, weil es normalerweise nur 1% ausmacht. In so einem konstruierten Test solltest Du fair bleiben. Würde ein großer Unterschied sein, würde man 100 exe ausliefern. Da habe ich keine Bange. Da wir theoretisch damit rechnen müssen, daß -march=native viel bringt, um wissenschaftlich zu bleiben, mußt Du leider auch damit messen.



  • Wie auch immer, hat aber nichts gebracht. Das Ergebnis ist bei einem Radius von 10000 sogar schlechter als meine erste Messung. 🙂

    [steffo@localhost performance]$ g++ -O3 -march=native pi.cpp -o pi-cpp
    [steffo@localhost performance]$ time ./pi-cpp
    3.14159
    
    real	0m2.930s
    user	0m2.925s
    sys	0m0.004s
    

    Liebe Grüße
    Steffo



  • Steffo schrieb:

    Wie auch immer, hat aber nichts gebracht.

    Es hat gebracht, daß wir über den Zweifel erhaben sind, bewußt unfair gemessen zu haben. Das ist enorm viel, finde ich.



  • volkard schrieb:

    Steffo schrieb:

    Wie auch immer, hat aber nichts gebracht.

    Es hat gebracht, daß wir über den Zweifel erhaben sind, bewußt unfair gemessen zu haben. Das ist enorm viel, finde ich.

    Wie gesagt, ich sehe das anders. Dein Beispiel mit den verschiedenen Exe-Dateien mag bei x86 und x64 Architekturen in der Praxis stimmen, aber eine feinere Abstimmung wirst du nicht vorfinden, deshalb halte ich nicht all zu sehr von zu viel Theoretisierung - das ist ein beliebtes Mittel von Lobbyisten und Marketing-Leuten, aber nicht von Leuten, die mit beiden Beinen auf dem Boden bleiben.

    EDIT: Außerdem ist der Source frei verfügbar. Es steht jedem zu selbst zu messen, um sein eigenes Urteil zu bilden.

    L. G.
    Steffo



  • Einen Vorschlag zur Güte: Du testest immer beides, dann können wir nebenbei noch abschätzen wieviel die zusätzliche Optimierung bringen würde



  • Bei mir siehts aktuell interessanterweise so aus:

    $ time java Main

    real 0m0.253s
    user 0m0.283s
    sys 0m0.052s

    $ time ./prog
    3.14159

    real 0m0.605s
    user 0m0.513s
    sys 0m0.004s

    Beide mit 10k.



  • Hast du was am Code geändert?



  • Ich habe alles in eine Code-Datei gesteckt und die 2 public bei den Klassen weggemacht, ansonsten nichts. Allerdings sehe ich gerade, dass bei Java gar keine Ausgabe ist. Irgendwas ist da falsch.



  • Steffo schrieb:

    Wie gesagt, ich sehe das anders. Dein Beispiel mit den verschiedenen Exe-Dateien mag bei x86 und x64 Architekturen in der Praxis stimmen, aber eine feinere Abstimmung wirst du nicht vorfinden,

    WEIL im fertigen Game nur 1% rauskommt.

    Steffo schrieb:

    deshalb halte ich nicht all zu sehr von zu viel Theoretisierung

    Wir theoretisieren mit diesen künstlichen Test-Programmen. Da kann es schon vorkommen, daß memcpy ohne oder mit SSE gigantisch auseinanderliegen. WÜRDE man ein Programm verkaufen, das so künstlich ist wie unsere Testprogramme, und WÜRDE es einen deutlichen Unterschied machen, dann würde man auch 12 exe auf die DVD tun.

    Steffo schrieb:

    das ist ein beliebtes Mittel von Lobbyisten und Marketing-Leuten, aber nicht von Leuten, die mit beiden Beinen auf dem Boden bleiben.

    Mußt Du mich wirklich jetzt antrollen? Ich dachte, Du hättest Dich vorhin nur von PI reinziehen lassen. Das jetzt ist aber offensiv. Nee, mach das nicht. Wir haben wenig genug Leute, die nachdenken können UND oft nett bleiben. Dich hatte ich als Neuentdeckung im Auge, nachdem PI mich so enttäuscht hat.



  • @volkard: Ganz ruhig, ich wollte dich nicht antrollen. 🙂
    Deine Argumente kann ich nachvollziehen, danke.

    @Pi: Ich habe meine Tests in einer VM gemacht. Keine Ahnung, wie relevant das ist.

    L. G.
    Steffo


Anmelden zum Antworten