Ryzen 3000 Load Simulator

Z

ZeroStrat

Gast
Ich habe eine kleine App geschrieben, mit der man das Boost-Verhalten von Ryzen 3000 analysieren kann. Die App verursacht entsprechend konfiguriert wellenförmige Lastzustände mit fest definierten Last- und Idle-Intervallen. Es handelt sich dabei um tatsächliche Idle-Phasen, da die Threads schlafen gelegt werden. Es findet auch keine I/O-Last statt.

Erklärung der Config-Datei "params.txt" mit Defaults:
NumOfTasks 15
UseDynamicLoad 1
PauseTimeMilliseconds 2000
LoadIntervalMilliseconds 10000
ShowLoadStates 1

NumOfTasks definiert die Anzahl der Threads, die verwendet werden. UseDynamicLoad 1/0 schaltet die wellenförmige Last an und aus. PauseTimeMilliseconds ist die Länge der Idle-Phasen und LoadIntervalMilliseconds analog die Länge der Lastphasen. ShowLoadStates steuert die Ausgabe von Statusmeldungen.

Die Datei ist im Zip-Ordner mit dabei und kann mit jedem normalen Texteditor bearbeitet werden. Wenn man beispielsweise einen 3900X besitzt, kann man bei NumOfTasks 24 verwenden.

Die App selbst wird über Doppelklick gestartet. Ich empfehle das Taktverhalten mit Ryzen Master zu beobachten. Der Taskmanager sollte ein wellenförmiges Muster anzeigen. Anbei ist noch ein Screenshot zur Orientierung.

Ich hoffe, ich kann mit dem Tool dazu beitragen zu verstehen, was die CPUs in tatsächlichen Idle-Phasen zwischen Lastzuständen wirklich machen... ;)

Edit: Noch zur Erklärung. Thread 0 verwaltet die Timer und Lastwechsel. Somit hat dieser Mainthread keine Idle-Phasen, sondern stets mind. eine geringe Last.

Update vom 06.10.19


Ich habe eine neue Version erstellt. Die Liste der Änderungen:
  • Fehler behoben, dass die PauseTime nicht größer als die LoadTime sein durfte. Die Zeiten können nun beliebig gesetzt werden,
  • Von Sekunden auf Millisekunden umgestiegen, um die Zeiten feiner einstellen zu können.
  • Die Parameterdatei enthält einen neuen Eintrag ShowLoadStates. Damit kann man die Ausgabe über den aktuellen Status steuern.
  • Portierung von .NET Framework zu Core, so dass die App auch unter Linux läuft.
  • Die .NET Framework Version läuft normal unter Windows. Es muss kein Core SDK installiert werden.

Hinweis: Damit die Timer sauber funktionieren, sollten nicht alle Threads zugeballert werden, besser immer Max-1 verwenden.

Bei Verwendung der .NET Core Version kann das SDK installiert werden, mind. aber die Runtime: https://dotnet.microsoft.com/download/dotnet-core/2.2


C#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace LoadSimulatorNETCore
{
    class Program
    {
        static bool _showLoadStates = true;
        static long _length = 200000;
        static ManualResetEvent _manualResetEvent = new ManualResetEvent(true);

        static void Main(string[] args)
        {
            // Defaults
            int numOfTasks = 15;
            bool useDynamicLoad = true;
            int pauseTimeMilliSeconds = 2000;
            int loadIntervalMilliSeconds = 5000;

            try
            {
                var check = File.Exists("params.txt");

                var settings =
                     (from line in File.ReadAllLines("params.txt")
                      let parameters = line.Split(' ')
                      select new KeyValuePair<string, string>(parameters[0], parameters[1])).ToDictionary(x => x.Key, x => x.Value);

                numOfTasks = Convert.ToInt32(settings["NumOfTasks"]);
                useDynamicLoad = Convert.ToInt32(settings["UseDynamicLoad"]) == 1;
                pauseTimeMilliSeconds = Convert.ToInt32(settings["PauseTimeMilliSeconds"]);
                loadIntervalMilliSeconds = Convert.ToInt32(settings["LoadIntervalMilliSeconds"]);
                _showLoadStates = Convert.ToInt32(settings["ShowLoadStates"]) == 1;
            }
            catch (FileLoadException ex)
            {
                Console.WriteLine("Error while reading parameter from file: {0}", ex.Message);
            }

            if (useDynamicLoad)
            {
                SetPauseHeartBeat(loadIntervalMilliSeconds, pauseTimeMilliSeconds);
                ResetPauseHeartBeat(loadIntervalMilliSeconds, pauseTimeMilliSeconds);
            }


            if (_showLoadStates)
            {
                Console.WriteLine("{0} tasks started...", numOfTasks);
                Console.WriteLine("Starting high utilisation...");
            }

            for (int i = 0; i < numOfTasks; i++)
            {
                Task.Factory.StartNew(() =>
                {
                    double[] array = Enumerable.Range(1, (int)_length).Select(x => (double)x).ToArray();

                    try
                    {
                        while (true)
                        {
                            double dotProduct = array.Sum(x => x * x);

                            // https://www.wolframalpha.com/input/?i=sum(i%5E2,i%3D1..n)
                            if ((long)dotProduct != (_length * (_length + 1) * (2 * _length + 1)) / 6)
                            {
                                throw new InvalidOperationException();
                            }

                            _manualResetEvent.WaitOne();
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Task aborted with exception {0}", ex.Message);
                    }
                });
            }

            Console.ReadKey();
        }

        private static IDisposable SetPauseHeartBeat(int loadIntervalMilliSeconds, int pauseTimeMilliSeconds)
        {
            return Observable.Generate(0, // dummy initialState
                                        x => true, // dummy condition
                                        x => x, // dummy iterate
                                        x => x, // dummy resultSelector
                                        x => TimeSpan.FromMilliseconds(loadIntervalMilliSeconds + pauseTimeMilliSeconds))
                                        .ObserveOn(Scheduler.Immediate)
                                        .Subscribe(x => SetPause());
        }

        private static IDisposable ResetPauseHeartBeat(int loadIntervalMilliSeconds, int pauseTimeMilliSeconds)
        {
            return Observable.Generate(0, // dummy initialState
                                        x => true, // dummy condition
                                        x => x, // dummy iterate
                                        x => x, // dummy resultSelector
                                        x => TimeSpan.FromMilliseconds(loadIntervalMilliSeconds + pauseTimeMilliSeconds))
                                        .Delay(TimeSpan.FromMilliseconds(pauseTimeMilliSeconds))
                                        .Subscribe(x => ResetPause());
        }

        private static void SetPause()
        {
            if (_showLoadStates)
                Console.WriteLine("Starting idle time...");
            _manualResetEvent.Reset();
        }

        private static void ResetPause()
        {
            if (_showLoadStates)
                Console.WriteLine("Starting high utilisation...");
            _manualResetEvent.Set();
        }
    }
}
 

Anhänge

  • Screen Shot 10-04-19 at 03.47 PM.PNG
    Screen Shot 10-04-19 at 03.47 PM.PNG
    1,2 MB · Aufrufe: 903
  • LoadSimulatorNETCore.zip
    511,2 KB · Aufrufe: 463
  • LoadSimulatorNETFramework.zip
    487,1 KB · Aufrufe: 595
Zuletzt bearbeitet von einem Moderator:
  • Gefällt mir
Reaktionen: Haldi, Topfn, Rickmer und 17 andere
ZeroStrat schrieb:
Simple Arithmetik auf Basis von FP64 und 64MB Datenpaketen, damit der IF noch ein wenig ackern muss.
Ah, nach nochmaligem Lesen des OP hats klick gemacht. ;) coole Idee.
 
  • Gefällt mir
Reaktionen: ZeroStrat
Wenn ich nur einen Thread verwende, dann legt der Scheduler leider diesen Thread nicht auf die "Gold Stars". Also überhaupt nicht. Da muss AMD noch nachbessern.
 
  • Gefällt mir
Reaktionen: Haldi
@ZeroStrat funktioniert das Tool nur für die 3000er, oder mit allen AMD / Intels? Anfangs 2017 war der 7700K auch nicht immer allCore auf maximalem Boost.
 
@Syrato Das Tool funktioniert mit allen CPUs. Es sind auch kein SIMD Instruktionen oder so enthalten.

Ich habe das ganze nur in den Ryzen 3000 Kontext gestellt, weil das halt derzeit ein brisantes Thema ist. Ich beziehe mich dabei natürlich auf das Video von der8auer, das irgendwie suggeriert Ryzen boostet nur zum Schein in Idle-Phasen (auf den Max-Boost). Nun kann das jeder selbst überprüfen... 👍
 
Zuletzt bearbeitet von einem Moderator:
  • Gefällt mir
Reaktionen: yummycandy
  • Gefällt mir
Reaktionen: ZeroStrat
ZeroStrat schrieb:
Wenn ich nur einen Thread verwende, dann legt der Scheduler leider diesen Thread nicht auf die "Gold Stars". Also überhaupt nicht. Da muss AMD noch nachbessern.
Also bei mir klappt das super.
Bei 1T Last wechselt er zwischen C0(gold, bester CCD0/CCX0) und C2(zweitbester im CCX0)
bei mehr: C1(CCX0), dann C5(bester im CCX1), dann C4(zweit bester im CCX1)

Es ist
CCD0 -> mit erst CCX0 mit guten Cores, dann CCX1 mit guten Cores
dann CCD1 ....

Ich habe im BIOS CPPD explizit auf enabled gestellt, seither klappt es.
 
  • Gefällt mir
Reaktionen: ZeroStrat
@bad_sign Jetzt bin ich verwirrt. Manche sagen, das kommt noch und bei dir klappt's aber jetzt schon?! Hast du schon ABBA draufgezogen?
 
ABB
1T war jetzt lustig, bei CB entscheidet er sich mehr für C2, als C0 aber hier wars 50/50

Browser und TS ist offen, also bisschen Noise ist dabei.
Ab T10 wird in den SMT Thread von C0 und C2 ausgelagert
Der Scheduler tut echt alles um C11 nicht auszulasten xD
Siehe 12T, 16T und 24T

@ZeroStrat seeeehr geiles Tool :daumen:
 

Anhänge

  • 1T.JPG
    1T.JPG
    200 KB · Aufrufe: 534
  • 2 Threads.png
    2 Threads.png
    465 KB · Aufrufe: 543
  • 3 threads.png
    3 threads.png
    479,5 KB · Aufrufe: 463
  • 4T.JPG
    4T.JPG
    196,3 KB · Aufrufe: 507
  • 5T.JPG
    5T.JPG
    206,7 KB · Aufrufe: 506
  • 6t.JPG
    6t.JPG
    204,2 KB · Aufrufe: 424
  • 7t.JPG
    7t.JPG
    203,8 KB · Aufrufe: 488
  • 8t.JPG
    8t.JPG
    201,9 KB · Aufrufe: 444
  • 9t.JPG
    9t.JPG
    202,2 KB · Aufrufe: 493
  • 10t.JPG
    10t.JPG
    203,1 KB · Aufrufe: 488
  • 12T.JPG
    12T.JPG
    206 KB · Aufrufe: 488
  • 16t.JPG
    16t.JPG
    202,7 KB · Aufrufe: 451
  • 24t.JPG
    24t.JPG
    201,2 KB · Aufrufe: 499
Zuletzt bearbeitet:
@bad_sign Der Gold Star ist bei dir zufällig Core0. Bei mir wird Core0 immer priorisiert. Haben wir jetzt einen Beweis für funktionierendes CPPD oder nicht? :D
 
Er orientiert sich aber definitiv am Rating der Cores.
Ob jetzt bester oder zweitbester ... ;)
Und der schlechteste Core im letzten CCX ist ein Tabu :stock:

Mal abgesehen der Verteilung. Mit deinem Tool arbeitet mein 3900X nicht schneller als 4.2 GHz avg.
HWInfo ließt bis zu 4,5 GHz aus, was mit meinem UV die grenze darstellt.
 
Zuletzt bearbeitet:
ZeroStrat schrieb:
Wenn ich nur einen Thread verwende, dann legt der Scheduler leider diesen Thread nicht auf die "Gold Stars". Also überhaupt nicht. Da muss AMD noch nachbessern.

stell doch einfach im Taskmanager die Zugehörigkeit ein.
 
Leo.16 schrieb:
stell doch einfach im Taskmanager die Zugehörigkeit ein.
Ja, das könnte ich tun. Besser wäre natürlich ein Automatismus, der auch dann greift, wenn man selbst nicht durchblickt, welcher Thread die meiste Last verursacht.
 
Zuletzt bearbeitet von einem Moderator:
bad_sign schrieb:
Er orientiert sich aber definitiv am Rating der Cores.

Ich habe jetzt mal CPPD im BIOS explizit aktiviert. Leider ohne Erfolg. Der Scheduler präferiert nicht die besten Cores.
 
Zuletzt bearbeitet:
Kommt wohl auf´s Mainboard an?! Bin noch auf irgendeinem AB BIOS und der Scheduler macht schon immer alles richtig. Auch mit deinem Tool:

Anmerkung 2019-10-05 172305.jpg

Selbst in Spielen ist zu beobachten, wie die Hauptlast versucht wird auf dem zweiten (besseren) CCX zu halten. Auf das erste CCX kommen nur schwach genutzte Threads. Zudem wird immer nur ein Thread pro Kern verwendet, soweit wie möglich.
 
Zurück
Oben