Geschwindigkeitstest: Java, dann VB und dann C++
-
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.
-
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?
-
@SeppJ
Oft werden Zeiger im Internet als magische Wundermittel angepriesen.
Ich möchte aber behaupten, dass ich, als Hobbyprogrammierer, ein recht gutes Bild von Computern habe.
Hast du ein Beispiel, wo genau ich Zeiger gewinnbringend einsparen könnte? Nur eines, damit ich den Rest entsprechend anpassen kann.Gemessen habe ich es mit dem Taskmanager und einfach den Wert abgelesen. Ich bin noch den Taskmanager von Windows 7 gewöhnt, in dem für jeden logischen Prozessor ein Diagramm angezeigt wird und nicht eines für alle. Ansonsten wäre mir das aufgefallen.
Java kommt allerdings auch nicht über 30 hinaus.@hustbaer
Das VB von 2006 hat die Möglichkeit nativ kompiliert zu werdenHier ist der gemessene Code:
array ist ein Zeiger vom Typ int, der auf das erste Element eines int Arrays zeigt.long Main::sortList(int elems) { int observedElems = elems; bool swapped; int aid; LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds, Frequency; QueryPerformanceFrequency(&Frequency); QueryPerformanceCounter(&StartingTime); 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); QueryPerformanceCounter(&EndingTime); ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; ElapsedMicroseconds.QuadPart *= 1000000; ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; return (long) ElapsedMicroseconds.QuadPart; }
-
Atlan schrieb:
Hast du ein Beispiel, wo genau ich Zeiger gewinnbringend einsparen könnte? Nur eines, damit ich den Rest entsprechend anpassen kann.
Ein Beispiel wird nicht reichen, wenn du nicht verstehst, wie es richtig geht. Es gibt kein magisches Kochrezept um Java nach C++ zu übersetzen oder um schlechtes C++ in gutes C++ um zu formen. Sonst würde das ja ein Computer machen können.
Ein simples Beispiel hat dir volkard schon gegeben. Und es hat gemacht, dass dein Programm nicht mehr lief, weil die Änderung die Fehler an anderer Stelle aufgedeckt hat.
-
Hast du ein Beispiel, wo genau ich Zeiger gewinnbringend einsparen könnte? Nur eines, damit ich den Rest entsprechend anpassen kann.
entferne im ersten Schritt mal ALLE Zeiger aus deinem Programm und verwende die Container Klassen aus der STL.
Dann alle anderen Tipps aus dem Thread beachten. Wenn es dann noch Performanceprobleme gibt, dann miss (!) mal an welchen Stellen dein Programm langsam ist und überleg dir, warum das so ist.Und ja, mit Zeiger kann man manchmal einiges an Geschwindigkeit rausholen, aber damit fängt man erst an, wenn das Programm mal ordentlich läuft.
Optimiere erstmal mit "C++ Bordmitteln" - sprich mit dem sinnvollen Einsatz der STL.Beispiel:
statt int* longArray nimmst du std::vector<int> longArray
Nicht vergessen ein resize auf die gewünschte Größe im Konstruktor zu machen, damit nur einmalig Speicher angefordert wird. Und dann greifst du mit longArray[index] ganz normal auf die Daten zu, musst dich fortan aber nicht mehr um new und delete kümmern.Ein Klassiker ist auch aus deinem Code:
char* input = new char[1];
Wieso??? Das ist einfach unnötig, außerdem erzeugst du ein Memory Leak.
Das zeigt einfach nur, dass du C++ eben doch noch nicht so gewohnt bist. Das machen nämlich nur Java Programmierer.
Und ganz generell vermischt du C und C++. Warum nicht std::string?
Auch dass du dieses Mini Programm versuchst mittels Klassen zu lösen deutet auf Java Programmierweise hin.
Zwei oder drei kleine "freie" Funktionen hätten gereicht - das könntest du dir auch dubiose Dinge wie new Main() erparen.Kurz gesagt: der Performance-Test zeigt in deinem Fall eher an, mit welchen Sprachen du gut vertraut bist, und mit welchen Sprachen eben noch nicht.
-
Ich habe nun array als Zeiger durch array als normales Array ersetzt und die Laufzeit ist auf 9,5 Sekunden im Standalone Release gesunken.
Wenn ich vector benutze, wird die Laufzeit wieder auf 13 Sekunden angehoben.
Damit bin ich nun auf VB Niveau.Ja ich bin C++ noch nicht gewohnt.
Was ich bisher meine verstanden zu haben: Finger weg von Zeigern, außer du willst optimieren oder sie lassen sich auf keinen Fall vermeiden. Wenn etwas dynamisch sein soll, benutz vector, weil das sich um alles kümmert.