Geschwindigkeitstest: Java, dann VB und dann C++



  • @SeppJ
    Wie kann ich diese Fehler denn überprüfen und ggf. beseitigen?
    Das hier alle paar Monate jemand vorbeikommt wusste ich nicht. Ich bin hier zum ersten Mal seit 2 Jahren online.
    Dann kann ich auch gleich die erwünschten Details posten.

    Gruß
    Atlan


  • Mod

    Atlan schrieb:

    @SeppJ
    Wie kann ich diese Fehler denn überprüfen und ggf. beseitigen?

    Indem du genau und nachvollziehbar beschreibst, was du gemacht hast. Was du mittlerweile ja auch getan hast.

    Ich persönlich habe bloß keine Lust, mir dein Codemonstrum anzutun, daher halte ich mich inhaltlich aus dem Thread raus.



  • Ich habs mal für gcc compilierbar gemacht.

    #include <iostream>
    #include <ctime>
    #include <cstring>
    using namespace std;
    
    class Main
    {
    public:
        Main(int, int);
        ~Main();
    private:
        void initArray(int elems);
        long sortList(int);
        bool run;
        //long* longArray;
        int* longArray;
    };
    
    Main::Main(int times, int elems)
    {
        long* timesEach = new long[times];
        long calcAid = 0;
        cout << "Total times speedtest will run: " << times << endl;
        for (int i = 0; i < times; i++) {
            cout << "Time " << i << " out of " << times << endl;
            cout << "Initializing List" << endl;
            initArray(elems);
            cout << "Finished initializing. List has " << elems << " elements" << endl;
            cout << "Starting sorting" << endl;
            timesEach[i] = sortList(elems);
        }
    
        for (int i = 0; i < times; i++) {
            calcAid += timesEach[i];
        }
        delete timesEach;
    
        //double result = (double)((double)calcAid / (double)times) / CLOCKS_PER_SEC;
        double result = (double)((double)calcAid / (double)times);
    
        cout << "Average time taken for sorting process in Microseconds: " << result << endl;
    }
    
    long Main::sortList(int elems) {
        int observedElems = elems; //noch zu behandelnde Objekte
        bool swapped;   //wurde schon gewechselt? Muss nicht initialisiert werden, da in do-while Schleife erledigt
        int aid;    //Hilfsvariable zum Tauschen der Werte
    
        time_t StartingTime, EndingTime, ElapsedMicroseconds; //Zeit
        StartingTime=clock();                                 //      starten
    
        do {//do-while-Schleife: Wird mindestens ein mal ausgeführt, aber nur so oft wiederholt, wie die Bedingung stimmt
            swapped = false;    //wahrheitsgemäß. Es wurde noch nicht getauscht
            for (int i = 1; i < observedElems; i++) {   //for-Schleife durchäuft Array von 1 bis observedElems - 1
                if (longArray[i - 1] < longArray[i]) {  //wenn der Wert an der Stelle i - 1 größer ist, als an Stelle i
                    aid = longArray[i - 1]; //der Wert von longArray an Ort i - 1 wird in aid geschrieben
                    longArray[i - 1] = longArray[i]; //der Wert an Stelle i wird an Stelle i - 1 geschrieben
                    longArray[i] = aid; //der Wert von aid wird an Stelle i geschrieben
                    swapped = true; //wahrheitsgemäß. Es wurde getauscht
                }
            }
            observedElems--;    //das gerade eingefügte Element muss nicht mehr überprüft werden; observedElems um einen decrementieren
        } while (swapped);//Bediungung der do-while-Schleife
    
        EndingTime=clock();                                       //Zeitmessung
        ElapsedMicroseconds = (EndingTime-StartingTime)/(double(CLOCKS_PER_SEC)/1000);
        return (long) ElapsedMicroseconds;                                     //verarbeiten
    }
    
    Main::~Main()
    {
    }
    
    int main(int count, char** args) {
        char* input = new char[1];
        int howOften;
        int elems;
    
        do {
            cout << "Start speedtest?[Y/N]" << endl;
            cin.getline(input, 2);
    
            if (strcmp(input, "y") == 0 || strcmp(input, "Y") == 0) {
                break;
            }
            else if (strcmp(input, "n") == 0 || strcmp(input, "N") == 0) {
                exit(0);
            }
        } while (true);
    
        input = new char[20];
    
        do {
            cout << "How often?" << endl;
            cin.getline(input, 20);
            howOften = atoi(input);
        } while (howOften == 0);
    
        do {
            cout << "How many elements?" << endl;
            cin.getline(input, 20);
            elems = atoi(input);
        } while (elems == 0);
    
        new Main(howOften, elems);
    
        cin.getline(input, 2);
    
    }
    
    void Main::initArray(int elems) {
        delete this->longArray;
        this->longArray = new int[elems];
    
        for (int i = elems - 1; i >= 0; i--) {
            this->longArray[i] = i;
        }
    }
    

    Dann die lästigen Abfragen aus der main() rausgemacht.

    int main() {
        new Main(5,100000);
    }
    

    Ausgabe

    Total times speedtest will run: 5
    Time 0 out of 5
    Initializing List
    Finished initializing. List has 100000 elements
    Starting sorting
    Time 1 out of 5
    Initializing List
    Finished initializing. List has 100000 elements
    Starting sorting
    Time 2 out of 5
    Initializing List
    Finished initializing. List has 100000 elements
    Starting sorting
    Time 3 out of 5
    Initializing List
    Finished initializing. List has 100000 elements
    Starting sorting
    Time 4 out of 5
    Initializing List
    Finished initializing. List has 100000 elements
    Starting sorting
    Average time taken for sorting process in Microseconds: 8506.4
    

    Ok, 8500ms. Mal an den Code gehen und die schlimmsten Sachen normalisieren.

    int main() {
        Main(5,100000);
    }
    

    Ausgabe

    Total times speedtest will run: 5
    Time 0 out of 5
    Initializing List
    *** Error in `/home/…/bin/Release/tmpcpp': munmap_chunk(): invalid pointer: 0x0000000000400ba0 ***
    ======= Backtrace: =========
    /lib64/libc.so.6(+0x726b3)[0x7f618f1cd6b3]
    /lib64/libc.so.6(+0x77fa6)[0x7f618f1d2fa6]
    /home/…/bin/Release/tmpcpp[0x400f45]
    /home/…/bin/Release/tmpcpp[0x400b46]
    /lib64/libc.so.6(__libc_start_main+0xf0)[0x7f618f17b630]
    /home/…/bin/Release/tmpcpp[0x400bc9]
    

    Das ist natürlich keine Basis für Vergleiche.



  • Atlan schrieb:

    @Martog
    Das es die Optimizer gibt, wusste ich aber ich wäre vom Gegenteil ausgegangen, dass die eher komplizierte Dinge optimieren können und nicht solche eher einfachen Dinge.
    Mit der Optimierung hast du Recht.
    Also wäre es noch einmal interessant eine verkettete Liste zu sortieren? Oder etwas mit vielen Methodenaufrufen (rekursiv einen Baum durchlaufen)?

    kannst du machen, aber auch dabei wirst du nichts aussagekraeftiges herausbekommen. Nach meiner Meinung ist es am besten, ein richtiges, wartbares Programm in jeder Sprache einmal zu schreiben und dabei auch die relevanten Sprachfeatures zu nutzen, also nicht einfach nur abzuschreiben, und dann verschiedene Teile zu "benchmarken".



  • Atlan schrieb:

    @Martog
    Das es die Optimizer gibt, wusste ich aber ich wäre vom Gegenteil ausgegangen, dass die eher komplizierte Dinge optimieren können und nicht solche eher einfachen Dinge.
    Mit der Optimierung hast du Recht.

    Also mach die alle Optimierungen an und schau dann nochmal.
    Bei mir hüpft dann die Zeit von 26000ms auf 7700ms.

    Atlan schrieb:

    Also wäre es noch einmal interessant eine verkettete Liste zu sortieren? Oder etwas mit vielen Methodenaufrufen (rekursiv einen Baum durchlaufen)?

    Weder noch. Verkettete Listen sortiert man eh nicht. Rekursiv einen Baum zu durchlaufen testet auch nur die RAM-Geschwindigkeit, das Methodenaufrufen ist im Vergleich zu billig.



  • @volkard
    Was meinst du mit normalisieren?
    Wo der Fehler mit dem Pointer herkommt, kann ich mir nicht erklären. Eigentlich müsste alles beschützt sein und keine AccessViolations oder sonstige unzulässigen Zugriffe versucht werden.

    @Marthog
    Was könnte man da denn nehmen? Den Huffman Code?

    @volkard
    Ich habe alle Einstellungen eingestellt, die ich gefunden habe.
    Wo finde ich die Optimierungen denn? Vielleicht habe ich ein paar übersehen.



  • Atlan schrieb:

    Wo der Fehler mit dem Pointer herkommt, kann ich mir nicht erklären.

    Von den Pointern. Genauer: Der Benutzung von new[] für dynamische int Arrays, anstatt vernünftig RAII Wrapper wie std::vector oder von mir auch aus std::unique_ptr<int[]> zu benutzen.

    Eigentlich müsste alles beschützt sein und keine AccessViolations oder sonstige unzulässigen Zugriffe versucht werden.

    Und wieso löscht dann init-Array als erstes das Array (noch dazu mit delete, was falsch ist), ohne irgendwie zu überprüfen, ob bereits eins erstellt wurde? (was beim ersten Mal nicht der Fall ist).
    Mit der Verwendung von RAII Wrappern wäre das nicht passiert.



  • Atlan schrieb:

    Wo der Fehler mit dem Pointer herkommt, kann ich mir nicht erklären. Eigentlich müsste alles beschützt sein und keine AccessViolations oder sonstige unzulässigen Zugriffe versucht werden.

    Kommt wahrscheinlich hier her:

    delete this->longArray;
    

    Dein longArray wird nirgendwo initialisiert und du versuchst so irgendeinen zufälligen Speicherbereich zu löschen.



  • ...und da bei dir wohl Speicher auf dem Heap ausgenullt wird, bei Stack aber nicht und da ein delete auf einen nullptr keine Auswirkung hatt.



  • Atlan schrieb:

    @Mechanics
    Meinst du, du zweifelst meine Glaubwürdigkeit an? Ich glaube das ja auch nicht aber diese Zahlen standen auf meinem Bildschirm.
    Was für Faktoren meinst du?

    Wurden doch schon genügend genannt. Fängt mit so simplen Sachen wie Debug oder Release an, nichts davon stand in deinem ersten Beitrag.



  • @Nathan
    Ich wollte ja gerade keine Wrapper oder API benutzen, weil ich die Sprache und nicht die API oder die Programmierer der API testen wollte.

    Das beim ersten Mal kein Array erzeugt wurde, wusste ich. Ich bin aber davon ausgegangen, dass delete erkennt, dass noch nichts allokiert wurde und deshalb auch nichts tut.

    Das mit delete[] wusste ich nicht. Es ist ca. 2 Jahre her, dass ich das letzte Mal etwas mit C++ gemacht habe und ich hatte nur noch delete im,Kopf und da delete den Speicherüberlauf gelöst hat, habe ich mich damit nicht mehr beschäftigt.

    @Mechanics
    Ich habe es für selbstverständlich gehalten, dass man nicht die Debug Version in der IDE laufen lässt, sondern die Release Version als Standalone.

    Welcher Test würde denn Sinn machen? Huffman?
    Und wo finde ich die ganzen Optimierungen? Ich habe in den Properties unter Optimization geguckt und dort alles zugunsten der Geschwindigkeit verstellt. Gibt es noch andere Orte?



  • Atlan schrieb:

    Das beim ersten Mal kein Array erzeugt wurde, wusste ich. Ich bin aber davon ausgegangen, dass delete erkennt, dass noch nichts allokiert wurde und deshalb auch nichts tut.

    Delete erkennt genau gar nichts. Delete wird versuchen alles zu löschen was man ihm gibt. Einzige Außnahme: Ein NULL Pointer. Das wäre auch die Möglichkeit wie du deinen Bug beheben kannst. Du musst dafür sorgen das dein Pointer NULL ist bevor du erste mal initArray aufrufst.


  • Mod

    sebi707 schrieb:

    Atlan schrieb:

    Das beim ersten Mal kein Array erzeugt wurde, wusste ich. Ich bin aber davon ausgegangen, dass delete erkennt, dass noch nichts allokiert wurde und deshalb auch nichts tut.

    Delete erkennt genau gar nichts. Delete wird versuchen alles zu löschen was man ihm gibt. Einzige Außnahme: Ein NULL Pointer. Das wäre auch die Möglichkeit wie du deinen Bug beheben kannst. Du musst dafür sorgen das dein Pointer NULL ist bevor du erste mal initArray aufrufst.

    Besser wäre es natürlich, die Speicherverwaltung stattdessen richtig zu machen, wie es vorgesehen ist, anstatt an den Symptomen herum zu basteln. In diesem Fall also möglichst alles als automatische Variable und die Teile, die dynamisch sein müssen, mit vernünftigen Ressourcenhalterklassen umsetzen, anstatt das selber schlecht zurecht zu pfuschen. Teil der Stärke oder Schwäche einer Sprache ist auch, welche Möglichkeiten man hat und wie man diese nutzt. Wenn man C++ so programmiert, als wäre es Java, dann ist es selbstverständlich, dass man man einen schlechten Java-Ersatz bekommt.



  • Atlan schrieb:

    @Mechanics
    Ich habe es für selbstverständlich gehalten, dass man nicht die Debug Version in der IDE laufen lässt, sondern die Release Version als Standalone.

    Selbstverständlich ist hier gar nichts 😉 Ich fang jetzt nicht davon an, dass man Daten, die man mit new[] anlegt, selbstverständlich auch mit delete[] löscht. Und dass beim Start über VS auch im Release Modus ein Debug Allocator verwendet wird, habe ich selber auch erst vor paar Jahren herausgefunden. Und hier im Forum haben wir sowieso schon alles mögliche gesehen. Ich kann mich noch an einen erinnern, der meinte, er hätte eine bahnbrechende Methode gefunden, Speicher zu sparen und hat eine String Klasse geschrieben, die glaub ständig mit new und delete irgendeine Implementierungsklasse erstellt hat, und er hat geglaubt, dadurch muss nicht mehr für jede String Instanz der ganze Code im Speicher gehalten werden und sowieso ist seine Idee genial und wollte sich davon auch nicht abbringen lassen.



  • Ich habe übrigens gerade mal beide Varianten getestet mit verschieden vielen Objekten. Dabei waren immer beide Varianten ziemlich genau gleich schnell. Könnte aber sein das ich mit der Java Version Mist gebaut habe, da ich mich mit Java überhaupt nicht auskenne. Ich denke aber das Program ist zu einfach und die Geschwindigkeit wird durch CPU Cache und RAM begrenzt.



  • @sebi707
    Ich habe jetzt alles angepasst. Für mich hat sich nichts geändert, weil alles schon vorher lief aber danke für den Tipp. Auch an dich @roflo. Wird mir bestimmt noch mal viel Sucherei ersparen.

    Was wäre denn ein guter Test? Der Huffman Code? Ein 3D Plotter?

    @SeppJ
    Auf die API habe ich bewusst verzichtet, weil ich nicht die API, sondern die reine Geschwindigkeit der Sprache testen wollte. Ansonsten wüsste ich nicht, wie ich Sprachfeatures gewinnbringend einbauen könnte. Bestimmt geht etwas mit Zeigern aber so genau kenne ich mich da nicht aus.
    Die CPU Auslastung des Programmes liegt bei mir ca. bei 24%. Ich könnte noch einmal nach etwas suchen, was knapp 100% braucht und damit den Test wiederholen.
    Oder was wäre denn ein guter Test? Der Huffman Code? Ein 3D Plotter?

    @Mechanics
    Ich komme aus dem Java-Forum und dort gibt es dieselben Querulanten. Unter anderem auch Whitehat Hacker, die einen Grafikhack für ein Spiel geschrieben haben, aber nichts mit der Fehlermeldung "Method X not applicable for argument type y. z expected"
    Trotzdem gehe ich immer vom Guten aus.

    Ich habe nun alle Optimierungen reingetan, die ich gefunden habe und die Laufzeit hat sich tatsächlich veringert. Aber nur um 0,3 Sekunden.


  • Mod

    Atlan schrieb:

    @SeppJ
    Auf die API habe ich bewusst verzichtet, weil ich nicht die API, sondern die reine Geschwindigkeit der Sprache testen wollte. Ansonsten wüsste ich nicht, wie ich Sprachfeatures gewinnbringend einbauen könnte. Bestimmt geht etwas mit Zeigern aber so genau kenne ich mich da nicht aus.

    Ich meine nicht die API, sondern die Sprachfeatures. Und mit Zeigern geht da wahrscheinlich nichts, das Problem ist nämlich im Gegenteil, dass du überall Zeiger benutzt (so wie in Java), obwohl das gar nicht nötig wäre. Einer der großen Vorteile von C++ ist doch gerade, dass man nicht andauernd überflüssige Indirektionen aufgebrummt bekommt. So wie du Zeiger hier als magisches Wundermittel beschreibst, scheinst du sehr merkwürdige Vorstellungen davon zu haben, wie Computer funktionieren.

    Die CPU Auslastung des Programmes liegt bei mir ca. bei 24%.

    Das ist schwer zu glauben. Du machst etwas sehr, sehr falsch oder du misst nicht richtig oder du interpretierst deine Messergebnisse falsch. Und falls deine 24% doch korrekt sein sollten, dann zeigt das, dass du irgendetwas anderes gemessen hast, was irgendwie das Programm blockiert.



  • SeppJ schrieb:

    Das ist schwer zu glauben. Du machst etwas sehr, sehr falsch oder du misst nicht richtig oder du interpretierst deine Messergebnisse falsch.

    Wieso, hört sich so an, als ob er vier Kerne hätte und einer davon ist zu 100% ausgelastet.


  • Mod

    Mechanics schrieb:

    SeppJ schrieb:

    Das ist schwer zu glauben. Du machst etwas sehr, sehr falsch oder du misst nicht richtig oder du interpretierst deine Messergebnisse falsch.

    Wieso, hört sich so an, als ob er vier Kerne hätte und einer davon ist zu 100% ausgelastet.

    Psst! Das ist auch mein Verdacht. Aber ich wollte es nicht so direkt sagen. Ich hatte die Hoffnung, dass er die Gültigkeit seiner Messmethoden hinterfragt.



  • Vielleicht testet er mit ner Quad-Core CPU.
    Anzeige von 24,irgendwas% im Task-Manager wäre dann ganz normal.
    EDIT: OK, für den Teil war ich zu langsam. 🙂 /EDIT

    Und ich könnte mir schon vorstellen dass Java hier etwa gleich schnell ist wie C++, vielleicht sogar ne Spur schneller. Zumindest wenn die C++ Version nicht auf genau die CPU hin optimiert ist auf der sie läuft. Denn der Java JIT Compiler wird das vermutlich machen, also Code erstellen für genau die CPU auf der das Programm gerade läuft.

    Was ich mir aber kaum vorstellen kann ist dass VB hier irgendwie mithalten kann. Wie soll das gehen, VB (ohne .NET) ist doch rein interpretiert? Oder gibt's da auch "echte" Compiler dafür? Oder ist eh VB .NET gemeint?


Anmelden zum Antworten