Geschwindigkeitstest: Java, dann VB und dann C++
-
@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?
Ich habe das Programm als Standalone gestartet. Nicht einmal ein Ordner war auf, während des Tests.@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)?@volkard
Ich habe die zufällige Ausgabe (, die nicht mitgemessen wird) eines Wertes aus dem sortierten Array hinzugefügt und tatsächlich ist die Ausführzeit gestiegen, jedoch nur um 0,2 Sekunden von 4,3 auf 4,5.Hier noch mal der gesamte Code. Ich weiß, dass der Startcode nicht der Schönste ist aber er sollte auch keinen Schönheitspreis gewinnen.
C++:
Main.h:#pragma once #include<Windows.h> #include<iostream> #include<string> #include<ctime> #include<Winnt.h> #include<Winbase.h> 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.cpp:
#include "Main.h" 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 LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds, Frequency; //Zeit QueryPerformanceFrequency(&Frequency); // Messung QueryPerformanceCounter(&StartingTime); // 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 QueryPerformanceCounter(&EndingTime); //Zeitmessung ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; //beenden ElapsedMicroseconds.QuadPart *= 1000000; //und ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; //Werte return (long) ElapsedMicroseconds.QuadPart; //verarbeiten } Main::~Main() { } void 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; } }
Java:
Mainclass:import java.util.Scanner; public class Mainclass { public static void main(String[] args) { Scanner scan = new Scanner(System.in); String str; outer: while (true){ str = null; do{ System.out.println("Start speedtest?"); str = scan.nextLine(); if (str.toLowerCase().equals("n")) break outer; } while (!str.toLowerCase().equals("y") && !str.toLowerCase().equals("n")); int elemsAm = 0; boolean rightInput = false; do{ System.out.println("How many elements?"); try{ elemsAm = scan.nextInt(); rightInput = true; }catch (Exception e){ rightInput = false; } } while (!rightInput); rightInput = false; int times = 0; do{ System.out.println("How often?"); try{ times = scan.nextInt(); rightInput = true; } catch(Exception e){ rightInput = false; } }while (!rightInput); System.out.println("Starting speedtest"); new Speedtest(elemsAm, times); } scan.close(); } }
Speedtest.java:
import java.util.ArrayList; public class Speedtest { private int[] array; private ArrayList<Long> list; public Speedtest(int lengthList, int times){ list = new ArrayList<Long>(times); for (int i = 0; i < times; i++){ System.out.println("Initializing list"); initList(lengthList); System.out.println("List initialised"); System.out.println("Starting sorting"); long[] startEnd = sortList(); System.out.println("Sorting finished"); System.out.println("Time: " + (startEnd[1] - startEnd[0])); list.add(startEnd[1] - startEnd[0]); } long result = 0; for (int i = 0; i < list.size(); i++){ result += list.get(i); } System.out.println("Average time in Microseconds: " + (result / times) / 1000); } private void initList(int lengthList){ this.array = new int[lengthList]; for (int i = lengthList - 1; i >= 0; i--){ this.array[i] = i; } } private long[] sortList(){ int observedElems = array.length; boolean swapped = true; int aid; long[] times = new long[] {System.nanoTime() , 0}; do{ swapped = false; for (int i = 1; i < observedElems; i++){ if (array[i - 1] < array[i]){ aid = array[i - 1]; array[i - 1] = array[i]; array[i] = aid; swapped = true; } } observedElems--; } while (swapped); times [1] = System.nanoTime(); return times; } }
-
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?Hier kommt alle paar Monate jemand mit genau dem gleichen Beitrag wie deinem vorbei. Bis jetzt hat sich jedes Mal herausgestellt, dass sie katastrophale Anfängerfehler bei ihren Messungen gemacht haben (Meistens waren es fehlende Compileroptimierungen/Debugeinstellungen. Niemanden interessiert es, wie schnell unoptimierter Code läuft). Eine gesunde Skepsis ist daher angebracht. Da du in deinem ersten Beitrag keinerlei Details genannt hattest, konnte man aber nichts genaueres sagen.
-
@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
-
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.
-
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.
-
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.