Benchmarkergebnisse, Teilnehmer Benchmark gesucht

larslrs

Komplett-PC-Aufrüster(in)
Hallo,

bei einem Performance-Test haben wir (gaussmath, ich) unerwartete Unterschiede zwischen Intel/AMD und Windows/Linux festgestellt.
Daher suchen wir weitere Ergebnisse zu diesem Benchmark.

Würdest Du zwecks Benchmark folgenden Algo bei Dir laufen lassen?
Für den Test möglichst alle anderen Programme schließen.

Wir haben zwei Varianten: Python Script für CPython >=3.5 sowie C#.
Interessant sind die Ergebnisse beider Varianten.

Für das Python-Script ist es unter Windows erforderlich, CPython zu installieren: Download Python | Python.org
Anschließend das Script mit Python öffnen und, falls sie nicht automatisch startet, mit F5 starten.

SC_bench_memPy3x.py (CPython >=3.5)
lars lrs, i3 7100 stock, DDR4@2400, CL10-12-12-28, Ubuntu 16.04 (alle patches installiert): 38s
HisN, i7 5960X@4.5Ghz, DDR4@2600, CL15-15-15-35, Windows10: 45.6s
Krolgosh, Xeon E5 2687W@3.10Ghz (stock), 64 GB DDR3@800, CL11-11-11-28, Windows 7: 80.9s
gaussmath, Ryzen 1950X@4Ghz + Game Mode (16MB Level 3 Cache aktiv, Dual Channel), DDR4@3446, CL14-14-14-30, Windows10: 54.8s
Olstyle, i5 5675c stock, Windows: 77.6s

SC_bench_memcs.cs:
lars lrs, i3 7100 stock, DDR4@2400, CL10-12-12-28, Ubuntu 16.04 (alle patches installiert): 9.3s
HisN, i7 5960X@4.5Ghz, DDR4@2600, CL15-15-15-35, Windows10: 9.0s
HisN, i7 5960X@4.5Ghz, DDR4@2600, CL15-15-15-35, Ubuntu16.04 Live-USB-Stick: 9.5s
Krolgosh, Xeon E5 2687W@3.10Ghz (stock), 64 GB DDR3@800, CL11-11-11-28, Windows 7: 12.2s
gaussmath, Ryzen 1950X@4Ghz + Game Mode (16MB Level 3 Cache aktiv, Dual Channel), DDR4@3446, CL14-14-14-30, Windows10: 13.3s
gaussmath, i7 3630QM@3.4Ghz, DDR3@1333, CL9-9-9-24, Windows10: 10.5s
Olstyle, i5 5675c stock, Windows: 8.6s

SC_bench_memcs16mb.cs
lars lrs, i3 7100 stock, DDR4@2400, CL10-12-12-28, Ubuntu 16.04 (alle patches installiert): 3.1s
gaussmath, i7 3630QM@3.4Ghz, DDR3@1333, CL9-9-9-24, Windows10: 3.9s
gaussmath, Ryzen 1950X@4Ghz + Game Mode (16MB Level 3 Cache aktiv, Dual Channel), DDR4@3446, CL14-14-14-30, Windows10: 2.1s
Olstyle, i5 5675c stock, Windows: 3.2s
_LS_ , i7 6700k@4,3GHz(Allcore), Cache@4,2GHz, DDR4@2400MHz CL14-14-14-36-1T Windows 10: 2.6s

Spectre und Meltdown-Patch
Olstyle, i5 5675c stock, Windows: Jeweils (fast) keine Unterschiede

Je mehr mitmachen, umso besser.

Vielen Dank,
Lars

Funktionsweise:
Es wird ein Array mit 16M Zufallszahlen (1...255) angelegt. Anschließend wird 2048 mal über das Array iteriert (äußere for-Schleife).
Pro Iteration wird in Abhängigkeit von der Zufallszahl im aktuellen Element das nächste Element ausgewählt (innere While-Schleife). Dh, die Schrittgröße ist abhängig von der gerade ausgewählten Zufallszahl. Wird 16M überschritten, so beginnt die nächste Iteration.
Hier und da wird etwas addiert, damit es auch etwas zu rechnen gibt: In der inneren while-Schleife ist dies der "Elemente-Index", der in Abhängigkeit von der gerade betrachteten Zufallszahl erhöht (+) oder verkleinert (-) wird. Letztlich wird insgesamt mehr addiert als subtrahiert.
In der äußeren for-Schleife werden alle Überläufe der inneren Schleife >16M modulo 2048 aufsummiert.
Jede der 2048 Iterationen startet mit einem anderen Wert, so dass sich die ausgewählten Werte pro Iteration teilweise voneinander unterscheiden.
 

Anhänge

  • SC_bench_memPy3x.py.zip
    647 Bytes · Aufrufe: 71
  • SC_bench_memcs.cs.zip
    703 Bytes · Aufrufe: 72
  • SC_bench_memcs16mb.cs.zip
    648 Bytes · Aufrufe: 64
Zuletzt bearbeitet:
Ich habe hier die kompilierte Exe des C# Codes hochgeladen: https://1drv.ms/u/s!As_jnW8h38YpgbN8207274U53uUX_A

Wahrscheinlich werdet ihr einen Sicherheitshinweis bekommen. Die Datei ist lupenrein, also keine Sorge.

Meine Threadripper schafft es in ca. 13.3 Sekunden. Mein i7 der 3. Generation packt den Durchlauf in ca. 10.5 Sekunden.
 
@larslrs: Ich vermute, dass mit meinem Ryzen System was nicht stimmt. Normalerweise war die Single Core Leistung leicht höher oder vergleichbar mit dem i7. Jetzt liegen stattdessen rund 30% dazwischen. Ich werde das System demnächst mal frisch aufsetzen.
 
Mh, naja. 30% sind jetzt immer zwischen threadripper und i7 oder nur bei diesem Test? Falls nur bei diesem Test:
Du schriebst, die 13s sind mit NUMA. Könntest Du auch noch Legacy=On mit NUMA/UMA probieren? Bzw. mit Thread-to-core-pinning?
Das Problem ist mit 16MB gerade so zu groß für einen Die, bzw die Inter-Die-Kommunikation ist zu langsam.
 
Ich komme auf mind. 67MB Context Data. Hier greift wahrscheinlich die große Schwäche von Ryzen: parallele Datenzugriffe/Prefetches
 
Edit: Mir fällt gerade auf, Du hast das Array als Int-Werte angelegt, nicht als (unsigned) char. Das ist keine Entschuldigung dafür, dass es auf dem Threadripper langsamer läuft. Aber es kann erklären, warum es nicht in 32MByte Cache passt.


Der gesamte Kontext beinhaltet die Generierung der Zufallszahlen. Ich weiß nicht, wie effizient C# ist, aber nach der Erzeugung der Zufallszahlen gehen wir 2048x immer wieder über das gleiche 16MByte Array; Jedoch nicht in eine trivialen (einfach vorhersehbaren) Art und Weise. Das Bisschen Algorithmus sollte dann auch noch in 32MByte hinein passen (zumindest bei C, vielleicht nicht bei C# und vielleicht nicht bei Python)

Parallelen Datenzugriff macht der Algorithmus gerade nicht. Mit prefetch ist auch nicht viel. Dafür stehen die Zufallswerte im Array. Und davon hängt ab, was als nächstes überprüft/addiert wird.
 
Zuletzt bearbeitet:
Wie kommst du auf 16 MB für das Array? Es sind 2^24×4 Byte.

Parallele Datenzugriffe müssen ja auch nicht im Code explizit definiert werden. Das baut der Compiler so. Davon bekommt man als Programmierer nichts mit.
 
Wie kommst du auf 16 MB für das Array? Es sind 2^24×4 Byte.

Parallele Datenzugriffe müssen ja auch nicht im Code explizit definiert werden. Das baut der Compiler so. Davon bekommt man als Programmierer nichts mit.

Siehe Edit in meinem vorherigen Post: Hatte Deinen Code dahingehend nicht überprüft. Im Python script ist es 16M*char.

Parallel die Daten holen kann er ja. Eine Cache-Line ist ja nicht nur Byte breit. Er dürfte die Daten halt nur nicht (unnötig) wegwerfen, damit er sie noch hat, wenn im überübernächsten Durchlauf wieder darauf zugegriffen wird. Der Compiler hat IMHO keinen Grund, Daten zu holen, die der Algo nirgends braucht. Und die Zufallszahlen (wann wird auf welches Array-Element zugegriffen), kennt der Compiler auch nicht.
 
Ok, ich teste das mal uint8 morgen. Parallele Datenzugriffe machen hier keinen Sinn, ja. Was die Prefetches betrifft, wäre ich mir allerdings nicht so sicher. Kann der Compiler keine statistische Betrachtung durchführen, also jene Daten in den Cache laden, die mit hoher Wahrscheinlichkeit benötigt werden?

Mein System hat eine sehr hohe Bandbreite. Woher kommt der Unterschied? Das muss doch irgendeine Cache Magic sein.
 
Soweit ich es überblicke, sind die Latenzen beim Threadripper schlechter als bei Intel. Der Speicherzugriff des Scriptes ist Random und nicht vorhersehbar. Dh, hohe Latenzen sind besonders schlecht. Allerdings ist der Zugriff auf einen relativ kleinen Speicherbereich begrenzt, was man jedoch beim Betrachten von beispielsweise 100 Zugriffen nicht erkennen kann.

Eine Frage ist, ob Probleme einer bestimmten Größe extrem schnell (schneller als Intel) bearbeitet werden können, insofern das Problem (die Daten dazu) komplett in den L3-Cache passen. Dann hängt es davon ab, dass die Daten/Cachelines nicht wieder gelöscht/überschrieben werden. Wenn die CPU also zu dem Schluss kommt, dass der Prefetch nichts genützt hat, weil die nächsten Befehle die Prefetch-Daten nicht benötigen, die CPU jedoch nicht beliebig weit voraussehen kann, und deshalb die Daten einfach wieder überschreibt, dann stehen die Daten 2Sekunden später eben nicht mehr zur Verfügung und müssen erneut mit hoher Latenz geholt werden. In den Prefetch- und Cache-Mechanismen stecke ich im Moment auch nicht drin.

Mir stellt sich noch die Frage, ob man mit bestimmten (weiteren) Einstellungen (zB Legacy=On) etwas zum positiven hin bewegen kann. Dies würde darauf hin deuten, dass das Betriebssystem noch nicht mit der CPU zu recht kommt.

Wenn 256 Byte auf einmal geholt werden, dann hat man mit einer gewissen Wahrscheinlichkeit bereits das nächste benötigte Byte bekommen (siehe Algorithmus). Aber man hat 256 Byte geholt und nur 2 Byte davon benötigt.
 
Ich teste morgen mal weitere Settings. Da die 2000er Ryzen hinsichtlich der Latenzen verbessert wurden, wäre es super, wenn jemand mit einer solchen CPU das mal testen könnte.

Im allgemeinen ist die Beteiligung hier im PCGH Forum nicht so gut. Deshalb habe ich schon überlegt, ob wir nicht ins 3DCenter wechseln sollten.
 
Erklärt doch z.B. mal im Anfangspost genauer was das Programm rechnet bevor du direkt über mangelnde Beteiligung schimpfst ;).
Werde es bei Gelegenheit Mal auf dem Bratwell laufen lassen. Dessen "L4-Cache" dürfte auch interessant agieren.
 
Ich teste morgen mal weitere Settings. Da die 2000er Ryzen hinsichtlich der Latenzen verbessert wurden, wäre es super, wenn jemand mit einer solchen CPU das mal testen könnte.

Wahrscheinlich ist auch 16MByte zu groß für den 1950-Cache.
Es schaut so aus, als ob SC den Cache der anderen Dies nicht nutzbringend verwenden kann.
(AMD Ryzen's Infinity Fabric & Memory Subsystem, Explained)
Das ist dann bei 2950 wahrscheinlich auch so und für mich etwas unerwartet: Ich würde vermuten, dass man von einem Die zum anderen wesentlich besser Daten übertragen kann, als aus dem Speicher...
 
Ich hab mal die ganze Sache unter Windows ausprobiert.


HisN, i7 5960X@4.5Ghz, DDR4@2600, CL15-15-15-35, Windows10

die von gaussmath bereitgestellte Exe
Runtime in seconds:00:00:09.0201888

das Python-Script
Runtime in seconds: 45.583479166030884

HisN, i7 5960X@4.5Ghz, DDR4@2600, CL15-15-15-35, Ubuntu16.04 Live-USB-Stick^^

Das Python-Script läuft auf der Live-Variante scheinbar nicht, erzählt was von Fehlerhaften Daten.
Das C-Script allerdings lässt sich mit Mono übersetzen und läuft dann etwas langsamer als unter Windows, nämlich 9,5 Sekunden.


Das Script läuft nur auf einem Kern? Mein alter Haswell taktet dabei nicht mal hoch^^ Also sind die 4.5Ghz eher mit sehr großer Vorsicht zu genießen.
 
Zuletzt bearbeitet:
Ja, das Script läuft nur auf einem Kern. Die Performance hängt jedoch auch vom Cache ab, so dass ein Mehrkerner mit mehr (oder anderem) Cache eine andere Performance haben kann.
 
Hab das ganze mal auf meiner Workstation getestet:

SC_bench_memPy3x.py
Krolgosh, Xeon E5 2687W@3.10Ghz (stock), 64 GB DDR3@800, CL11-11-11-28, Windows 7 = 80.93665623664856 sec

SC_bench_memcs.cs:
Krolgosh, Xeon E5 2687W@3.10Ghz (stock), 64 GB DDR3@800, CL11-11-11-28, Windows 7 = 12.2413849 sec

Kann das heut Abend dann gern auch nochmal mit meinem i7 daheim machen.
 
Ok, jetzt wirds interessant. Ich habe den Datentyp auf byte umgestellt, uint8 gibt's übrigens unter C# nicht. Der Code ist somit jetzt erst äquivalent zum Python Skript.

gaussmath, i7 3630QM@3.4Ghz, DDR3@1333, CL9-9-9-24, Windows10, Runtime in seconds:00:00:03.9727339

gaussmath, Ryzen 1950X@4Ghz + Game Mode (16MB Level 3 Cache aktiv, Dual Channel), DDR4@3446, CL14-14-14-30, Windows10, Runtime in seconds:00:00:02.1354053

Erklärt doch z.B. mal im Anfangspost genauer was das Programm rechnet bevor du direkt über mangelnde Beteiligung schimpfst
zwinker4.gif
.

Gerechnet wird da im Grunde gar nicht. Es ist ein Cache/Speicherbenchmark, der sich dadurch auszeichnet, dass die Speicherzugriffe zufällig verteilt sind. Das Speichermanagement "hasst" derartige Speicherzugriffe, weil sequentielle Zugriffe besser verarbeitet werden können. Das System "weiß" sozusagen, was als nächstes benötigt wird und kann entsprechend optimieren.
 

Anhänge

  • SC_bench_memcs_16mb.zip
    2,4 KB · Aufrufe: 66
Zuletzt bearbeitet von einem Moderator:
Code:
[COLOR=blue]using System;
[COLOR=blue]using System.Diagnostics;
 
[COLOR=blue]namespace TestPythonBenchmark
{
    [COLOR=blue]class [COLOR=#2b91af]Program    {
        [COLOR=blue]private [COLOR=blue]static [COLOR=#2b91af]Random _random = [COLOR=blue]new [COLOR=#2b91af]Random(241500528);
 
        [COLOR=blue]static [COLOR=blue]void Main([COLOR=blue]string[] args)
        {
            [COLOR=blue]const [COLOR=blue]int cycles = 2048;
            [COLOR=blue]int testsize = ([COLOR=blue]int)[COLOR=#2b91af]Math.Pow(2, 24);
 
            [COLOR=blue]byte[] testdata = [COLOR=blue]new [COLOR=blue]byte[testsize];
 
            [COLOR=blue]for ([COLOR=blue]int i = 0; i < testsize; i++)
            {
                testdata[i] = ([COLOR=blue]byte)_random.Next(1, 255);
            }
 
            [COLOR=blue]int the_sum = 0;
 
            [COLOR=#2b91af]Stopwatch stopwatch = [COLOR=blue]new [COLOR=#2b91af]Stopwatch();
            stopwatch.Start();
 
            [COLOR=blue]for ([COLOR=blue]int k = 0; k < cycles; k++)
            {
                [COLOR=blue]int value = k;
                [COLOR=blue]while (value < testsize)
                {
                    [COLOR=blue]if (testdata[value] > 128)
                    {
                        value += testdata[value];
                    }
                    [COLOR=blue]else                    {
                        value--;
                    }
                }
                the_sum += (value % cycles);
            }
 
            stopwatch.Stop();
 
            [COLOR=blue]if (the_sum != 200704)
            {
                [COLOR=blue]throw [COLOR=blue]new [COLOR=#2b91af]Exception([COLOR=#a31515]"wrong test result");
            }
            [COLOR=blue]else            {
                [COLOR=#2b91af]Console.WriteLine([COLOR=#a31515]"Runtime in seconds:" + stopwatch.Elapsed);
            }
 
            [COLOR=#2b91af]Console.ReadKey();
        }
    }
}
 
Ich habe auch noch die Werbetrommel gerührt im Thread "AMD Ryzen". Leider noch keiner hier vorbeigeschaut mit einem 2000er Ryzen... :(
 
Zurück