Java vs. C. Performance-Vergleich
-
Hallo zusammen,
ich bin in C ein absoluter newbie (und in java nur ein relativer)
und wollte schon mal die beiden Sprachen gegeneinander testen um mich in
hochgepriesener Überlegenheit von C bez. Performance selber zu vergwissern. Dazu ist mir folgender Test eingfallen:Man rufe in einer Schleife rekursive Funktion fak(i) die
zu einem i rekursiv Fakultät berechnet. Das i läuft von 1 bis
10000000 deshalb nimmt man für i > 17 i mod 18 (fak(18) überschreitet schon den Int-Bereich).Zugehöriger Code:
public class testing_stuff { static int fak(int n){ if(n<=1) return 1; if(n==2) return 2; else return n*fak(n-1);} public static void main(String[] args){ long start = System.currentTimeMillis(); for(int i = 2;i<=10000000;i++){ if(i < 18) System.out.println(fak(i)); else System.out.println(fak(i % 18)); } long stop = System.currentTimeMillis(); System.out.println("Verstrichene Zeit in java: " + (stop-start)/1000); } }
#include <stdio.h> #include <conio.h> #include <ctime> int fak(int n){ if(n<=1) return 1; if(n==2) return 2; else return n*fak(n-1); } int main(void) { clock_t start = clock(); for(int i = 2;i<=10000000;i++){ if(i < 18) printf("%d \n",fak(i)); else printf("%d \n",fak( i % 18)); } clock_t stop = clock(); int cpu_time = (stop - start )/CLOCKS_PER_SEC; printf("verstrichene Zeit in C %d",cpu_time); getch(); //warten auf einen Tastendruck return 1; }
Es gibt mit Sicherheit sinvollere Tests und ein Test ist sowieso nie repräsentativ, ABER:
Java braucht 120 sek
C braucht 2449 sek (auf meinem Rechner).Kann mir jemand erklären was da los ist?
Ist C also doch nicht immer schneller als Java oder habe ich in C was falsch gemacht? Es liegen ja schon Welten zwischen den beiden Ergebnissen. Ich benutzte DEV C++ 4.9.9.0Gruss
checkit
-
Die ganze Zeit wird wahrscheinlich in der Ausgabe verpulvert, da hat Java vielleicht eine bessere Routine als C, besser gepuffert für deinen Fall und schon ist der Unterschied da.
Tip: Als (fast) blutiger Anfänger in das sehr filigrane Geschäft der Performancemessung einzusteigen halte ich für wenig zielführend. Vor allem wenn man daraus wertvolle Schlüsse ziehen will.
MfG SideWinder
-
Vielleicht hat sich dein Rechner zu sehr gelangweilt und ist eingeschlafen.
PS: Lass einfach mal die Ausgabe weg.
-
Ohne Optimierungen kompiliert? -O2 -fomit-frame-pointer sollte es bei C schon minestens sein
-
knivil schrieb:
PS: Lass einfach mal die Ausgabe weg.
Wenn der Compiler halbwegs was taugt, kommt dann wahrscheinlich immer annähernd 0 raus
-
knivil schrieb:
PS: Lass einfach mal die Ausgabe weg.
ja, das wirds sein. man muss aber noch die compiler austricksen, damit sie nicht merken, dass sie eigentlich garnix tun müssen und die schleife komplett rausschmeissen.
BTW, java ist in manchen dingen schon überraschend schnell (geworden). wenn ich da nur an die HSQLDB denke (ein DBMS, das komplett in Java geschrieben wurde). aber trotzdem sollte ein gut gemachtes C-programm schneller sein, als ein Java-äquivalent.
-
maximAL schrieb:
knivil schrieb:
PS: Lass einfach mal die Ausgabe weg.
Wenn der Compiler halbwegs was taugt, kommt dann wahrscheinlich immer annähernd 0 raus
Nicht wenn er die Werte alle ausgibt, oder denkst du der berechnet das zur Compile-Time?
MfG SideWinder
-
Nachdem ich aus dem Programm korrektes C gemacht habe (beispielsweise <ctime> gibt es nicht in C - nur C++), habe ich es auch mal ausprobiert. Bei mir läuft das Programm so knapp 4 Sekunden. Allerdings habe ich die Ausgabe nach /dev/null umgeleitet. Offensichtlich sind die restlichen 2445 Sekunden dazu da, die Ausgabe auf dem Bildschirm zu machen.
Das java-Programm braucht bei mir 90,5 Sekunden. Auch mit umgeleiteter Ausgabe.
Gcc liegt in der Version 4.4.1 und java als sun-jdk 1.6.0 vor. Beide Varianten liefen unter Ubuntu 9.10 auf einer 2GHz AMD-CPU.
-
SideWinder schrieb:
maximAL schrieb:
knivil schrieb:
PS: Lass einfach mal die Ausgabe weg.
Wenn der Compiler halbwegs was taugt, kommt dann wahrscheinlich immer annähernd 0 raus
Nicht wenn er die Werte alle ausgibt, oder denkst du der berechnet das zur Compile-Time?
MfG SideWinder
Nochmal lesen?
-
tntnet schrieb:
Bei mir läuft das Programm so knapp 4 Sekunden. Allerdings habe ich die Ausgabe nach /dev/null umgeleitet. Offensichtlich sind die restlichen 2445 Sekunden dazu da, die Ausgabe auf dem Bildschirm zu machen.
wahrscheinlich hast du recht, ich hab die ausgabe gegen folgendes ersetzt:
volatile char *vp; volatile int vi; void dummy (char *p, int i) { vp = p; vi = i; }
^^ in der hoffnung, dass der compiler die schleife nicht rauswirft (was er offenbar nicht tut)
resultat: 3 Sekunden.tntnet schrieb:
Das java-Programm braucht bei mir 90,5 Sekunden. Auch mit umgeleiteter Ausgabe.
dem Java-programm hab ich eine ähnliche funktion untergejubelt:
static volatile int vi; static void dummy (int i) { vi = i; }
und jetzt - gut festhalten - 779 Millisekunden
erklärung? keine ahnung, vielleicht ist der java-compiler schlauer und macht aus der rekusiven fak()-funktion was iteratives.
-
779 ohne VM-Startup oder mit? Evtl. hat der JIT-Compiler auch zur Laufzeit die Sinnlosigkeit erkannt und rausgeworfen? Ist es *fix*, dass er volatile niemals nie optimieren darf in Java?
MfG SideWinder
-
Den C/C++ Code bitte mit VC++ kompilieren, das Resultat ist praktisch immer schneller als MinGW/G++ Erzeugnisse
Gewisse Komplexität vorausgesetzt natürlich.
-
SideWinder schrieb:
779 ohne VM-Startup oder mit?
ohne, ich hab den originalcode genommen, nur System.out.println() gegen dummy() ersetzt.
SideWinder schrieb:
Evtl. hat der JIT-Compiler auch zur Laufzeit die Sinnlosigkeit erkannt und rausgeworfen? Ist es *fix*, dass er volatile niemals nie optimieren darf in Java?
wer weiss? dieses java-zeug ist ja sehr intelligent und macht laufzeitoptimierungen, etc. vielleicht hat es einige abkürzungen genommen (es gibt keinen zweiten thread, der auf die volatile-variable zugreift, also mach' ich mal nix), aber das glaube ich nicht. 'volatile' verhält sich ähnlich wie 'synchronized' oder volatile in C: die variable muss sofort beschrieben, und darf nicht gecached werden. wenn ich die schleife auskommentiere, braucht er 0 ms, also irgendwas wird er schon machen.
Icematix schrieb:
Den C/C++ Code bitte mit VC++ kompilieren, das Resultat ist praktisch immer schneller als MinGW/G++ Erzeugnisse
Gewisse Komplexität vorausgesetzt natürlich.ha, mein fehler. ich hab im debug-mode compiliert. im release-mode (VS 2005) und 'clock' gegen GetTickCount() ersetzt sind es nur noch: 502 Millisekunden
ok, die welt ist wieder in ordnung: C ist etwas schneller. uff, ich hab' schon 'nen schreck gekriegt.
-
Also bei mir sieht es mit dummy Funktionen so aus:
MmingW 4.2.1 (64 Bit): 232 ms
Java 1.6 (32 Bit): 254-262 ms
MmingW 4.2.1 (32 Bit): 268 ms
VC++ 2008 prof (64 Bit): 265-281 ms
VC++ 2008 prof (32 Bit): 327-344 msBei MingW mit -O2 und -fomit-frame-pointer. Bei VC++ mit /O2 /Ot /Oy (Rest belassen wie es war). Sollten also so ca. die gleichen Vorraussetzungen sein.
Java 64 Bit kann ich leider nicht testen.
Die Zeiten schwanken aber deutlich und liegen so nah aneinander das man da kaum genaue Vergleiche ziehen kann.
-
Ein Vergleich von C# vs. Java wäre sinnvoller.
Ich tippe mal, das Java C# Sharp um Längen wegfegen wird.
-
Solche Microbenchmarks sind doch sinnlos. Erstrecht wenn man sie so stümperhaft ausführt :).
Aber wenn schon, dann http://shootout.alioth.debian.org/u64/benchmark.php?test=all&lang=all
-
SideWinder schrieb:
[...] Ist es *fix*, dass er volatile niemals nie optimieren darf in Java?
Nö, steht nirgendwo das er das nicht darf. Volatile wird eigentlich auch nur
für Multithreading verwendet und dort muss dann garantiert sein das die als
volatile gekennzeichnete Variable für alle Threads sichtbar ist und einen
konsistenten Wert enthält. Kann gut sein, das wenn die Variable nur im main-
Thread deklariert ist und nirgendwo anders verwendet wird, der Compiler das
wegoptimiert.Java-Programme kann man im Allgemeinen nicht so benchmarken wie C-Programme.
Die ersten drei einfachen Sachen sind zuerst mit dem javac und optimize flag
kompilieren. Eclipse hat z.B. seinen eigenen Builder.
Die JVM mit -server starten, für eine noch strengere Codeoptimierung während
der Laufzeit.
Und als dritte Maßnahme nie benchmarken ohne Warm-up (ein paar Minuten), damit
der dynamische Compiler eine Chance hat VOR dem eigentlichen Benchmark zu
optimieren oder gar Code in nativen Maschinencode umzuwandeln und nicht während
des Benchmarks.
Desweiteren muss man auch schauen was der GC so treibt und vielleicht den
Speicher erhöhen damit er nicht während des Benchmarks aktiv wird.Das größte Problem beim benchmarken ist sowieso zu verhindern das der
Benchmarkcode als "toter Code" erkannt wird.
-
rüdiger schrieb:
Solche Microbenchmarks sind doch sinnlos. Erstrecht wenn man sie so stümperhaft ausführt.
garnicht, die zeigen zumindest, dass der zeitliche unterschied bei reiner codeausführung zwischen Java und C viel kleiner ist, als die meisten glauben. C ist zwar schneller, aber nicht viel. (die von dir verlinkte seite zeigt das ja auch).
-
garnicht ... zwischen Java und C viel kleiner ... verlinkte seite zeigt das ja auch
Mir zeigt diese Seite in erster Linie, dass Java im Vergleich zu C++ abkackt.
-
und...wtf im Vergleich zu Haskell!
Das hätte ich ja nie gedacht. Krasse Sache das.