-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathProgram.cs
151 lines (123 loc) · 5.41 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security.Principal;
using Microsoft.Extensions.Configuration;
namespace TimerBenchmark;
internal abstract class TimerBenchmark
{
private static bool? _isAdmin;
private static bool IsAdmin()
{
if (_isAdmin == null)
{
_isAdmin = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
}
return _isAdmin.Value;
}
[RequiresDynamicCode("Calls Microsoft.Extensions.Configuration.ConfigurationBinder.Get<T>()")]
[RequiresUnreferencedCode("Calls Microsoft.Extensions.Configuration.ConfigurationBinder.Get<T>()")]
private static async Task Main()
{
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
BenchmarkingParameters? parameters = config.GetSection("BenchmarkingParameters").Get<BenchmarkingParameters>();
if (parameters is null)
{
Console.WriteLine("Error: Unable to read configuration parameters.");
return;
}
if (!IsAdmin())
{
await Console.Error.WriteLineAsync("error: administrator privileges required");
Environment.Exit(1);
}
decimal iterations =
(decimal)(parameters.EndValue - parameters.StartValue) / (decimal)parameters.IncrementValue;
decimal totalMinutes = iterations * parameters.SampleValue * 2 / 60000m; // Assuming Sleep(1) = ~2ms
Console.WriteLine($"Approximate worst-case estimated time for completion: {Math.Round(totalMinutes, 2)} mins");
Console.WriteLine("Worst-case is determined by assuming Sleep(1) = ~2ms with 1ms Timer Resolution");
Console.WriteLine(
$"Start: {parameters.StartValue}, End: {parameters.EndValue}, Increment: {parameters.IncrementValue}, Samples: {parameters.SampleValue}");
KillProcess("SetTimerResolution");
string currentDirectory = Environment.CurrentDirectory;
string[] dependencies = new[] { "SetTimerResolution.exe", "MeasureSleep.exe" };
bool hasMissingDependencies = false;
object missingDependenciesLock = new object();
Parallel.ForEach(dependencies, dependency =>
{
string fullPath = Path.Combine(currentDirectory, dependency);
if (!File.Exists(fullPath))
{
lock (missingDependenciesLock)
{
if (!hasMissingDependencies)
{
Console.WriteLine($"Error: {dependency} does not exist in the current directory");
hasMissingDependencies = true;
}
}
}
});
if (hasMissingDependencies)
{
return;
}
string content = "RequestedResolutionMs,DeltaMs,STDEV";
await File.WriteAllTextAsync("results.txt", content);
for (double i = parameters.StartValue; i <= parameters.EndValue; i += parameters.IncrementValue)
{
double formattedValue = Math.Round(i, 4, MidpointRounding.AwayFromZero);
Console.WriteLine($"info: benchmarking {formattedValue}");
int resolution = (int)(formattedValue * 1E4);
await Task.Run(() =>
{
Process.Start(Path.Combine(currentDirectory, "SetTimerResolution.exe"),
$"--resolution {resolution} --no-console");
});
// Delay after setting resolution
await Task.Delay(1);
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = Path.Combine(currentDirectory, "MeasureSleep.exe"),
Arguments = $"--samples {parameters.SampleValue}",
UseShellExecute = false,
RedirectStandardOutput = true
};
Process? process = Process.Start(startInfo);
string output = await process?.StandardOutput.ReadToEndAsync()!;
await process.WaitForExitAsync();
string[] outputLines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
(double avg, double stdev) = (0, 0);
foreach (var line in outputLines)
{
if (line.StartsWith("Avg: ") && double.TryParse(line.AsSpan(5), out var parsedAvg))
{
avg = parsedAvg;
}
else if (line.StartsWith("STDEV: ") && double.TryParse(line.AsSpan(7), out var parsedStdev))
{
stdev = parsedStdev;
}
}
string resultLine = $"{formattedValue}, {Math.Round(avg, 4)}, {stdev}{Environment.NewLine}";
await File.AppendAllTextAsync("results.txt", resultLine);
KillProcess("SetTimerResolution");
}
Console.WriteLine("info: results saved in results.txt");
}
private class BenchmarkingParameters
{
public double StartValue { get; init; }
public double IncrementValue { get; init; }
public double EndValue { get; init; }
public int SampleValue { get; init; }
}
private static void KillProcess(string processName)
{
foreach (var process in Process.GetProcessesByName(processName))
{
process.Kill();
}
}
}