[Perfromance Benchmark] Java - C++



  • @borg: Dann schreib doch mal so einen GUI-Test. Nicht nur dich interessiert das Ergebnis. Allerdings ist es nicht ganz leicht, so einen Test zu schreiben. Rate mal, warum man nirgendwo einen findet.



  • hmm. ja, komische messung.
    noch ne zeitmessung ins programm eingebaut:

    #include <iostream> 
    #include <string> 
    using namespace std; 
    
    int main(int argc, char *argv[]) 
    { 
      clock_t start=clock();
      int i, n = ((argc == 2) ? atoi(argv[1]) : 10000000); 
      string str; 
      size_t capacity = 31; 
      str.reserve(capacity); // as per C-string 
      size_t newLength = 6; 
      for (i = 0; i < n; i++) 
      { 
        if(newLength > capacity) 
        { 
          capacity *= 2; 
          str.reserve(capacity); 
        } 
        str += "hello\n"; 
        newLength += 6; 
      } 
      cout << str.length() << endl; 
      cout<<(clock()-start)/double(CLOCKS_PER_SEC)<<" sec"<<endl;
      return 0; 
    }
    

    ergibt bei mir
    8.722 sec

    jetzt mal den vorschlag nehmen, zu vermuten, daß std::string den trick mit capacity eh schon selber kann:

    int main(int argc, char *argv[]) 
    { 
    	clock_t start=clock();
      int i, n = ((argc == 2) ? atoi(argv[1]) : 10000000); 
      string str; 
      for (i = 0; i < n; i++) 
        str += "hello\n"; 
      cout << str.length() << endl; 
    	cout<<(clock()-start)/double(CLOCKS_PER_SEC)<<" sec"<<endl;
      return 0; 
    }
    

    7.97 sec

    aha. also schon richtig, daß der tester c++ nicht wie seine westentasche kannte.

    mal schauen, wieviel es bringt, noch nen string zu nehmen.
    6.97 sec.

    int main(int argc, char *argv[]) 
    { 
    	clock_t start=clock();
    	int i, n = ((argc == 2) ? atoi(argv[1]) : 10000000); 
    	string hello="hallo\n";
    	string str; 
    	for (i = 0; i < n; i++) 
    		str += hello; 
    	cout << str.length() << endl; 
    	cout<<(clock()-start)/double(CLOCKS_PER_SEC)<<" sec"<<endl;
    	return 0; 
    }
    

    und dann kam noch das argument "da wr ja eigentlich wissen, was wir wollen, können wir auch gleich das ergebnis erzeugen".

    string hello="hallo\n";
    	string str;
    	str.reserve(hello.size()*n);
    	for (i = 0; i < n; i++) 
    		str += hello; 
    	cout << str.length() << endl;
    

    6.04 sec

    oder gemeinerweise

    string hello="hallo\n";
    	string str;
    	str.reserve(hello.size()*n);
    /*	for (i = 0; i < n; i++) 
    		str += hello; */
    	cout << str.length() << endl;
    

    0 sec!

    ok, man wird behaupten, das gelte nicht. ist aber an sich kacke, was zu messen, was man nie scheiben würde. mal mit gewalt bei += bleiben und die anzahl der aufrufe ein klein wenig senken.

    string hello="hallo\n";
    	string str;
    	while(n!=0){
    		while(n%2==0){
    			n/=2;
    			hello+=hello;
    		}
    		--n;
    		str+=hello;
    	}
    

    2.62 sec

    mal den code von Ponto auf meiner maschine messen.

    char hallo[] = "Hallo\n"; 
    int const size = strlen(hallo); 
    string str(size * n, 0); 
    std::string::iterator iter = str.begin(); 
    for ( int i=0; i != n; ++i ) { 
       for (int j = 0; j != size; ++j) { 
          *iter = hallo[j]; 
          ++iter; 
       } 
    }
    

    1.98 sec

    naja, in dieser richtung könnte man weitermachen, zum beispiel

    char const hallo[]="Hallo\n";
    	int const size=strlen(hallo);
    	string str(n*size,0);
    	int const bigSize=sizeof(int)*size;
    	int* bigHallo=new int[size];
    	{
    		string bigHalloStr;
    		for(size_t i=0;i<sizeof(int);++i)
    			bigHalloStr+=hallo;
    		memcpy(bigHallo,&*bigHalloStr.begin(),bigSize);
    	}
    	{
    		int* pi=(int*)&*str.begin();
    		while(n>=sizeof(int)){
    			for(int i=0;i<size;++i)
    				*pi++=bigHallo[i];
    			n-=4;
    		}
    		char* pc=(char*)pi;
    		while(n>0){
    			for(int i=0;i<size;++i)
    				*pc++=hallo[i];
    			n-=1;
    		}
    	}
    //	cout<<str<<endl;
    	cout << str.length() << endl;
    

    1.17 sec

    das geht eben in java nicht so fein. man kommt einfach nicht gescheit an die interna ran. nun mag der javaianer sagen, dads sei auch nie notwendig. der kunde kann ja nen schnelleren rechner kaufen. und außerdem dürfe man nur die entwicklungszeit zählen, denn die bezahle man selber, und nie die laufzeit. hab ich alles schon gehört.

    oder man geht in c++ den weg in die andere richtung...

    class MultiString{
    private:
    	string str;
    	int count;
    public:
    	MultiString(string const& _str,int _count):
    	str(_str),
    	count(_count){
    	}
    	int length(){
    		return count*str.length();
    	}
    	//op[]
    	//op<<
    };
    

    0 sec. klar.

    in diesen regionen des abstrahierens kann java auch nicht folgen. hier spielt c++ klar seinen vortiel des zero abstaction overhead aus. mit überladenen operatoren kriegt man die klasse schnell hin, daß sie sich in der anwendung wie ein konstanter string anfühlt. ist die variable n zur compilezeit bekannt, kann man sie als template-parameter benutzen und nochmal sparen. mit ein wenig aufwand kriegt man c++-programme oft viel schneller als mit dem erstbesten ansatz.

    hat man vor, auch ein wenig aufwand zu treiben, um sein programm schnell wie assembler zu machen, ist c++ ganz ok als sprache. will man (oder kann man) das nicht, ist java ganz ok. nur ist es ein fehler, in c++ ein programm zu messen, das einfach mal so hingeschrieben wurde. das sollte man in c++ nicht machen, dafür gibt's andere sprachen.

    gewonnen hat übrigens

    int main(int argc, char *argv[]){ 
    	cout<< ((argc == 2) ? atoi(argv[1]) : 10000000) * (sizeof("Hallo\n")-1)<<'\n';
    }
    


  • @volkard: Mir ist nicht ganz klar, was du mit dem letzten Beispiel sagen willst. So etwas kann ich selbstverständlich auch in Java schreiben. Auch ist mir nicht klar, was das mit

    in diesen regionen des abstrahierens kann java auch nicht folgen. hier spielt c++ klar seinen vortiel des zero abstaction overhead aus.

    zu tun hat. So etwas verursacht in Java mit Sicherheit auch keinen Overhead, der JIT-Compiler kann genauso Methoden inlinen und anderen Overhead sehe ich dort nicht.

    Ungetestet:

    final class MultiString
    {
        public MultiString(String string, int count)
        {
            this.string = string;  // Referenzzuweisung, String ist immutable - effizienter als bei dir
            this.count = count;
        }
    
        public int getLength()    {return string.length() * count;}
        public char charAt(int index)     {return string.charAt(index % string.length());}
    
        public append(PrintStream out)
        {
            for( int i = 0;  i < count;  ++i )
                out.print(string);
        }
    
        private final String string;
        private final int count;
    }
    

    Die anderen Beispiele konnte ich mir jetzt grad vorm Essen nicht mehr ansehen. Aber ich bitte dich mal um eine genauere Erklärung für das letzte. 🙂

    EDIT2: Ich sehe diese aufgezwungene und fest im Gedächtnis verankerte Sprachabhängigkeit irgendwie nie. Das ist doch nur eine Frage des Algorithmus. Sehe ich das richtig, dass der Gag hier doch ist, den String nicht im Speicher zu halten, sondern erst bei der Ausgabe nacheinander auszugeben? Das kann ich doch mit jeder Sprache machen. Wir wissen doch beide, dass das niedere menschliche Wesen vor dem Monitor entscheidend ist.



  • Wenn du den String zusammenbauen willst, kann man dann in Java noch StringBuilder nehmen. Funktioniert genauso wie ein std::vector, man kann am Ende appenden und capacity vorgeben. Im Grunde nur ein Wrapper um ein dynamisches char-Array, auch leicht zum selber schreiben. Man kann diesen StringBuilder auch in Konkatenationen verwenden und in Streams schreiben, das könnte deinem vorletzten Beispiel entsprechen.
    Ich sehe nicht, was man da noch groß einsparen kann.

    Wenn die Größe vorher bekannt ist, kann man auch gleich ein char[] nehmen und mit System.arraycopy() reinkopieren (spart Indexprüfung).
    Dieses char[] kann man dann wie jeden String in Konkatenationen und Ausgaben verwenden.

    Ich könnte IMHO alle deine Beispiele nachbauen und frage mich immer noch, was das mit der verwendeten Sprache zu tun hat. 😕



  • Entwickler schrieb:

    Warum pusht eine Firma wie Oracle Java ohne Ende?
    Warum pusht eine Firma wie IBM Java ohne Ende?
    Warum pusht eine Firma wie SAP Java ohne Ende?
    (alle drei würde ich zu absoluten Riesen im IT Bereich sehen)

    Warum entwickelt MS mit C# ein gegenstück zu Java?
    Warum boomt J2EE ohne Ende?

    Warum pusht eine Firma wie Oracle VMWare, obwohl sie eigentlich kein Geld sparen, da sie kostenlose Linux-Versionen kriegen und nur Windows-Lizenzen erwerben müssen? Die VMWare soll nicht mal andere Prozessor-Typen emulieren!

    Warum pusht eine Firma wie IBM Linux mit 1 Milliarde Dollar, obwohl ihre gesamte Software auf Windows läuft und für Mainframes/Cluster AIX zur Verfügung steht?

    SAP pusht Java, damit MS mit C# kläglich untergeht und SAP nicht aufgekauft wird 🙄

    Nur wenn man die Hintergründe kennt, kann man bestimmte Argumente auch Argumente sein lassen.

    boomt java vielleicht nur, weil scrippt-kiddies schneller guis/"applets" schreiben können, als in c++? das klingt vielleicht nach einem totschlagargument, aber ich habe noch nie ein c++-einsteiger tut/buch gesehen, das einen gleich in gui-programmierung einführt, ganz im gegensatz zu java. und auch sonst hört man ja öfters, das gui mit java leichter sei...

    mfg



  • Was ist daraus geworden?

    Java hat im Webservices Bereich ziemlich alle anderen verdrängt, obwohl es langsamer ist als C oder C++! Warum? Es ist einfacher und die Firma spart Geld!

    IBM stellt die gesamte Lotus/Domino Struktur auf Java um(Workplace). Warum? Weil die Kunden es wahrscheinlich möchten.

    Oracle und SAP weiß ich nicht.

    terraner schrieb:

    java. und auch sonst hört man ja öfters, das gui mit java leichter sei...

    Und genau darum werden sich diese Sprachen durchsetzen! Warum hat sich PHP gegen C/Perl im CGI Bereich durchgesetzt, obwohl es langsamer war/ist? Es ist einfacher und jeder kann es!

    Warum hat sich Windows damals gegen Unix durchgesetzt? Es wurde anfangs von Guru's auch nicht für voll genommen, was ist daraus geworden?



  • Optimizer schrieb:

    So etwas kann ich selbstverständlich auch in Java schreiben.

    ups, hab ich verpasst, daß operator overloading eingeführt wurde? wenn das der fall ist, kann man sich natürlich klassen schreiben, die man dann auch benutzen mag. oder man könnte auch die operatoren für die eingebauten typen wegmachen.

    So etwas verursacht in Java mit Sicherheit auch keinen Overhead, der JIT-Compiler kann genauso Methoden inlinen und anderen Overhead sehe ich dort nicht.

    kann sein. aber ich traue das java nicht fehlerfrei zu.

    und das letzte beispiel verdeutlicht einfach nur die schlechtheit des tests. solche tests fordern doch nur herauf, daß man die compiler umstrickt, sodaß sie genau die testfälle erkennen und wegoptimieren.



  • Hallo,

    wenn man die Aussage des Benchmarks, daß Java bei einigen Aufgaben schneller als C++ bzw. schneller als von üblichen C++ Compilern produzierter Code ist, entkräften möchte, dann sollte man vielleicht nicht gerade einen Teilbenchmark optimieren, bei dem C++ sowieso schneller ist. Es sollten eher die optimiert werden, bei denen die C++ Version langsamer ist.



  • Damit dürfte Java schnell genug sein... Passt auch zum Thema IBM und Java 😉

    http://www.heise.de/newsticker/meldung/46362

    Irgendwann vielleicht auch erschwinglich für kleinere Firmen 🙂



  • volkard schrieb:

    Optimizer schrieb:

    So etwas kann ich selbstverständlich auch in Java schreiben.

    ups, hab ich verpasst, daß operator overloading eingeführt wurde? wenn das der fall ist, kann man sich natürlich klassen schreiben, die man dann auch benutzen mag. oder man könnte auch die operatoren für die eingebauten typen wegmachen.

    Wenn's dir um Operator-Overloading geht, dann nimm doch C#. Da haste das Gleiche in Grün und mit operator overloading. Aber ich sehe nicht, warum das dann abstrakter oder performanter ist? Denn das war doch das Thema. 😕

    So etwas verursacht in Java mit Sicherheit auch keinen Overhead, der JIT-Compiler kann genauso Methoden inlinen und anderen Overhead sehe ich dort nicht.

    kann sein. aber ich traue das java nicht fehlerfrei zu.

    Hmmmmm. Ich denke, dass du dem Hotspotter einiges zutrauen kannst. Ich würde nicht meine Hand darauf verwetten, dass so ne Methode beim ersten Kompilieren geinlined wird. Das Problem ist, dass nicht-statische und nicht-private Methode erstmal als virtuell gelten.
    Aber wenn der Hotspotter sogar Variablen erkennt, die ihren Wert nicht mehr ändern, sie fest einkompiliert und dann die Stelle neu kompiliert, wenn sich der Wert nach 93846 Jahren doch geändert hat, dann darfst du ihm inlinen zutrauen, würde ich sagen.

    und das letzte beispiel verdeutlicht einfach nur die schlechtheit des tests. solche tests fordern doch nur herauf, daß man die compiler umstrickt, sodaß sie genau die testfälle erkennen und wegoptimieren.

    Von dem Benchmark halte ich genauso wenig wie du. Ich habe mich nur gewundert, warum dass deiner Meinung in Java nicht möglich sein soll. Gerade Optimierungen auf Algorithmenebene (und das war das doch) sind doch in nahezu jeder Sprache umsetzbar.
    Das ist doch so schön. Jeder darf in der Sprache coden, die ihm genehmer ist und ungefähr auf die gleiche Performance kann er doch noch kommen. Ein HashSet ist und bleibt ein HashSet, auch wenn's in Java gecodet ist. 🙂

    Dann gibt's halt Dinge, wo man in C++ mehr Möglichkeiten hat. Dann gibt's noch Dinge, wo man in C++ mehr Aufwand investieren muss, um die selbe Funktionalität zu erhalten. Dann gibt's sogar Dinge, wo man in C++ mehr Aufwand investieren muss, um die selbe Performance zu erhalten (z.B. Allokatoren). Ist halt immer unterschiedlich, aber am meisten hängt's halt doch vom Programmierer ab.

    Java macht mir halt das Leben leichter und ich kann mehr über meine Algorithmen nachdenken. Weil wenn ich statt

    for( std::vector<Foo*>::const_iterator i = myVector.begin();  i != myVector.end();  ++i )
        (*i)->methode();
    

    folgendes habe:

    for( Foo x : myVector)
        x.methode();
    

    kann ich mich leichter auf's Wesentliche konzentrieren. Das soll jetzt nur als Beispiel dienen und nicht aufzeigen, dass ich mit obigen C++ Code überfordert bin. Aber ich bin halt trotzdem nur ein Mensch.
    Und weil es so viele Menschen auf dieser Welt gibt, gibt es noch andere Sprachen als C++. 😃 👍



  • Java macht mir halt das Leben leichter und ich kann mehr über meine Algorithmen nachdenken. Weil wenn ich statt

    for( std::vector<Foo*>::const_iterator i = myVector.begin(); i != myVector.end(); ++i ) 
    (*i)->methode();
    

    noch nie was von typedef gehört?

    das ist es was mich an java stört. keine operatoren und keine typedefs.
    wieso wurde das eigentlich nicht übernommen? diese beiden dinge erleichtern das leben einem sehr. vieleicht werden wenigstens operatoren mit eingenommen, so wie die templates.

    ich hab mal eine gui gebastelt mit java ( studium ) und ich muss sagen, Java algos sind nicht lahm. leider ist aber swing & co. mehr als lahmarschig. die ganze grafik ist in java sehr langsam. das liegt wohl daran, dass die GUI portabel sein soll und man deswegen noch einen layer über die win-gui legt.



  • DEvent schrieb:

    noch nie was von typedef gehört?

    Nein, ich bin blöd, weißt.
    Dieses Stück Code ist ein repräsentatives Beispiel dafür, dass C++ mir an einigen Stellen einfach zu kaputt ist, was mich ablenkt. Und das betrifft insbesondere auch Templates. Das ist meine Meinung, die ich haben darf.

    das ist es was mich an java stört. keine operatoren und keine typedefs.
    wieso wurde das eigentlich nicht übernommen? diese beiden dinge erleichtern das leben einem sehr. vieleicht werden wenigstens operatoren mit eingenommen, so wie die templates.

    Das ist deine Meinung, die du auch haben darfst. Falls du auf Operatoren in Java ernsthaft hoffst, muss ich dich enttäuschen, die Chance dafür geht gegen absolut 0. Ich finds auch ein bisschen schade, deshalb schwank ich so zwischen Java und C#, welches dafür nicht mal kovariante return-Typen kennt.

    ich hab mal eine gui gebastelt mit java ( studium ) und ich muss sagen, Java algos sind nicht lahm. leider ist aber swing & co. mehr als lahmarschig. die ganze grafik ist in java sehr langsam. das liegt wohl daran, dass die GUI portabel sein soll und man deswegen noch einen layer über die win-gui legt.

    Und wieder etwas, was nichts mit Java zu tun hat. In C++ rufst du WinAPI Funktionen auf. In Java machst du das nicht und beschwerst dich aber dann, anstatt es dort genauso zu machen.
    Ich werde diese Logik nie verstehen. "Hey wenn ich in C++ WinAPI nutze und in Java Swing, dann ist Java voll lahm, man ist das scheiße" *kopfschüttel*



  • Auch C++ kennt foreach...
    Ich denke, das was C++ einfach fehlt ist eine klare Standard Umgebung,
    Java hat das, mag kein Vorteil sein, aber es macht es den Leuten einfach.
    Und, seinen wir ehrlich, im grunde sind Programmierer faul, was
    einfach ist, und jeder versteht wird sich durchsetzen.

    Devil



  • stimmt auf die idee, statt swing direkt die winapi aufzurufen kommt keiner. (also wenn einem die gui wichtiger ist als portabilität). Aber wenn man zB wxWidgets benutzt wird die GUI ja nicht so lahm wie swing. ist das jetzt ein beispiel für die lahmheit von java oder ein beispiel für eine schlechte implementation der swing-entwickler?

    naja in 5 jahren wird das eh keinen unterschied machen...



  • Ich glaube, dass du glaubst, dass Swing ein Wrapper um das Betriebssystem-API ist. Swing wird aber vom Programm selber gemalt, was einiges sicher erklärt 💡 .
    Mit AWT gibts noch nen Wrapper um das Native System, das kann aber natürlich nicht so viel.



  • Optimizer schrieb:

    Dieses Stück Code ist ein repräsentatives Beispiel dafür, dass C++ mir an einigen Stellen einfach zu kaputt ist, was mich ablenkt. Und das betrifft insbesondere auch Templates. Das ist meine Meinung, die ich haben darf.

    Die ist aber ebenso wenig repräsentativ wie dein Beispiel für eine kaputte Sprache.



  • was bitte heist jetzt "wird vom programm selber gemahlt" ?



  • DEvent schrieb:

    leider ist aber swing & co. mehr als lahmarschig. die ganze grafik ist in java sehr langsam.

    Wie lange wohl noch? In 1 oder 2 Javaversionen wird Swing auf OpenGL aufsetzen und kommt damit deutlich näher an die darunterliegende Hardware. Vermutlich ähnlich nah wie die native GUI. Abgesehen davon wird Swing sowieso von Version zu Version deutlich beschleunigt und der Geschwindigkeitsnachteil macht immer weniger aus, weil die Rechner schneller werden. Bei Java tut sich andauernd etwas und die Schwächen werden konsequent, wenn auch nicht ganz so schnell wie sich manche erhoffen, beseitigt. Was tut sich währenddessen bei C++? Jahrelanges Warten auf den nächsten Standard. Ich frage mich, wann die C++ Gemeinde endlich aufwacht und mal einen Zahn zulegt. Wenn der neue Standard so groß ist, dass es 10 Jahre benötigt, ihn festzulegen, dann sollte man doch überlegen, ob man nicht lieber häufiger kleinere Veränderungen vornimmt. Zumal bei so langen Zeitdauern vermutlich viele Dinge, die in den ersten Jahren entschieden wurden, am Schluss längst veraltet sind.



  • for( std::vector<Foo*>::const_iterator i = myVector.begin();  i != myVector.end();  ++i )
        (*i)->methode();
    

    ma schaun, was man da noch vereinfachen kann 🙂

    erstmal das typedef wie bereits gesagt wurde:

    typedef std::vector<Foo*>::const_iterator iterator;
    for(iterator i = myVector.begin();  i != myVector.end();  ++i )
        (*i)->methode();
    

    ok, sieht schon einfacher aus... leider stört mich noch die zusätzliche dereferenzierung von i.

    ok, boost hilft uns da weiter:

    using namespace boost;
    //...
    typedef indirect_iterator<std::vector<Foo*>::const_iterator> iterator;
    for(iterator i = myVector.begin();  i != myVector.end();  ++i )
        i->methode();
    

    ok...durch die typedef ist das doch nicht so schön...

    egal, man kann ja noch das for problemlos wegbekommen:

    #include <boost/lambda/lambda.hpp>
    #include <boost/lambda/bind.hpp>
    
    using namespace boost::lambda;
    //...
    std::for_each(bar.begin(),bar.end(),bind(&Foo::methode,*_1));
    

    najut, so kurz wie die java version is es immernoch nicht, aber wenigtens ein oneliner 😃



  • devil81 schrieb:

    Auch C++ kennt foreach...

    aber kein ernstzunehmendes.

    und java kennt keine enrsatzunehmenden templates. fair ist es nur, zu sagen: c++ hat kein foreach und java hat keine templates.

    Ich denke, das was C++ einfach fehlt ist eine klare Standard Umgebung,
    Java hat das, mag kein Vorteil sein, aber es macht es den Leuten einfach.

    klarer standard ist in c++ genauso da. nur macht c++ den riesen-fehler, nur bis zur konsolen-ausgabe ohne farbe zu gehen. nix bunt, keine threads, nix sockets, keine maus. nix eben. und ein standardisierungskomitee, das schlicht verabsäumt, minor changes rauszubringen.

    edit: ich würde sagen, die standardisierung hat c++ getötet. vielleicht noch zu retten, wenn ganz bald ein standard mit mehr grafik rauskommt.


Anmelden zum Antworten