Skip to content

Commit 79738d5

Browse files
committed
Update to dynamically pull Wrathmark, compile, publish, and execute
1 parent f7db979 commit 79738d5

File tree

2 files changed

+165
-15
lines changed

2 files changed

+165
-15
lines changed

src/VirtualClient/VirtualClient.Actions/Wrathmark/WrathmarkWorkloadExecutor.cs

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
using System.Threading;
2-
using System.Threading.Tasks;
3-
using VirtualClient.Common.Telemetry;
1+
using System.IO;
42

53
namespace VirtualClient.Actions.Wrathmark
64
{
75
using System;
86
using System.Collections.Generic;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
910
using Microsoft.Extensions.DependencyInjection;
10-
using Polly.Caching;
1111

1212
using VirtualClient.Common;
1313
using VirtualClient.Common.Extensions;
14+
using VirtualClient.Common.Telemetry;
1415
using VirtualClient.Contracts;
1516

1617
/// <summary>
@@ -20,6 +21,10 @@ public class WrathmarkWorkloadExecutor : VirtualClientComponent
2021
{
2122
private readonly ISystemManagement systemManagement;
2223
private readonly ProcessManager processManager;
24+
private readonly IPackageManager packageManager;
25+
26+
private string benchmarkDirectory;
27+
private string dotnetExePath;
2328

2429
/// <summary>
2530
/// Initializes a new instance of the <see cref="WrathmarkWorkloadExecutor"/> class.
@@ -34,8 +39,21 @@ public WrathmarkWorkloadExecutor(
3439
// Follows the example, but is wrong. The services should be injected to this class, not resolved here
3540
this.systemManagement = dependencies.GetService<ISystemManagement>();
3641
this.processManager = this.systemManagement.ProcessManager;
42+
this.packageManager = this.systemManagement.PackageManager;
3743
}
3844

45+
/// <summary>
46+
/// The name of the package where the DotNetSDK package is downloaded.
47+
/// </summary>
48+
public string DotNetSdkPackageName => this.Parameters.GetValue<string>(nameof(WrathmarkWorkloadExecutor.DotNetSdkPackageName), "dotnetsdk");
49+
50+
/// <summary>
51+
/// The name of the package where the AspNetBench package is downloaded.
52+
/// </summary>
53+
public string TargetFramework =>
54+
// Lower case to prevent build path issue.
55+
this.Parameters.GetValue<string>(nameof(WrathmarkWorkloadExecutor.TargetFramework)).ToLower();
56+
3957
/// <summary>
4058
/// Name of the tool.
4159
/// </summary>
@@ -51,32 +69,125 @@ public WrathmarkWorkloadExecutor(
5169
/// </summary>
5270
protected string WorkloadExecutablePath { get; }
5371

72+
/// <inheritdoc />
73+
protected override async Task InitializeAsync(EventContext telemetryContext, CancellationToken cancellationToken)
74+
{
75+
DependencyPath workloadPackage = await this.packageManager.GetPackageAsync(
76+
this.PackageName,
77+
cancellationToken);
78+
79+
if (workloadPackage == null)
80+
{
81+
throw new DependencyException(
82+
$"The expected package '{this.PackageName}' does not exist on the system or is not registered.",
83+
ErrorReason.WorkloadDependencyMissing);
84+
}
85+
86+
const string RelativeBenchmarkPath = "wrath-sharp";
87+
this.benchmarkDirectory = this.Combine(workloadPackage.Path, RelativeBenchmarkPath);
88+
89+
DependencyPath dotnetSdkPackage = await this.packageManager.GetPackageAsync(
90+
this.DotNetSdkPackageName,
91+
cancellationToken)
92+
.ConfigureAwait(false);
93+
94+
if (dotnetSdkPackage == null)
95+
{
96+
throw new DependencyException(
97+
$"The expected package '{this.DotNetSdkPackageName}' does not exist on the system or is not registered.",
98+
ErrorReason.WorkloadDependencyMissing);
99+
}
100+
101+
this.dotnetExePath = this.Combine(dotnetSdkPackage.Path, this.Platform == PlatformID.Unix ? "dotnet" : "dotnet.exe");
102+
103+
// Build the wrath sharp project
104+
// To make native libraries that can be used, enumerate the SupportedPlatforms metadata and call publish for each
105+
// Outputs
106+
// bin/Release/net6.0/linux-x64/wrath-sharp.dll
107+
// bin/Release/net6.0/linux-x64/publish/wrath-sharp.dll
108+
string publishArgument = $"publish -c Release -r {this.PlatformArchitectureName} -f {this.TargetFramework} /p:UseSharedCompilation=false /p:BuildInParallel=false /m:1 /p:Deterministic=true /p:Optimize=true";
109+
await this.ExecuteCommandAsync(
110+
this.dotnetExePath,
111+
publishArgument,
112+
this.benchmarkDirectory,
113+
cancellationToken)
114+
.ConfigureAwait(false);
115+
}
116+
54117
/// <summary>
55118
/// Executes the Wrathmark component logic.
56119
/// </summary>
57120
/// <param name="telemetryContext">Provides context information that will be captured with telemetry events.</param>
58121
/// <param name="cancellationToken">A token that can be used to cancel the operation.</param>
59122
protected override async Task ExecuteAsync(EventContext telemetryContext, CancellationToken cancellationToken)
60123
{
124+
// Example: ./bin/Release/net6.0/linux-x64/publish
125+
string outputDirectory = Path.Combine(
126+
this.benchmarkDirectory,
127+
"bin",
128+
"Release",
129+
this.TargetFramework,
130+
this.PlatformArchitectureName,
131+
"Publish");
132+
61133
this.Logger.LogTraceMessage(
62134
$"{nameof(WrathmarkWorkloadExecutor)}.Starting",
63135
telemetryContext);
64136

65137
var startTime = DateTime.UtcNow;
66138

67-
var results = await this.ExecuteWorkloadAsync(telemetryContext, cancellationToken);
139+
var results = await this.ExecuteWorkloadAsync(
140+
this.dotnetExePath,
141+
$"run {outputDirectory} --framework ${this.TargetFramework}",
142+
this.benchmarkDirectory,
143+
telemetryContext,
144+
cancellationToken);
68145

69146
var endTime = DateTime.UtcNow;
70147

71148
await this.CaptureMetricsAsync(results, startTime, endTime, telemetryContext, cancellationToken);
72149
}
73150

74-
private Task<string> ExecuteWorkloadAsync(EventContext telemetryContext, CancellationToken cancellationToken)
151+
private async Task ExecuteCommandAsync(
152+
string pathToExe,
153+
string commandLineArguments,
154+
string workingDirectory,
155+
CancellationToken cancellationToken)
156+
{
157+
if (!cancellationToken.IsCancellationRequested)
158+
{
159+
this.Logger.LogTraceMessage(
160+
$"Executing process '{pathToExe}' '{commandLineArguments}' at directory '{workingDirectory}'.");
161+
162+
EventContext telemetryContext = EventContext.Persisted()
163+
.AddContext("command", pathToExe)
164+
.AddContext("commandArguments", commandLineArguments);
165+
166+
using (IProcessProxy process =
167+
this.systemManagement.ProcessManager.CreateElevatedProcess(
168+
this.Platform,
169+
pathToExe,
170+
commandLineArguments,
171+
workingDirectory))
172+
{
173+
this.CleanupTasks.Add(() => process.SafeKill());
174+
await process.StartAndWaitAsync(cancellationToken).ConfigureAwait(false);
175+
176+
if (!cancellationToken.IsCancellationRequested)
177+
{
178+
await this.LogProcessDetailsAsync(process, telemetryContext);
179+
}
180+
}
181+
}
182+
}
183+
184+
private Task<string> ExecuteWorkloadAsync(string command, string arguments, string workingDirectory, EventContext telemetryContext, CancellationToken cancellationToken)
75185
{
76186
EventContext relatedContext = telemetryContext.Clone()
77187
.AddContext("packageName", this.PackageName)
78-
.AddContext("packagePath", this.WorkloadPackage.Path)
79-
.AddContext("command", this.WorkloadExecutablePath)
188+
.AddContext("packagePath", workingDirectory)
189+
.AddContext("command", command)
190+
.AddContext("arguments", arguments)
80191
;
81192

82193
return this.Logger.LogMessageAsync($"{nameof(WrathmarkWorkloadExecutor)}.ExecuteWorkload", relatedContext, async () =>
@@ -88,7 +199,7 @@ private Task<string> ExecuteWorkloadAsync(EventContext telemetryContext, Cancell
88199
{
89200
// We create a operating system process to host the executing workload, start it and
90201
// wait for it to exit.
91-
using (IProcessProxy workloadProcess = this.processManager.CreateProcess(this.WorkloadExecutablePath, null, this.WorkloadPackage.Path))
202+
using (IProcessProxy workloadProcess = this.processManager.CreateProcess(command, arguments, workingDirectory))
92203
{
93204
this.CleanupTasks.Add(() => workloadProcess.SafeKill());
94205

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,57 @@
11
{
22
"Description": "Wrathmark CPU Performance Workload",
33
"Metadata": {
4-
"RecommendedMinimumExecutionTime": "01:00:00",
5-
"SupportedPlatforms": "win-x64",
6-
"SupportedOperatingSystems": "Windows"
4+
"RecommendedMinimumExecutionTime": "00:05:00",
5+
"SupportedPlatforms": "linux-x64,linux-arm64,win-x64,win-arm64",
6+
"SupportedOperatingSystems": "CBL-Mariner,Ubuntu,Windows",
7+
},
8+
"Parameters": {
9+
"DotNetVersion": "7.0.401",
10+
"TargetFramework": "net7.0"
711
},
8-
"Parameters": {},
912
"Actions": [
1013
{
1114
"Type": "WrathmarkWorkloadExecutor",
1215
"Parameters": {
13-
"Scenario": "Othello",
16+
"Scenario": "WrathmarkBenchmark",
17+
"PackageName": "Wrathmark",
18+
"DotNetSdkPackageName": "dotnetsdk",
19+
"TargetFramework": "$.Parameters.TargetFramework",
1420
"Tags": "CPU"
1521
}
1622
}
23+
],
24+
"Dependencies": [
25+
{
26+
"Type": "ChocolateyInstallation",
27+
"Parameters": {
28+
"Scenario": "InstallChocolatey",
29+
"PackageName": "chocolatey"
30+
}
31+
},
32+
{
33+
"Type": "ChocolateyPackageInstallation",
34+
"Parameters": {
35+
"Scenario": "InstallGit",
36+
"PackageName": "chocolatey",
37+
"Packages": "git"
38+
}
39+
},
40+
{
41+
"Type": "GitRepoClone",
42+
"Parameters": {
43+
"Scenario": "CloneWrathOthelloRepo",
44+
"RepoUri": "https://github.com/ricomariani/wrath-othello.git",
45+
"PackageName": "Wrathmark"
46+
}
47+
},
48+
{
49+
"Type": "DotNetInstallation",
50+
"Parameters": {
51+
"Scenario": "InstallDotNetSdk",
52+
"DotNetVersion": "$.Parameters.DotNetVersion",
53+
"PackageName": "dotnetsdk"
54+
}
55+
}
1756
]
18-
}
57+
}

0 commit comments

Comments
 (0)