Skip to content
Merged
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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.49
2.1.50
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void GeekBenchParserVerifySingleCoreResult()
}

[Test]
public void GeekBench5ParserVerifyMetricsSingleCore()
public void GeekBench5ParserVerifyMetricsSingleCore_Test()
{
string outputPath = Path.Combine(workingDirectory, "Examples", "Geekbench", "GeekBench5Example.txt");
this.rawText = File.ReadAllText(outputPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace VirtualClient.Actions
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
Expand Down Expand Up @@ -161,22 +162,20 @@ protected override async Task InitializeAsync(EventContext telemetryContext, Can
{
using (IProcessProxy process = this.processManager.CreateProcess(this.ExecutablePath, $"--unlock {email} {licenseKey}"))
{
this.CleanupTasks.Add(() =>
try
{
// Note:
// Issues were found on Linux/ARM64 systems with the process failing to be killed
// using standard .NET logic. This happens on Ampere systems with lots of cores.
// We are using the 'kill -9' option as a workaround.
this.processManager.SafeKill(process, this.Logger);
});
await process.StartAndWaitAsync(cancellationToken, withExitConfirmation: true);

await process.StartAndWaitAsync(cancellationToken);

if (!cancellationToken.IsCancellationRequested)
if (!cancellationToken.IsCancellationRequested)
{
await this.LogProcessDetailsAsync(process, telemetryContext, this.PackageName);
process.ThrowIfDependencyInstallationFailed();
}
}
finally
{
await this.LogProcessDetailsAsync(process, telemetryContext, this.PackageName, logToFile: true);

process.ThrowIfDependencyInstallationFailed();
process.Close();
process.SafeKill(this.Logger, TimeSpan.FromSeconds(30));
}
}
}
Expand Down Expand Up @@ -213,6 +212,7 @@ private void CaptureMetrics(IProcessProxy process, string standardOutput, string
// using workload name as testName
GeekBenchMetricsParser geekbenchMetricsParser = new GeekBenchMetricsParser(standardOutput);
IList<Metric> metrics = geekbenchMetricsParser.Parse();

foreach (Metric metric in metrics)
{
this.Logger.LogMetric(
Expand Down Expand Up @@ -259,24 +259,23 @@ private Task ExecuteWorkloadAsync(string pathToExe, string commandLineArguments,
{
using (IProcessProxy process = this.processManager.CreateProcess(pathToExe, commandLineArguments))
{
this.CleanupTasks.Add(() =>
try
{
// Note:
// Issues were found on Linux/ARM64 systems with the process failing to be killed
// using standard .NET logic. This happens on Ampere systems with lots of cores.
// We are using the 'kill -9' option as a workaround.
this.processManager.SafeKill(process, this.Logger);
});
await process.StartAndWaitAsync(cancellationToken, withExitConfirmation: true);

await process.StartAndWaitAsync(cancellationToken);
if (!cancellationToken.IsCancellationRequested)
{
await this.LogProcessDetailsAsync(process, telemetryContext, this.PackageName);
process.ThrowIfWorkloadFailed();

if (!cancellationToken.IsCancellationRequested)
string standardOutput = process.StandardOutput.ToString();
this.CaptureMetrics(process, standardOutput, commandLineArguments, telemetryContext, cancellationToken);
}
}
finally
{
await this.LogProcessDetailsAsync(process, telemetryContext, this.PackageName, logToFile: true);
process.ThrowIfWorkloadFailed();

string standardOutput = process.StandardOutput.ToString();
this.CaptureMetrics(process, standardOutput, commandLineArguments, telemetryContext, cancellationToken);
process.Close();
process.SafeKill(this.Logger, TimeSpan.FromSeconds(30));
}
}
}
Expand Down
44 changes: 24 additions & 20 deletions src/VirtualClient/VirtualClient.Actions/Prime95/Prime95Executor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,39 +293,43 @@ await this.Logger.LogMessageAsync($"{this.TypeName}.ExecuteWorkload", telemetryC
{
using (IProcessProxy process = this.systemManagement.ProcessManager.CreateProcess(this.ExecutablePath, commandArguments, this.WorkloadPackage.Path))
{
this.CleanupTasks.Add(() => process.SafeKill());

// Prime95 does not stop on it's own. It will run until you tell it to stop.
// We have to definitively stop the program.
DateTime explicitTimeout = DateTime.UtcNow.Add(this.Duration);

if (process.Start())
{
await this.WaitAsync(explicitTimeout, cancellationToken);
process.SafeKill();

if (!cancellationToken.IsCancellationRequested)
try
{
KeyValuePair<string, string> results = default;
await this.WaitAsync(explicitTimeout, cancellationToken);

if (this.fileSystem.File.Exists(this.ResultsFilePath))
if (!cancellationToken.IsCancellationRequested)
{
await RetryPolicies.FileOperations.ExecuteAsync(async () =>
KeyValuePair<string, string> results = default;

if (this.fileSystem.File.Exists(this.ResultsFilePath))
{
results = await this.LoadResultsAsync(this.ResultsFilePath, cancellationToken);
});
}
await RetryPolicies.FileOperations.ExecuteAsync(async () =>
{
results = await this.LoadResultsAsync(this.ResultsFilePath, cancellationToken);
});
}

await this.LogProcessDetailsAsync(process, telemetryContext, "Prime95", results: results);
await this.LogProcessDetailsAsync(process, telemetryContext, "Prime95", results: results);

// The exit code on SafeKill is -1 which is not a part of the default success codes.
process.ThrowIfWorkloadFailed(this.successExitCodes);
// The exit code on SafeKill is -1 which is not a part of the default success codes.
process.ThrowIfWorkloadFailed(this.successExitCodes);

if (!string.IsNullOrWhiteSpace(results.Value))
{
this.CaptureMetrics(process, results.Value, telemetryContext, cancellationToken);
if (!string.IsNullOrWhiteSpace(results.Value))
{
this.CaptureMetrics(process, results.Value, telemetryContext, cancellationToken);
}
}
}
finally
{
// Prime95 does not stop on it's own. It will run until you tell it to stop.
// We have to definitively stop the program.
process.SafeKill(this.Logger);
}
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public static class TextParsingExtensions
public static readonly string EmailRegex = @"[\w\-\.]+@([\w -]+\.)+[\w-]{2,}";

private static readonly Regex CommaDelimitedExpression = new Regex(",", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex NewLineExpression = new Regex("\r\n|\n", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex SemiColonDelimitedExpression = new Regex(";", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex TripleCommaDelimitedExpression = new Regex(",,,", RegexOptions.Compiled | RegexOptions.IgnoreCase);

Expand All @@ -70,7 +71,7 @@ public static class TextParsingExtensions
public static string RemoveRows(string text, Regex delimiter)
{
List<string> result = new List<string>();
List<string> rows = text.Split(Environment.NewLine, StringSplitOptions.None).ToList();
List<string> rows = NewLineExpression.Split(text).ToList();

foreach (string row in rows)
{
Expand All @@ -91,17 +92,25 @@ public static string RemoveRows(string text, Regex delimiter)
public static IDictionary<string, string> Sectionize(string text, Regex delimiter)
{
IDictionary<string, string> result = new Dictionary<string, string>();
string[] sections = Regex.Split(text, delimiter.ToString(), delimiter.Options);
IEnumerable<string> sections = Regex.Split(text, delimiter.ToString(), delimiter.Options)
.Where(s => !string.IsNullOrWhiteSpace(s?.Trim()));

foreach (string section in sections)
if (sections?.Any() == true)
{
if (!string.IsNullOrWhiteSpace(section))
foreach (string section in sections)
{
List<string> rows = section.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries).ToList();
string sectionName = rows.FirstOrDefault().Trim();
rows.RemoveAt(0);

result.Add(sectionName, string.Join(Environment.NewLine, rows.Select(r => r.Trim())));
string sectionInfo = section?.Trim();
if (!string.IsNullOrWhiteSpace(sectionInfo))
{
List<string> rows = NewLineExpression.Split(sectionInfo).ToList();
if (rows?.Any() == true)
{
string sectionName = rows.FirstOrDefault().Trim();
rows.RemoveAt(0);

result.Add(sectionName, string.Join(Environment.NewLine, rows.Select(r => r.Trim())));
}
}
}
}

Expand Down Expand Up @@ -389,7 +398,7 @@ public static string TranslateStorageByUnit(string text, string metricUnit)
public static IDictionary<string, string> Sectionize(string text, IDictionary<string, Regex> matchingRegexes)
{
IDictionary<string, string> result = new Dictionary<string, string>();
List<string> rows = text.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries).ToList();
List<string> rows = NewLineExpression.Split(text).ToList();

foreach (KeyValuePair<string, Regex> section in matchingRegexes)
{
Expand Down
41 changes: 21 additions & 20 deletions src/VirtualClient/VirtualClient.Contracts/VirtualClientComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ public async Task ExecuteAsync(CancellationToken cancellationToken)

try
{
this.CleanupTasks.Clear();
PlatformSpecifics.ThrowIfNotSupported(this.Platform);
PlatformSpecifics.ThrowIfNotSupported(this.CpuArchitecture);

Expand Down Expand Up @@ -786,9 +787,8 @@ await this.Logger.LogMessageAsync($"{this.TypeName}.Execute", telemetryContext,
{
this.EndTime = DateTime.UtcNow;
this.LogSuccessOrFailedMetric(succeeded, scenarioStartTime: this.StartTime, scenarioEndTime: this.EndTime, telemetryContext: telemetryContext);
await this.CleanupAsync(telemetryContext, cancellationToken);
}

await this.CleanupAsync(telemetryContext, cancellationToken);
});
}
}
Expand All @@ -804,31 +804,32 @@ await this.Logger.LogMessageAsync($"{this.TypeName}.Execute", telemetryContext,
/// </summary>
protected virtual Task CleanupAsync(EventContext telemetryContext, CancellationToken cancellationToken)
{
if (this.CleanupTasks.Any())
return Task.Run(() =>
{
try
if (this.CleanupTasks.Any())
{
foreach (Action cleanupTask in this.CleanupTasks)
try
{
try
{
cleanupTask.Invoke();
}
catch (Exception exc)
foreach (Action cleanupTask in this.CleanupTasks)
{
// Best effort...but logged
this.Logger.LogMessage($"{this.TypeName}.CleanupError", LogLevel.Warning, telemetryContext.Clone().AddError(exc));
try
{
cleanupTask.Invoke();
}
catch (Exception exc)
{
// Best effort...but logged
this.Logger.LogMessage($"{this.TypeName}.CleanupError", LogLevel.Warning, telemetryContext.Clone().AddError(exc));
}
}
}
catch (Exception exc)
{
// Best effort...but logged
this.Logger.LogMessage($"{this.TypeName}.CleanupError", LogLevel.Warning, telemetryContext.Clone().AddError(exc));
}
}
catch (Exception exc)
{
// Best effort...but logged
this.Logger.LogMessage($"{this.TypeName}.CleanupError", LogLevel.Warning, telemetryContext.Clone().AddError(exc));
}
}

return Task.CompletedTask;
});
}

/// <summary>
Expand Down
Loading
Loading