Gast
#6697215
Rufe die Kommando einfach mal händisch auf:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
|
Anzeige
|
c++ Code langsam
Gast
#6697215
Rufe die Kommando einfach mal händisch auf:
Jo danke, trotzdem komisch das run.sh auf wsl-debian bei mir diverse Macken hat. Ich konnte die Ausführungszeit beim zweiten IO Versuch via seek mit einem 100MB Buffer halbieren. Jetzt schaue ich mal nach fread mit strtok und nachträglicher newline Erkennung.
Gast
#6699066
Ich möchte zu Bedenken geben, dass die Benchmarks evtl. unterschiedliche Ladezeiten des Binaries nicht berücksichtigen. Vielleicht muss die libstdc++ einen Haufen Sachen initialisieren, bevor die main aufgerufen wird. Die Ausgabe von time ist daher vielleicht etwas mit Vorsicht zu genießen. Eine Alternative wäre rdtsc vor/nach Synchronisierungspunkten/barrier, damit die Operationen auch tatsächlich abgeschlossen sind. Wenn man die Dateien aus einem tmpfs läd, sollte der syscall overhead auch deutlich vernachlässigbar klein sein.
Beitrag #6703193 wurde von einem Moderator gelöscht.
Einfach Klasse dieses Testdingens.. Der hans.exe fehlt noch ein arg für Spaltenzahl weil immer 45 oder habe ich das falsche Paket erwischt? Strtok war ja schonmal nicht schlecht, liefert nur falsche Ergebnisse bei leeren Feldern aus.. lol Ich versuche es mal mit strtok_r. Mit fread konnte ich mein Script von 10Sekunden auf 4Sekunden reduzieren. Aber halt nur mit der List.txt. So da habe ich es auch mal geschafft.. eher ein Funproject so umständlich wie das noch wurde.. mit strtok_r und fread.. einziger Nachteil da nicht automatisch gelöst man muss je nach Filegrösse den Buffer der Datei anpassen.. Wenn ich mal Zeit finde mache ich das mit fwrite und buffer.. komischerweise habe ich auch ein Projekt mit 10000 Dateien a 45 Spalten :D
Gast
#6705896
Philipp K. schrieb: > So da habe ich es auch mal geschafft.. eher ein Funproject so > umständlich wie das noch wurde.. Kompiliert unter Windows leider nicht. Da gibt es keine strtok_r() Funktion, und der Code ist ein schlimmes Gemisch aus C und C++, das weder der C noch der C++ Compiler mag. Aber Zeiger auf Zeiger auf FILE habe ich noch nie gesehen, dafür ein Plus für Kreativität. Unter WSL2 Ubuntu geht es durch den gcc Compiler. Aber das Program macht nur eine Endlosschleife, und müllt die Festplatte zu, Nachdem das nodup.txt über 70 GB gross war, Abbruch. Damit hast du erst mal den letzen Platz, mit Abstand! udok schrieb: > Kompiliert unter Windows leider nicht. Da gibt es keine strtok_r() > Funktion #if defined(_WIN32) || defined(_WIN64) /* We are on Windows */ # define strtok_r strtok_s #endif
Gast
#6705958
Ok, danke, war schon etwas frustriert! Mit dem define geht es durch den Compiler. Das list.txt muss genau 100e3 Zeilen sein, ich hatte zum Testen kleinere Daten genommen, und damit die Endlosschleife produziert. Hier die Ergebnisse unter Win10, 100 Bytes / Feld:
Ja sorry, so kompiliert wohl alles überall anders.. ich wollte es halt nur mit strtok ausprobieren.. da scheint dann nur der Dateizugriff die Rolle zu spielen. So siehts bei mir aus.. mit 4MB buffer (anstatt 150 :D) und setvbuf mit 4MB.
Die Zehn Zeilen strtok goodness bieten noch etwas Raum fuer optimierung... ;-)
Gast
#6705996
Philipp K. schrieb: > Ja sorry, so kompiliert wohl alles überall anders.. > > ich wollte es halt nur mit strtok ausprobieren.. da scheint dann nur der > Dateizugriff die Rolle zu spielen. Danke jedenfalls für dein Programm! Mir ist aufgefallen, dass die Ergebnisse für die foobar2 Version heute deutlich schlechter waren, nur 136 MB/sec, die waren schon mal bei über 200 MB/sec. Lösung: Ich habe heute nur mit -O2 compiliert, und nicht mit "-O2 -Oi- -GS-", wie zuletzt. Der MS Compiler schaltet bei -O2 automatisch die intrinsic Funktionen an, und die Compiler eigene memcpy/strcmp ist eine for Schleife, und die ist deutlich langsamer, als die Funktion aus der C Runtime. Damit ist auch Phillips strtok Funktion auch um einiges schneller. Hier also noch ein Update für Win10, 100 Zeichen/Feld, cl 2019, -O2 -Oi- GS-:
Gast
#6706003
Hier das Update für Win10, 1000k Zeilen, 10 Bytes/Feld:
Frank M. schrieb: > Profiler messen Dauer/Anzahl von Funktionsaufrufen. Der nützt Dir gar > nichts innerhalb der while-Schleife. "Measure, don't guess." (Kirk Pepperdine) "Premature optimization is the root of all evil." (Donald E. Knuth) Können wir das Testpackage vielleicht bei GitHub oder so hochladen? :) Und hat jemand eine Idee, wie man eine Julia Variante (https://julialang.org/, fyi, das ist eine relativ neue Sprache, die so einfach wie Python, aber so leistungsfähig wie C sein soll, speziell für "scientific computing") benchmarken könnte? Das Problem ist, dass das Skript bei jedem call in eine neue, frische Shell neu JIT kompiliert wird, was ja irgendwie Quatsch ist. Es gibt ein benchmarking Paket (https://github.com/JuliaCI/BenchmarkTools.jl), aber das läuft nur, wenn man es aus der selben shell mehrfach startet. Das Benchmarking shell skript hier callt das Skript oder die Binary mehrfach und rechnet dann die Zeit aus, richtig? Ja ist komisch.. ich habe trotz 2x Debian-WSL (einmal alter i5m-4Kern und 6Kern neuer i5-9600) total unterschiedliche Rang-Ergebnisse. Ich habe mal eine Datei mit Outputbuffer angehängt.. da kommt nochmal 1/3. (Jedenfalls bei mir). Auf dem LAppy bekomme ich das ./run.sh mit Zeitmessung nicht hin, auf dem Tower lief es sofort.
Gast
#6707045
Noch nicht alles gelesen... Hat schon jemand eine multithreading-Variante mit getrenntem io- und processing-threads skizziert?
Gast
#6707158
Jan K. schrieb: > Können wir das Testpackage vielleicht bei GitHub oder so hochladen? :) > Von mir aus schon, aber die meisten Programme sind nicht von mir... Ich stelle die nächsten Tage die aktuelle Version hier rein. > Und hat jemand eine Idee, wie man eine Julia Variante > (https://julialang.org/, fyi, das ist eine relativ neue Sprache, die so > einfach wie Python, aber so leistungsfähig wie C sein soll, speziell für > "scientific computing") benchmarken könnte? Sollte ja nicht so schwierig sein? Mit Python, Perl, Lua und gawk gehts ja auch, und die Ergebnisse sind sehr gut. Wenn du ein Skript hast, stell es einfach hier rein. > Das Benchmarking shell skript hier callt das Skript oder die Binary > mehrfach und rechnet dann die Zeit aus, richtig? Richtig.
Gast
#6707176
Philipp K. schrieb: > Ja ist komisch.. ich habe trotz 2x Debian-WSL (einmal alter i5m-4Kern > und 6Kern neuer i5-9600) total unterschiedliche Rang-Ergebnisse. > Hast du eventuell noch die WSL Version 1? Die kannst du für grosse Files vergessen. Eventuell sind auch die dynamischen Libs unterschiedlich? Ich trenne Windows und Linux immer strikt. Die Ergebnisse sind eigentlich sehr gut reproduzierbar. Versuche, mal unter Windows oder unter Linux reproduzierbar ordentliche Performance zu bekommen. Die Windows exe laufen bei mir unter Windows auf einem Cygwin/Msys2 Terminal, und die Linux Programme laufen auf einem WSL2 bash Terminal. Sonst hast du unerwartete Effekte, wenn etwa auf grosse Dateien über die Grenze der virtuellen Maschine zugegriffen wird, oder wenn ein Kompatibilitätslayer dazwischen ist. Wenn du hier Ergebnisse postest, dann sortier sie bitte mit "run.sh |sort -k5V", ansonsten kann das keiner Lesen. Und schreibe dazu, was du genau auf welchem System gemacht hast, und wie du compiliert hast. > Ich habe mal eine Datei mit Outputbuffer angehängt.. da kommt nochmal > 1/3. (Jedenfalls bei mir). Wundert mich etwas, 64-512 kByte Buffer ist bei mir das Optimum, drüber fällst du aus dem Cache raus.
Gast
#6707179
Ich nicht schrieb: > Noch nicht alles gelesen... Hat schon jemand eine > multithreading-Variante mit getrenntem io- und processing-threads > skizziert? Es gibt von Roger eine MT Variante. Im Prinzip kannst du das ganze File aufteilen, und jeder Prozessor übernimmt einen Teil. Ich würde das Fass hier aber nicht aufmachen. Das braucht viel Zeit, und so interessant ist das Problem ja dann doch nicht.
Gast
#6707190
Philipp K. schrieb: > Ich habe mal eine Datei mit Outputbuffer angehängt.. da kommt nochmal > 1/3. (Jedenfalls bei mir). Sehe ich hier eher nicht, aber der Speicherverbrauch ist runtergegangen:
Gast
#6707212
Hier noch das Ergebnis sortiert nach Speicherverbrauch (Peak WorkingSet in MB, nur ein Durchlauf):
Python liest das ganze 909 MB File ein einen Rutsch in den Speicher, alle anderen Programme brauchen deutlich weniger RAM. Der Peak WorkingSet sind (glaube ich) shared DLL und privater RAM. Ok. ich habe noch versucht zu optimieren aber strcmp scheint ja schon das schnellste zu sein. Ich wollte noch 3 checks einbauen um strcmp zu umgehen, das war aber eher kontraproduktiv. 1. Doppelte Strings im Array direkt leeren damit strcmp früher aussteigt. 2. Die Stringlängen anhand der vorhandene Pointer vergleichen. 3. Man hat ja einen Pointer für len+1 .. den direkt zum vergleich des letzetn Zeichens nutzen (*Nextsep-1).. Dauert aber alles länger als strcmp direkt durchlaufen zu lassen.. wäre bei großen Feldern interessant. Ich denke mal mit strtok lohnt da ausser vielleicht mmap nichts mehr. udok schrieb: > Sehe ich hier eher nicht, aber der Speicherverbrauch ist runtergegangen: Ich denke mal das lag am fprintf, wieso habe ich eigentlich c und c++ gemischt? Mein Code müsste ja eigentlich gnu99 Konform sein? (Habe davon aber keine Ahnung.) Ich habe jetzt mal fprintf mit fwrite und Buffer optimiert. Sieht jedenfalls bei mir ganz gut aus. Wie kann die Native Version eigentlich schneller sein als die Festplatte, zeigt jedenfalls mein Laptop. Ich benutze nur WSL2 mit aktuellen Updates.
Gast
#6722908
Philipp K. schrieb: > Ich denke mal das lag am fprintf, wieso habe ich eigentlich c und c++ > gemischt? Mein Code müsste ja eigentlich gnu99 Konform sein? (Habe davon > aber keine Ahnung.) Dein Code ist GNU und Linux konform, compiliert aber nicht unter Windows. Ein älterer Compiler als VS2019 hat gleich aufgegeben... Ist eigentlich schade, weil es immer nur Kleinigkeiten sind. Um es nicht noch ein viertes Mal ausbessern zu müssen, habe ich dir die Änderungen angehängt. Ich habe mir rausgenommen, die Einrückungen etwas anzupassen, ich komme damit sonst nicht klar. stpcpy() und strtok_r gibt es nicht, lässt sich aber leicht umgehen.
Gast
#6722917
Hier die Ergebnisse unter Win10, compiliert mit vs2019 -O2 -GS- Ich habe diesmal extra lange Felder mit 500 Bytes genommen, weil das Ergebnis sehr interessant ist. Der Gewinner ist Perl, abgesehen von den optimierten und deutlich aufwendigeren native C Funktionen! Perl dürfte die beste Hash Bibliothek haben, und der Overhead der Skriptsprachen spielt bei so grossen Feldern keine Rolle.
Gast
#6722920
Philipp K. schrieb: > Wie kann die Native Version eigentlich schneller sein als die > Festplatte, zeigt jedenfalls mein Laptop. Ich benutze nur WSL2 mit > aktuellen Updates. Die Festplatte spielt da keine Rolle, weil die Files sowieso im RAM sind. Drum bringt dein Ansatz mit dem supergrossen Buffer auch nicht viel.
Gast
#6722948
Hier noch die Ergebnisse für Linux WSL2: Ein Trauerspiel, wie schlecht die Microsoft Libs sind.
Gast
#6722959
Achso okay, trotzdem witzig das bei mir das Ergebnis mit meinem Ziel übereinstimmt (nativ angenähert). Habe nur den folder kopiert und mein Script eingetragen. Ja mit dem Buffer ist klar, das war nur noch so ein Test Überbleibsel damit ich Blöcke und nicht einzelne Bytes schreibe. Für meine Anwendung Spalten in tausenden Lines zu löschen reicht es allemal. Wieder etwas dazugelernt. Danke. In bash dauert es fast ne halbe Stunde ;)
Gast
#6722979
Philippk_59 schrieb: > Achso okay, trotzdem witzig das bei mir das Ergebnis mit meinem Ziel > übereinstimmt (nativ angenähert). Habe nur den folder kopiert und mein > Script eingetragen. Was anderes mache ich auch nicht, warum sind dein Werte sooo langsam? Lass das ganze doch mal unter Windows laufen. > In bash dauert es fast ne halbe Stunde ;) Kannst du das Skript posten? udok schrieb: >> In bash dauert es fast ne halbe Stunde ;) > Kannst du das Skript posten? Gibt es so noch nicht, ich meinte nur mein Spalten Löschscript das noch zeilen löscht, Daten konvertiert und Dateien umarrangiert.. das dürfte in C schneller gehen. Ich kann es ja mal in Bash umsetzen. udok schrieb: > warum sind dein Werte sooo langsam? Ich finde es geht eigentlich, das ist ja vielleicht sogar AMD/INTEL abhängig.. Mein Laptop ist halt nicht so schnell, der Tower schafft es genau doppelt so schnell bei gleichem Endergebnis. Ich habe noch nie auf Windows kompiliert.. mir ist das ganze zu umständlich. bei Linux arbeite ich nur mit "Nano" und Shell ohne Autoscripts. Gcc, debuggen, und coden alles in der Bash ;) p.s. Onlinegdb nutze ich auch nur wenn ich unterwegs bin um auf die schnelle rumzuspielen. EDIT: Der stpcpy Erstaz für Windows ist aber schon krass .. ein Strlen auf den Buffer beim einfügen von nem Semikolon ist nicht sehr performant. Ode rhabe ich da jetzt einen Denkfehler?
Gast
#6723413
Philipp K. schrieb: > Ich habe noch nie auf Windows kompiliert.. mir ist das ganze zu > umständlich. bei Linux arbeite ich nur mit "Nano" und Shell ohne > Autoscripts. Ist genau so einfach wie unter Linux. Statt gcc rufst du halt cl auf. Du musst nur die Pfade richtig sethen, wie im Skript vs2019.env gezeigt. Wenn die Pfade passen, kannst du auch einfach das Skript build.sh aufrufen. Als Shell verwende ich Mingw, Powershell oder das neue Windows Terminal geht aber sicher genauso, oder auch die bash von WSL2.
Gast
#6723434
Philipp K. schrieb: > EDIT: Der stpcpy Erstaz für Windows ist aber schon krass .. ein Strlen > auf den Buffer beim einfügen von nem Semikolon ist nicht sehr > performant. Ode rhabe ich da jetzt einen Denkfehler?char * > STPCPY (char *dest, const char *src) > { > size_t len = strlen (src); > return memcpy (dest, src, len + 1) + len; > } Meine strpcpy war sowieso falsch, ich dachte die hängt Strings zusammen... Von der Performanceseite ist es egal, memcpy und strlen sind so gut optimiert, das du das nicht merkst. Und Funktionsaufrufe sind auf x64 praktisch gratis. Mit cl -O2 optimiert der compiler das auch weg, nur der Code ist nur mehr halb so schnell, weil die compiler inline Version langsamer als der Funktionsaufruf ist.
Gast
#6723442
Ich habe noch mal bei FreeBSD geschaut, was die für eine stpcpy Funktion haben:
Linux weiss ich nicht, mit den glibc Sourcen komme ich nicht klar.
Gast
#6723626
udok schrieb: > Ich habe noch mal bei FreeBSD geschaut, was die für eine stpcpy > Funktion > haben: > char *stpcpy(char * __restrict to, const char * __restrict from) > { > for (; (*to = *from); ++from, ++to); > return(to); > } > > Linux weiss ich nicht, mit den glibc Sourcen komme ich nicht klar. Ich würde mit ziemlicher Sicherheit sagen, dass das der "allgemeine Fallback" ist. Gängige Compiler ersetzen die Standardfunktionen durch vektorisierte, handoptimierte Varianten für die ausgewählte CPU. Das sieht dann irgendwie so aus https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/strcpy-avx2.S.html oder so https://code.woboq.org/userspace/glibc/sysdeps/arm/armv6/strcpy.S.html Al Fine schrieb: > Gängige Compiler ersetzen die Standardfunktionen durch vektorisierte, > handoptimierte Varianten für die ausgewählte CPU Oder wie ich bei strtok gesehen habe 64 Bit breite Verarbeitung.. mein Denkfehler war das ich ja mit lastconcat den Anfang setze, daher ist das strlen auf das source nicht so heikel. Auf meinen Rechner lässt sich Fread und strtok auf unter 2 Sekunden beschränken..450MB lesen und verarbeiten. Ich habe dann nur das Schreiben optimiert wobei dann nochmal 2-3 Sekunden dazukommen. Also das mindeste müsste ja die Plattenperformance sein. Damit sind meine Zeiten plausibel mit lesen,gebuffertem schreiben beim verarbeiten.. das verarbeiten ohne schreiben könnte ich auf weit unter 1 Sekunde berechnen. udok schrieb: > Linux weiss ich nicht, mit den glibc Sourcen komme ich nicht klar. Ich denke mal das es in Linux bestmöglich gelöst ist, während es Windows einfacher hält. Die ganzen Stringsachen sind in Windows Byteschubbserei, während diese in der Glibc schon besser gelöst sind. Wie z.B. stpcpy das einfach memcpy direkt ausführt.. wenn ich das richtig gesehen habe, scheint die Verarbeitung wenn keine groben Fehler gemacht werden nur wenig Zeit in Anspruch zu nehmen, das es dann eher auf die IO Umsetzung ankommt. Strtok benutzt in der Glibc strspn und strcspn die etwas anders angesetzt sind.. bei Windows ist es vielleicht wieder nur Byteschubbserei wenn man den Sources trauen kann. https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/strspn-c.c.html
Gast
#6727513
Philipp K. schrieb: >> Linux weiss ich nicht, mit den glibc Sourcen komme ich nicht klar. > > Ich denke mal das es in Linux bestmöglich gelöst ist, während es Windows > einfacher hält. Der Satz lässt ja alle Möglichkeiten offen, je nach Definition von bestmöglich :-) Das fängt schon damit an, das Windows einfach andere Ziele hat. Das ist kein OS für Rechenzentren und hohen Datendurchsatz. Für GUIs und Mausschubsen reicht es allemal. Binäre Kompatibilität ist z.B wichtiger als Performance im MS Universum. So hat der stdio File Layer nicht nur eine Schicht wie in Linux, sondern 2-3 Schichten, wo auch die Unix open/read/write/close Funktionen abgebildet werden und verschiedene Konvertierungen gemacht werden. Das kostet halt immer etwas, in der Praxis ist das aber meist nicht so wichtig. > Die ganzen Stringsachen sind in Windows Byteschubbserei, während diese > in der Glibc schon besser gelöst sind. Ich habe dir ein paar Bilder angehängt mit Performance Tests. Die neuere Ucrt hat ein paar ziemlich gut optimierte Funktionen drinnnen. Besser geht fast immer, aber die Systeme nähern sich an. Der MS compiler macht auch sehr kompakten und schnellen Code. Aber fette Binaries und unlesbaren Code und kranke Benutzerkonzepte hast du da wie dort. Früher hattest du mal 5% der heutigen Rechenleistung, aber die Programme waren trotzdem recht schnell. Heute wird die Performance von riesen Ascii Files und Megaframeworks mit superauflösenden Icons aufgefressen, davon hat der Anwender nichts. Das Problem heute ist, das man mit PC Software kein Geld verdienen kann. Es gibt vieles gratis, und daher kein kommerzielles Interesse an guten Programmen. Die SW Industrie sattelt um auf Dienste und/oder Werbung. Ein paar Nischen halten sich noch, aber die werden fast alle in 10 Jahren verschwunden sein. > Wie z.B. stpcpy das einfach memcpy direkt ausführt.. wenn ich das > richtig gesehen habe, scheint die Verarbeitung wenn keine groben Fehler > gemacht werden nur wenig Zeit in Anspruch zu nehmen, das es dann eher > auf die IO Umsetzung ankommt. Wenn die Daten erst mal im 1st Level Cache sind, spielt alles weitere keine grosse Rolle. Dann musst nur mehr schauen, das du möglichst mehrere Bytes auf einmal anschaust (SSE/AVX oder 8-Byte Register), und das du keine Abhängigkeiten zwischen den Daten hast - Eine CPU kann dann bis zu 6 Operation gleichzeitig ausführen. Danke für die tolle Erklärung und den Benchmarks. Irgendwie scheint man nur mit Glibc in Linux einen direkten Vergleich machen zu können. In MingW ist zum Beispiel strtok auch nur eine Hilfe nicht direkt mit Bytes arbeiten zu müssen, dort wird mit Schleifen und Char ohne andere Funktionen gearbeitet. Also im Prinzip kein Vergleich möglich. Denke aber auch das es bei den heutigen Rechenleistungen und SSD Performance irgendwie keine Rolle spielt für die Privaten Anwendungen. Angenommen bei meinem Script habe ich in Glibc darauf geachtet das kein Byte mehr als nötig gelesen und geschrieben wird.. Bei der MingW Version mit stpcpy, strtok etc. bestimmt 3 mal mehr. Das macht dann bei 450MB auch ne Sekunde mit dem ganzen IO drum herum. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|