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:
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
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
Zuletzt bearbeitet von einem Moderator: