Forum: PC-Programmierung c++ Code langsam


von udok (Gast)


Lesenswert?

Rufe die Kommando einfach mal händisch auf:
1
1) ./gen_csv.exe (erzeugt list.txt)
2
2) time ./test_philipp.exe
3
4
Zum Testen noch:
5
3) cp nohup.txt nohup_philipp.txt
6
4) ./test_hans.exe
7
5) diff -q nohup_philipp.txt nohup.txt

von Philipp K. (philipp_k59)


Lesenswert?

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.

von heinzel (Gast)


Lesenswert?

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 vom Autor gelöscht.
von Philipp K. (philipp_k59)


Lesenswert?

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.

von Philipp K. (philipp_k59)


Angehängte Dateien:

Lesenswert?

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

von udok (Gast)


Lesenswert?

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!

von Roger S. (edge)


Lesenswert?

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

von udok (Gast)


Lesenswert?

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:
1
test_foobar_lua2.sh                   Lua           Seconds=17.14  MB/sec=26.5
2
test_hans.exe                         CPP           Seconds=5.69   MB/sec=79.9
3
test_mikro77_hash.gawk                Gawk          Seconds=5.24   MB/sec=86.8
4
test_philipp_strtok.exe               C             Seconds=4.55   MB/sec=99.9
5
test_mikro77_n2.exe                   CPP           Seconds=3.89   MB/sec=116.9
6
test_heinzel2.exe                     CPP           Seconds=3.47   MB/sec=131.0
7
test_heinzel.exe                      CPP           Seconds=3.45   MB/sec=131.8
8
test_foobar3.exe                      C             Seconds=3.41   MB/sec=133.3
9
test_roger.exe                        CPP           Seconds=3.41   MB/sec=133.3
10
test_mikro77_hash.exe                 CPP           Seconds=3.39   MB/sec=134.1
11
test_roger.exe                        CPP           Seconds=3.38   MB/sec=134.5
12
test_foobar2.exe                      C             Seconds=3.26   MB/sec=139.4
13
test_mh_yalu_python3.sh               Python3       Seconds=2.53   MB/sec=179.7
14
test_mikro77_hash.pl                  Perl          Seconds=2.50   MB/sec=181.8
15
test_csharp_roger.exe                 C#            Seconds=1.97   MB/sec=230.8
16
test_jemand_rust.exe                  Rust          Seconds=1.58   MB/sec=287.7
17
test_native_n2.exe                    C,N^2         Seconds=0.41   MB/sec=1108.8
18
test_native_hash.exe                  C,Simple      Seconds=0.23   MB/sec=1976.5

von Philipp K. (philipp_k59)


Lesenswert?

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.
1
test_hans.exe            CPP      Bytes=18880    Seconds=1.58   MB/sec=287.7
2
test_mh_python3.sh       Python3  Bytes=544      Seconds=3.99   MB/sec=113.9
3
test_heinzel.exe         CPP      Bytes=14624    Seconds=1.19   MB/sec=382.0
4
test_mikro77_sort.exe    CPP      Bytes=18864    Seconds=1.45   MB/sec=313.5
5
test_foobar3.exe         C        Bytes=14440    Seconds=6.12   MB/sec=74.3
6
test_strtok.exe          C        Bytes=14512    Seconds=3.00   MB/sec=151.5
7
test_heinzel2.exe        CPP      Bytes=14624    Seconds=1.15   MB/sec=395.3
8
test_mikro77_hash.exe    CPP      Bytes=14688    Seconds=1.45   MB/sec=313.5
9
test_roger.exe           CPP      Bytes=230400   Seconds=24.28  MB/sec=18.7
10
test_foobar2.exe         C        Bytes=14448    Seconds=7.66   MB/sec=59.3
11
test_mikro77_hash.pl     Perl     Bytes=470      Seconds=1.90   MB/sec=239.3
12
test_native_n2.exe       C        Bytes=14464    Seconds=0.42   MB/sec=1082.4
13
test_native_hash.exe     C        Bytes=14464    Seconds=0.28   MB/sec=1623.6

von Roger S. (edge)


Lesenswert?

Die Zehn Zeilen strtok goodness bieten noch etwas Raum fuer 
optimierung... ;-)

von udok (Gast)


Lesenswert?

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-:
1
test_foobar_lua2.sh      Lua           Bytes=272      Seconds=17.41  MB/sec=26.1
2
test_hans.exe            CPP           Bytes=33792    Seconds=5.66   MB/sec=80.3
3
test_mikro77_hash.gawk   Gawk          Bytes=184      Seconds=5.44   MB/sec=83.6
4
test_mikro77_n2.exe      CPP           Bytes=25600    Seconds=4.19   MB/sec=108.5
5
test_heinzel.exe         CPP           Bytes=25600    Seconds=3.70   MB/sec=122.9
6
test_heinzel2.exe        CPP           Bytes=25600    Seconds=3.49   MB/sec=130.3
7
test_roger.exe           CPP           Bytes=27136    Seconds=3.45   MB/sec=131.8
8
test_mikro77_sort.exe    CPP           Bytes=34304    Seconds=3.44   MB/sec=132.2
9
test_roger.exe           CPP           Bytes=27136    Seconds=3.44   MB/sec=132.2
10
test_mikro77_hash.exe    CPP           Bytes=29696    Seconds=3.21   MB/sec=141.6
11
test_mikro77_hash.pl     Perl          Bytes=470      Seconds=2.54   MB/sec=179.0
12
test_mh_yalu_python3.sh  Python3       Bytes=534      Seconds=2.52   MB/sec=180.4
13
test_philipp_strtok.exe  C             Bytes=10752    Seconds=2.35   MB/sec=193.4
14
test_foobar3.exe         C             Bytes=10240    Seconds=2.16   MB/sec=210.5
15
test_csharp_roger.exe    C#            Bytes=127488   Seconds=1.94   MB/sec=234.3
16
test_foobar2.exe         C             Bytes=10752    Seconds=1.91   MB/sec=238.0
17
test_jemand_rust.exe     Rust          Bytes=1084416  Seconds=1.59   MB/sec=285.9
18
test_native_n2.exe       C,N^2         Bytes=15872    Seconds=0.41   MB/sec=1108.8
19
test_native_hash.exe     C,Simple      Bytes=15872    Seconds=0.23   MB/sec=1976.5

von udok (Gast)


Lesenswert?

Hier das Update für Win10, 1000k Zeilen, 10 Bytes/Feld:
1
[0]$ cat run_Win10_1000kLines_10Bytes_20210526.log
2
test_foobar_lua2.sh      Lua           Bytes=272      Seconds=23.05  MB/sec=21.5
3
test_hans.exe            CPP           Bytes=33792    Seconds=16.31  MB/sec=30.4
4
test_mikro77_hash.pl     Perl          Bytes=470      Seconds=13.77  MB/sec=36.0
5
test_mikro77_hash.gawk   Gawk          Bytes=184      Seconds=12.26  MB/sec=40.5
6
test_jemand_rust.exe     Rust          Bytes=1084416  Seconds=10.30  MB/sec=48.2
7
test_heinzel2.exe        CPP           Bytes=25600    Seconds=10.19  MB/sec=48.7
8
test_heinzel.exe         CPP           Bytes=25600    Seconds=10.10  MB/sec=49.1
9
test_mikro77_sort.exe    CPP           Bytes=34304    Seconds=8.27   MB/sec=60.0
10
test_mh_yalu_python3.sh  Python3       Bytes=534      Seconds=8.05   MB/sec=61.6
11
test_philipp_strtok.exe  C             Bytes=10752    Seconds=7.88   MB/sec=62.9
12
test_roger.exe           CPP           Bytes=27136    Seconds=6.98   MB/sec=71.1
13
test_roger.exe           CPP           Bytes=27136    Seconds=6.94   MB/sec=71.5
14
test_mikro77_hash.exe    CPP           Bytes=29696    Seconds=6.39   MB/sec=77.6
15
test_mikro77_n2.exe      CPP           Bytes=25600    Seconds=5.81   MB/sec=85.4
16
test_foobar3.exe         C             Bytes=10240    Seconds=5.24   MB/sec=94.7
17
test_foobar2.exe         C             Bytes=10752    Seconds=4.93   MB/sec=100.6
18
test_csharp_roger.exe    C#            Bytes=127488   Seconds=4.07   MB/sec=121.9
19
test_native_n2.exe       C,N^2         Bytes=15872    Seconds=2.03   MB/sec=244.3
20
test_native_hash.exe     C,Simple      Bytes=15872    Seconds=0.83   MB/sec=597.6

von Sheeva P. (sheevaplug)


Lesenswert?

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)

von Jan K. (jan_k)


Lesenswert?

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?

von Philipp K. (philipp_k59)


Angehängte Dateien:

Lesenswert?

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.
1
test_hans.exe            CPP      Bytes=18880    Seconds=8.93   MB/sec=55.5
2
test_mh_python3.sh       Python3  Bytes=544      Seconds=9.89   MB/sec=50.2
3
test_heinzel.exe         CPP      Bytes=14624    Seconds=5.75   MB/sec=86.3
4
test_mikro77_sort.exe    CPP      Bytes=18864    Seconds=4.51   MB/sec=110.0
5
test_foobar3.exe         C        Bytes=14440    Seconds=9.81   MB/sec=50.6
6
test_strtok.exe          C        Bytes=14512    Seconds=5.80   MB/sec=85.5
7
test_heinzel2.exe        CPP      Bytes=14624    Seconds=5.57   MB/sec=89.0
8
test_mikro77_hash.exe    CPP      Bytes=14688    Seconds=3.09   MB/sec=160.5
9
test_roger.exe           CPP      Bytes=230400   Seconds=32.20  MB/sec=15.4
10
test_foobar2.exe         C        Bytes=14448    Seconds=10.37  MB/sec=47.8
11
test_mikro77_hash.pl     Perl     Bytes=470      Seconds=9.90   MB/sec=50.1
12
test_native_n2.exe       C        Bytes=14464    Seconds=2.20   MB/sec=225.5
13
test_native_hash.exe     C        Bytes=14464    Seconds=0.83   MB/sec=597.6

von Ich nicht (Gast)


Lesenswert?

Noch nicht alles gelesen... Hat schon jemand eine 
multithreading-Variante mit getrenntem io- und processing-threads 
skizziert?

von udok (Gast)


Lesenswert?

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.

von udok (Gast)


Lesenswert?

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.

von udok (Gast)


Lesenswert?

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.

von udok (Gast)


Lesenswert?

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:
1
test_hans.exe                         PeakWorkingSet=2.84   Seconds=5.75   MB/sec=79
2
test_philipp_strtok.exe               PeakWorkingSet=97.98  Seconds=2.33   MB/sec=195
3
test_philipp_strtok2.exe              PeakWorkingSet=10.20  Seconds=2.26   MB/sec=202
4
test_foobar2.exe                      PeakWorkingSet=2.47   Seconds=1.94   MB/sec=235
5
test_jemand_rust.exe                  PeakWorkingSet=4.05   Seconds=1.59   MB/sec=286
6
test_native_hash.exe                  PeakWorkingSet=3.50   Seconds=0.22   MB/sec=2020

von udok (Gast)


Lesenswert?

Hier noch das Ergebnis sortiert nach Speicherverbrauch (Peak WorkingSet 
in MB, nur ein Durchlauf):
1
[0]$ cat run_Win10_200kLines_100Bytes-20210527b.log |sort -t= -k2g
2
test_foobar3.exe          C       PeakWorkingSet=2.45   Seconds=4.32   MB/sec=211
3
test_foobar2.exe          C       PeakWorkingSet=2.46   Seconds=3.82   MB/sec=238
4
test_native_hash.exe      C       PeakWorkingSet=2.50   Seconds=0.44   MB/sec=2043
5
test_native_n2.exe        C,N^2   PeakWorkingSet=2.50   Seconds=0.84   MB/sec=1084
6
test_heinzel.exe          CPP     PeakWorkingSet=2.73   Seconds=6.97   MB/sec=130
7
test_heinzel2.exe         CPP     PeakWorkingSet=2.73   Seconds=6.97   MB/sec=131
8
test_roger.exe            CPP     PeakWorkingSet=2.74   Seconds=6.93   MB/sec=131
9
test_mikro77_n2.exe       CPP     PeakWorkingSet=2.81   Seconds=8.08   MB/sec=112
10
test_mikro77_sort.exe     CPP     PeakWorkingSet=2.82   Seconds=6.65   MB/sec=137
11
test_hans.exe             CPP     PeakWorkingSet=2.83   Seconds=11.13  MB/sec=82
12
test_jemand_rust.exe      Rust    PeakWorkingSet=3.84   Seconds=3.14   MB/sec=289
13
test_mikro77_hash.pl      Perl    PeakWorkingSet=6.78   Seconds=5.08   MB/sec=179
14
test_philipp_strtok2.exe  C       PeakWorkingSet=10.20  Seconds=4.51   MB/sec=202
15
test_csharp_roger.exe     C#      PeakWorkingSet=21.57  Seconds=3.83   MB/sec=238
16
test_philipp_strtok.exe   C       PeakWorkingSet=97.97  Seconds=4.62   MB/sec=197
17
test_mh_yalu_python3.py   Python3 PeakWorkingSet=905.86 Seconds=5.02   MB/sec=181

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.

von Philipp K. (philipp_k59)


Lesenswert?

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.

von Philipp K. (philipp_k59)


Angehängte Dateien:

Lesenswert?

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.
1
test_roger.exe           CPP      Bytes=230400   Seconds=36.21  MB/sec=13.7
2
test_foobar2.exe         C        Bytes=14448    Seconds=10.67  MB/sec=46.5
3
test_mikro77_hash.pl     Perl     Bytes=470      Seconds=10.45  MB/sec=47.5
4
test_mh_python3.sh       Python3  Bytes=544      Seconds=10.20  MB/sec=48.6
5
test_foobar3.exe         C        Bytes=14440    Seconds=9.55   MB/sec=51.9
6
test_hans.exe            CPP      Bytes=18880    Seconds=9.53   MB/sec=52.0
7
test_strtok.exe          C        Bytes=14512    Seconds=5.91   MB/sec=83.9
8
test_heinzel2.exe        CPP      Bytes=14624    Seconds=5.72   MB/sec=86.7
9
test_heinzel.exe         CPP      Bytes=14624    Seconds=5.70   MB/sec=87.0
10
test_mikro77_sort.exe    CPP      Bytes=18864    Seconds=4.26   MB/sec=116.4
11
test_mikro77_hash.exe    CPP      Bytes=14688    Seconds=3.26   MB/sec=152.1
12
test_strtok_fw_philipp.exe C        Bytes=14512    Seconds=2.53   MB/sec=196.0
13
test_native_n2.exe       C        Bytes=14464    Seconds=2.30   MB/sec=215.7
14
test_native_hash.exe     C        Bytes=14464    Seconds=0.86   MB/sec=576.7

von udok (Gast)


Angehängte Dateien:

Lesenswert?

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.

von udok (Gast)


Lesenswert?

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.
1
[0]$ cat run_WIN10_50kLines_500Bytes_20210610.log
2
test_foobar_lua2.lua     Lua     PeakWorkingSet=3.0    Seconds=39.71  MB/sec=28
3
test_mikro77_hash.gawk   Gawk    PeakWorkingSet=2.8    Seconds=34.29  MB/sec=33
4
test_mh_python3.py       Python3 PeakWorkingSet=11.0   Seconds=14.89  MB/sec=76
5
test_hans.exe            CPP     PeakWorkingSet=2.8    Seconds=11.41  MB/sec=99
6
test_mikro77_n2.exe      CPP     PeakWorkingSet=2.8    Seconds=9.36   MB/sec=120
7
test_roger.exe           CPP     PeakWorkingSet=2.8    Seconds=7.84   MB/sec=144
8
test_mikro77_hash.exe    CPP     PeakWorkingSet=2.8    Seconds=7.24   MB/sec=156
9
test_heinzel.exe         CPP     PeakWorkingSet=2.7    Seconds=7.17   MB/sec=157
10
test_heinzel2.exe        CPP     PeakWorkingSet=2.7    Seconds=7.18   MB/sec=157
11
test_mh_yalu_python3.py  Python3 PeakWorkingSet=1103.1 Seconds=7.04   MB/sec=160
12
test_mikro77_sort.exe    CPP     PeakWorkingSet=2.8    Seconds=6.98   MB/sec=162
13
test_philipp_strtok_fw.exe C     PeakWorkingSet=11.1   Seconds=4.99   MB/sec=226
14
test_foobar3.exe         C       PeakWorkingSet=2.4    Seconds=4.65   MB/sec=242
15
test_philipp_strtok.exe  C       PeakWorkingSet=98.0   Seconds=4.40   MB/sec=256
16
test_philipp_strtok2.exe C       PeakWorkingSet=10.2   Seconds=4.27   MB/sec=264
17
test_csharp_roger.exe    C#      PeakWorkingSet=21.6   Seconds=4.13   MB/sec=273
18
test_foobar2.exe         C       PeakWorkingSet=2.5    Seconds=4.06   MB/sec=278
19
test_jemand_rust.exe     Rust    PeakWorkingSet=6.7    Seconds=3.07   MB/sec=368
20
test_mikro77_hash.pl     Perl    PeakWorkingSet=6.9    Seconds=2.73   MB/sec=413
21
test_native_n2.exe       C       PeakWorkingSet=2.5    Seconds=0.67   MB/sec=1678
22
test_native_hash.exe     C       PeakWorkingSet=2.5    Seconds=0.41   MB/sec=2743

von udok (Gast)


Lesenswert?

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.

von udok (Gast)


Lesenswert?

Hier noch die Ergebnisse für Linux WSL2:

Ein Trauerspiel, wie schlecht die Microsoft Libs sind.
1
[0]$ cat run_WSL2_Ubuntu_50kLines_500Bytes_20210610.log
2
test_mikro77_n2.gawk       Gawk    Bytes=244      Seconds=21.23  MB/sec=53
3
test_mh_python3.sh         Python3 Bytes=544      Seconds=7.48   MB/sec=151
4
test_mikro77_n2.exe        CPP     Bytes=13904    Seconds=4.69   MB/sec=240
5
test_foobar2.exe           C       Bytes=8672     Seconds=3.46   MB/sec=326
6
test_mh_yalu_python3.sh    Python3 Bytes=534      Seconds=2.57   MB/sec=439
7
test_jemand_rust.exe       Rust    Bytes=10415456 Seconds=2.06   MB/sec=547
8
test_mikro77_sort.exe      CPP     Bytes=24472    Seconds=2.03   MB/sec=555
9
test_mikro77_hash.exe      CPP     Bytes=15144    Seconds=1.90   MB/sec=593
10
test_mikro77_hash.pl       Perl    Bytes=470      Seconds=1.76   MB/sec=641
11
test_foobar3.exe           C       Bytes=8632     Seconds=1.30   MB/sec=867
12
test_hans.exe              CPP     Bytes=19672    Seconds=1.27   MB/sec=888
13
test_philipp_strtok_fw.exe C       Bytes=13112    Seconds=1.17   MB/sec=964
14
test_philipp_strtok2.exe   C       Bytes=13112    Seconds=1.15   MB/sec=980
15
test_philipp_strtok.exe    C       Bytes=13024    Seconds=1.12   MB/sec=1007
16
test_heinzel2.exe          CPP     Bytes=14056    Seconds=1.00   MB/sec=1127
17
test_heinzel.exe           CPP     Bytes=14056    Seconds=0.99   MB/sec=1139
18
test_native_n2.exe         C       Bytes=12816    Seconds=0.70   MB/sec=1610
19
test_native_hash.exe       C       Bytes=12816    Seconds=0.56   MB/sec=2013

von Philippk_59 (Gast)


Lesenswert?

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 ;)

von udok (Gast)


Lesenswert?

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?

von Philipp K. (philipp_k59)


Lesenswert?

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?
1
char *
2
STPCPY (char *dest, const char *src)
3
{
4
  size_t len = strlen (src);
5
  return memcpy (dest, src, len + 1) + len;
6
}

: Bearbeitet durch User
von udok (Gast)


Lesenswert?

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.

von udok (Gast)


Lesenswert?

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.

von udok (Gast)


Lesenswert?

Ich habe noch mal bei FreeBSD geschaut, was die für eine stpcpy Funktion
haben:
1
char *stpcpy(char * __restrict to, const char * __restrict from)
2
{
3
  for (; (*to = *from); ++from, ++to);
4
  return(to);
5
}

Linux weiss ich nicht, mit den glibc Sourcen komme ich nicht klar.

von Al Fine (Gast)


Lesenswert?

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

von Philipp K. (philipp_k59)


Lesenswert?

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.

von Philipp K. (philipp_k59)


Lesenswert?

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

von udok (Gast)



Lesenswert?

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.

von Philipp K. (philipp_k59)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.