diff --git a/common/Perf/Azure.Test.Perf/Azure.Test.Perf.csproj b/common/Perf/Azure.Test.Perf/Azure.Test.Perf.csproj
index 6debc3b1af67..0417ce0d6823 100644
--- a/common/Perf/Azure.Test.Perf/Azure.Test.Perf.csproj
+++ b/common/Perf/Azure.Test.Perf/Azure.Test.Perf.csproj
@@ -8,4 +8,8 @@
+
+
+
+
diff --git a/common/Perf/Azure.Test.Perf/PerfOptions.cs b/common/Perf/Azure.Test.Perf/PerfOptions.cs
index 6fdd2fdf2eab..dbd95980dac3 100644
--- a/common/Perf/Azure.Test.Perf/PerfOptions.cs
+++ b/common/Perf/Azure.Test.Perf/PerfOptions.cs
@@ -37,6 +37,9 @@ public class PerfOptions
[Option('r', "rate", HelpText = "Target throughput (ops/sec)")]
public int? Rate { get; set; }
+ [Option("status-interval", Default = 1, HelpText = "Interval to write status to console in seconds")]
+ public int StatusInterval { get; set; }
+
[Option("sync", HelpText = "Runs sync version of test")]
public bool Sync { get; set; }
diff --git a/common/Perf/Azure.Test.Perf/PerfProgram.cs b/common/Perf/Azure.Test.Perf/PerfProgram.cs
index df379728f437..0ecf35f43e3e 100644
--- a/common/Perf/Azure.Test.Perf/PerfProgram.cs
+++ b/common/Perf/Azure.Test.Perf/PerfProgram.cs
@@ -1,13 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using Azure.Test.PerfStress;
using CommandLine;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
-using System.Reflection.Emit;
using System.Runtime;
using System.Text.Json;
using System.Threading;
@@ -31,12 +31,12 @@ public static async Task Main(Assembly assembly, string[] args)
if (testTypes.Any())
{
- var optionTypes = GetOptionTypes(testTypes);
- await Parser.Default.ParseArguments(args, optionTypes).MapResult(
+ var optionTypes = PerfStressUtilities.GetOptionTypes(testTypes);
+ await PerfStressUtilities.Parser.ParseArguments(args, optionTypes).MapResult(
async o =>
{
var verbName = o.GetType().GetCustomAttribute().Name;
- var testType = testTypes.Where(t => GetVerbName(t.Name) == verbName).Single();
+ var testType = testTypes.Where(t => PerfStressUtilities.GetVerbName(t.Name) == verbName).Single();
await Run(testType, o);
},
errors => Task.CompletedTask
@@ -83,7 +83,7 @@ private static async Task Run(Type testType, PerfOptions options)
Console.WriteLine();
using var setupStatusCts = new CancellationTokenSource();
- var setupStatusThread = PrintStatus("=== Setup ===", () => ".", newLine: false, setupStatusCts.Token);
+ var setupStatusThread = PerfStressUtilities.PrintStatus("=== Setup ===", () => ".", newLine: false, setupStatusCts.Token);
using var cleanupStatusCts = new CancellationTokenSource();
Thread cleanupStatusThread = null;
@@ -109,7 +109,8 @@ private static async Task Run(Type testType, PerfOptions options)
if (options.Warmup > 0)
{
- await RunTestsAsync(tests, options.Sync, options.Parallel, options.Rate, options.Warmup, "Warmup");
+ await RunTestsAsync(tests, options.Sync, options.Parallel, options.Rate, options.Warmup, options.StatusInterval,
+ "Warmup");
}
for (var i = 0; i < options.Iterations; i++)
@@ -119,7 +120,8 @@ private static async Task Run(Type testType, PerfOptions options)
{
title += " " + (i + 1);
}
- await RunTestsAsync(tests, options.Sync, options.Parallel, options.Rate, options.Duration, title, options.JobStatistics, options.Latency);
+ await RunTestsAsync(tests, options.Sync, options.Parallel, options.Rate, options.Duration, options.StatusInterval,
+ title, options.JobStatistics, options.Latency);
}
}
finally
@@ -128,7 +130,7 @@ private static async Task Run(Type testType, PerfOptions options)
{
if (cleanupStatusThread == null)
{
- cleanupStatusThread = PrintStatus("=== Cleanup ===", () => ".", newLine: false, cleanupStatusCts.Token);
+ cleanupStatusThread = PerfStressUtilities.PrintStatus("=== Cleanup ===", () => ".", newLine: false, cleanupStatusCts.Token);
}
await Task.WhenAll(tests.Select(t => t.CleanupAsync()));
@@ -141,7 +143,7 @@ private static async Task Run(Type testType, PerfOptions options)
{
if (cleanupStatusThread == null)
{
- cleanupStatusThread = PrintStatus("=== Cleanup ===", () => ".", newLine: false, cleanupStatusCts.Token);
+ cleanupStatusThread = PerfStressUtilities.PrintStatus("=== Cleanup ===", () => ".", newLine: false, cleanupStatusCts.Token);
}
await tests[0].GlobalCleanupAsync();
@@ -161,7 +163,7 @@ private static async Task Run(Type testType, PerfOptions options)
}
private static async Task RunTestsAsync(IPerfTest[] tests, bool sync, int parallel, int? rate,
- int durationSeconds, string title, bool jobStatistics = false, bool latency = false)
+ int durationSeconds, int statusIntervalSeconds, string title, bool jobStatistics = false, bool latency = false)
{
_completedOperations = new int[parallel];
_lastCompletionTimes = new TimeSpan[parallel];
@@ -191,7 +193,7 @@ private static async Task RunTestsAsync(IPerfTest[] tests, bool sync, int parall
var lastCompleted = 0;
using var progressStatusCts = new CancellationTokenSource();
- var progressStatusThread = PrintStatus(
+ var progressStatusThread = PerfStressUtilities.PrintStatus(
$"=== {title} ===" + Environment.NewLine +
"Current\t\tTotal",
() =>
@@ -202,7 +204,9 @@ private static async Task RunTestsAsync(IPerfTest[] tests, bool sync, int parall
return currentCompleted + "\t\t" + totalCompleted;
},
newLine: true,
- progressStatusCts.Token);
+ progressStatusCts.Token,
+ statusIntervalSeconds
+ );
Thread pendingOperationsThread = null;
if (rate.HasValue)
@@ -375,7 +379,7 @@ private static async Task RunLoopAsync(IPerfTest test, int index, bool latency,
catch (Exception e)
{
// Ignore if any part of the exception chain is type OperationCanceledException
- if (!ContainsOperationCanceledException(e))
+ if (!PerfStressUtilities.ContainsOperationCanceledException(e))
{
throw;
}
@@ -406,112 +410,5 @@ private static Thread WritePendingOperations(int rate, CancellationToken token)
return thread;
}
-
- // Run in dedicated thread instead of using async/await in ThreadPool, to ensure this thread has priority
- // and never fails to run to due ThreadPool starvation.
- private static Thread PrintStatus(string header, Func