Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace VirtualClient.Actions
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
Expand Down Expand Up @@ -80,23 +81,27 @@ public async Task LAPACKWorkloadProfileInstallsTheExpectedDependenciesOnUnixPlat
}

[Test]
[TestCase("PERF-CPU-LAPACK.json")]
public async Task LAPACKWorkloadProfileExecutesTheExpectedWorkloadsOnWindowsPlatform(string profile)
[TestCase("PERF-CPU-LAPACK.json", Architecture.X64, "win-x64")]
[TestCase("PERF-CPU-LAPACK.json", Architecture.Arm64, "win-arm64")]
public async Task LAPACKWorkloadProfileExecutesTheExpectedWorkloadsOnWindowsPlatform(
string profile,
Architecture architecture,
string platformSpecificDirectory)
{
IEnumerable<string> expectedCommands = this.GetProfileExpectedCommands(PlatformID.Win32NT);
string[] expectedFiles = new string[]
{
@"win-x64/cmakescript.sh",
@"win-x64/LapackTestScript.sh", @"win-x64/lapack_testing.py",
@"win-x64/TESTING/testing_results.txt"
$"{platformSpecificDirectory}/cmakescript.sh",
$"{platformSpecificDirectory}/LapackTestScript.sh", $"{platformSpecificDirectory}/lapack_testing.py",
$"{platformSpecificDirectory}/TESTING/testing_results.txt"
};
string cygwinPath = this.mockFixture.PlatformSpecifics.Combine("C:", "tools", "cygwin");

// Setup the expectations for the workload
// - Workload package is installed and exists.
// - Workload binaries/executables exist on the file system.
// - The workload generates valid results.
this.mockFixture.Setup(PlatformID.Win32NT);
this.mockFixture.Setup(PlatformID.Win32NT, architecture);
this.mockFixture.SetupFile(cygwinPath);
this.mockFixture.SetupPackage("lapack", expectedFiles: expectedFiles);
this.mockFixture.ProcessManager.OnCreateProcess = (command, arguments, workingDir) =>
Expand All @@ -105,7 +110,9 @@ public async Task LAPACKWorkloadProfileExecutesTheExpectedWorkloadsOnWindowsPlat
if (arguments.Contains("LapackTestScript.sh", StringComparison.OrdinalIgnoreCase))
{
process.StandardOutput.Append(TestDependencies.GetResourceFileContents("Results_LAPACK.txt"));
this.mockFixture.SetupPackage("lapack", expectedFiles: @"win-x64\TESTING\testing_results.txt");
this.mockFixture.SetupPackage(
"lapack",
expectedFiles: $@"{platformSpecificDirectory}\TESTING\testing_results.txt");
}

return process;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace VirtualClient.Actions
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
Expand Down Expand Up @@ -237,6 +238,40 @@ public void LAPACKExecutorThrowsWhenTheResultsFileIsNotGenerated()
}
}

[Test]
public async Task LAPACKExecutorReportsCancellationAsFailed_WindowsArm64()
{
this.SetupTest(PlatformID.Win32NT, Architecture.Arm64);
using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
using (TestLAPACKExecutor executor = new TestLAPACKExecutor(this.mockFixture))
{
this.mockFixture.ProcessManager.OnCreateProcess = (command, arguments, workingDirectory) =>
{
InMemoryProcess process = new InMemoryProcess();
if (arguments.Contains("LapackTestScript.sh", StringComparison.OrdinalIgnoreCase))
{
process.OnStart = () =>
{
cancellationSource.Cancel();
return true;
};
}

return process;
};

await ((VirtualClientComponent)executor).ExecuteAsync(cancellationSource.Token);

var outcomeMessages = this.mockFixture.Logger.MessagesLogged($"{executor.TypeName}.SucceededOrFailed");
Assert.AreEqual(1, outcomeMessages.Count());

EventContext outcomeContext = outcomeMessages.First().Item3 as EventContext;
Assert.IsNotNull(outcomeContext);
Assert.AreEqual("Failed", outcomeContext.Properties["metricName"]);
Assert.AreEqual(1, this.mockFixture.Logger.MessagesLogged($"{executor.TypeName}.ExecutionCancelled").Count());
}
}

private class TestLAPACKExecutor : LAPACKExecutor
{
public TestLAPACKExecutor(MockFixture fixture)
Expand Down
176 changes: 99 additions & 77 deletions src/VirtualClient/VirtualClient.Actions/LAPACK/LAPACKExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,26 @@ protected override async Task InitializeAsync(EventContext telemetryContext, Can
/// </summary>
protected override async Task ExecuteAsync(EventContext telemetryContext, CancellationToken cancellationToken)
{
using (BackgroundOperations profiling = BackgroundOperations.BeginProfiling(this, cancellationToken))
try
{
if (this.Platform == PlatformID.Unix)
using (BackgroundOperations profiling = BackgroundOperations.BeginProfiling(this, cancellationToken))
{
// Run make to generate all object files for fortran subroutines.
await this.ExecuteCommandAsync("make", null, this.packageDirectory, cancellationToken)
.ConfigureAwait(false);

// Delete results file that gets generated.
if (this.fileSystem.File.Exists(this.ResultsFilePath))
if (this.Platform == PlatformID.Unix)
{
await this.fileSystem.File.DeleteAsync(this.ResultsFilePath);
}
// Run make to generate all object files for fortran subroutines.
await this.ExecuteCommandAsync("make", null, this.packageDirectory, cancellationToken)
.ConfigureAwait(false);

using (IProcessProxy process = await this.ExecuteCommandAsync("bash", this.ScriptFilePath, this.packageDirectory, telemetryContext, cancellationToken, runElevated: true))
{
if (!cancellationToken.IsCancellationRequested)
// Delete results file that gets generated.
if (this.fileSystem.File.Exists(this.ResultsFilePath))
{
await this.fileSystem.File.DeleteAsync(this.ResultsFilePath);
}

using (IProcessProxy process = await this.ExecuteCommandAsync("bash", this.ScriptFilePath, this.packageDirectory, telemetryContext, cancellationToken, runElevated: true))
{
cancellationToken.ThrowIfCancellationRequested();

if (process.IsErrored())
{
await this.LogProcessDetailsAsync(process, telemetryContext, "LAPACK", logToFile: true);
Expand All @@ -107,22 +109,34 @@ await this.ExecuteCommandAsync("make", null, this.packageDirectory, cancellation
await this.CaptureMetricsAsync(process, this.ResultsFilePath, telemetryContext, cancellationToken);
}
}
}
else if (this.Platform == PlatformID.Win32NT)
{
await this.ExecuteCygwinBashAsync("./cmakescript.sh", this.packageDirectory, this.cygwinPackageDirectory, telemetryContext, cancellationToken)
.ConfigureAwait(false);

// Delete results file that gets generated.
if (this.fileSystem.File.Exists(this.ResultsFilePath))
else if (this.Platform == PlatformID.Win32NT)
{
await this.fileSystem.File.DeleteAsync(this.ResultsFilePath);
}
using (IProcessProxy process = await this.ExecuteCygwinBashAsync(
"./cmakescript.sh",
this.packageDirectory,
this.cygwinPackageDirectory,
telemetryContext,
cancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();

using (IProcessProxy process = await this.ExecuteCygwinBashAsync("./LapackTestScript.sh", this.packageDirectory, this.cygwinPackageDirectory, telemetryContext, cancellationToken))
{
if (!cancellationToken.IsCancellationRequested)
if (process.IsErrored())
{
await this.LogProcessDetailsAsync(process, telemetryContext, "LAPACK", logToFile: true);
process.ThrowIfWorkloadFailed();
}
}

// Delete results file that gets generated.
if (this.fileSystem.File.Exists(this.ResultsFilePath))
{
await this.fileSystem.File.DeleteAsync(this.ResultsFilePath);
}

using (IProcessProxy process = await this.ExecuteCygwinBashAsync("./LapackTestScript.sh", this.packageDirectory, this.cygwinPackageDirectory, telemetryContext, cancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();

if (process.IsErrored())
{
await this.LogProcessDetailsAsync(process, telemetryContext, "LAPACK", logToFile: true);
Expand All @@ -134,73 +148,81 @@ await this.ExecuteCygwinBashAsync("./cmakescript.sh", this.packageDirectory, thi
}
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
EventContext cancelContext = telemetryContext.Clone()
.AddContext("executionCancelled", true);

this.Logger.LogMessage($"{this.TypeName}.ExecutionCancelled", LogLevel.Information, cancelContext);

throw new WorkloadException(
"The LAPACK workload did not complete before execution was cancelled.",
ErrorReason.WorkloadFailed);
}
}

private async Task ExecuteCommandAsync(string pathToExe, string commandLineArguments, string workingDirectory, CancellationToken cancellationToken)
private Task ExecuteCommandAsync(string pathToExe, string commandLineArguments, string workingDirectory, CancellationToken cancellationToken)
{
if (!cancellationToken.IsCancellationRequested)
{
this.Logger.LogTraceMessage($"Executing process '{pathToExe}' '{commandLineArguments}' at directory '{workingDirectory}'.");
cancellationToken.ThrowIfCancellationRequested();

this.Logger.LogTraceMessage($"Executing process '{pathToExe}' '{commandLineArguments}' at directory '{workingDirectory}'.");

EventContext telemetryContext = EventContext.Persisted()
.AddContext("command", pathToExe)
.AddContext("commandArguments", commandLineArguments);
EventContext telemetryContext = EventContext.Persisted()
.AddContext("command", pathToExe)
.AddContext("commandArguments", commandLineArguments);

await this.Logger.LogMessageAsync($"{nameof(LAPACKExecutor)}.ExecuteProcess", telemetryContext, async () =>
return this.Logger.LogMessageAsync($"{nameof(LAPACKExecutor)}.ExecuteProcess", telemetryContext, async () =>
{
using (IProcessProxy process = this.systemManagement.ProcessManager.CreateElevatedProcess(this.Platform, pathToExe, commandLineArguments, workingDirectory))
{
using (IProcessProxy process = this.systemManagement.ProcessManager.CreateElevatedProcess(this.Platform, pathToExe, commandLineArguments, workingDirectory))
{
this.CleanupTasks.Add(() => process.SafeKill(this.Logger));
await process.StartAndWaitAsync(cancellationToken).ConfigureAwait();
this.CleanupTasks.Add(() => process.SafeKill(this.Logger));
await process.StartAndWaitAsync(cancellationToken).ConfigureAwait();

if (!cancellationToken.IsCancellationRequested)
{
this.LogProcessDetailsAsync(process, telemetryContext)
.ConfigureAwait();
cancellationToken.ThrowIfCancellationRequested();

process.ThrowIfErrored<WorkloadException>(errorReason: ErrorReason.WorkloadFailed);
}
}
}).ConfigureAwait();
}
await this.LogProcessDetailsAsync(process, telemetryContext)
.ConfigureAwait();

process.ThrowIfErrored<WorkloadException>(errorReason: ErrorReason.WorkloadFailed);
}
});
}

private async Task CaptureMetricsAsync(IProcessProxy process, string resultsFilePath, EventContext telemetryContext, CancellationToken cancellationToken)
{
if (!cancellationToken.IsCancellationRequested)
{
this.MetadataContract.AddForScenario(
"LAPACK",
null,
toolVersion: null,
this.PackageName);
cancellationToken.ThrowIfCancellationRequested();

this.MetadataContract.Apply(telemetryContext);
this.MetadataContract.AddForScenario(
"LAPACK",
null,
toolVersion: null,
this.PackageName);

if (!this.fileSystem.File.Exists(resultsFilePath))
{
throw new WorkloadException(
$"The LAPACK results file was not found at path '{resultsFilePath}'.",
ErrorReason.WorkloadFailed);
}
this.MetadataContract.Apply(telemetryContext);

KeyValuePair<string, string> results = await this.LoadResultsAsync(resultsFilePath, cancellationToken);
await this.LogProcessDetailsAsync(process, telemetryContext, "LAPACK", logToFile: true, results: results);

LAPACKMetricsParser lapackParser = new LAPACKMetricsParser(results.Value);
IList<Metric> metrics = lapackParser.Parse();

this.Logger.LogMetrics(
"LAPACK",
"Linear Algorithms",
process.StartTime,
process.ExitTime,
metrics,
null,
null,
this.Tags,
telemetryContext);
if (!this.fileSystem.File.Exists(resultsFilePath))
{
throw new WorkloadException(
$"The LAPACK results file was not found at path '{resultsFilePath}'.",
ErrorReason.WorkloadFailed);
}

KeyValuePair<string, string> results = await this.LoadResultsAsync(resultsFilePath, cancellationToken);
await this.LogProcessDetailsAsync(process, telemetryContext, "LAPACK", logToFile: true, results: results);

LAPACKMetricsParser lapackParser = new LAPACKMetricsParser(results.Value);
IList<Metric> metrics = lapackParser.Parse();

this.Logger.LogMetrics(
"LAPACK",
"Linear Algorithms",
process.StartTime,
process.ExitTime,
metrics,
null,
null,
this.Tags,
telemetryContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"Description": "LAPACK Performance workload",
"Metadata": {
"RecommendedMinimumExecutionTime": "(4-cores)=02:00:00,(16-cores)=04:00:00,(64-cores)=10:00:00",
"SupportedPlatforms": "linux-x64,linux-arm64",
"SupportedOperatingSystems": "CBL-Mariner,CentOS,Debian,RedHat,Suse,Ubuntu"
"SupportedPlatforms": "linux-x64,linux-arm64,win-x64,win-arm64",
"SupportedOperatingSystems": "CBL-Mariner,CentOS,Debian,RedHat,Suse,Ubuntu,Windows"
},
"Parameters": {
"CompilerVersion": ""
Expand Down
Loading