Skip to content

Commit af70532

Browse files
AlexW-FAlex Williams-FerreiraCopilot
authored
Parameterize NAS Parallel Benchmark profile for ThreadCount and Bench… (#662)
* Parameterize NAS Parallel Benchmark profile for ThreadCount and Benchmarkclass - Add ThreadCount profile parameter (default: LogicalCoreCount - 2) to replace hard-coded Environment.ProcessorCount for OMP_NUM_THREADS. Uses ParametersOn guard to set ThreadCount=1 on systems with 2 or fewer cores. - Add Benchmarkclass profile parameter (default: C) to replace previously hard-coded class D benchmark references. IS and DC benchmarks remain pinned to classes C and B respectively due to NPB limitations. - Add ThreadCount property to NASParallelBenchClientExecutor with fallback to Environment.ProcessorCount if not specified. - Add unit test for custom ThreadCount override. - Add Resource Requirements section to documentation with memory estimation formulas and per-class sizing table. - Document ThreadCount, Benchmarkclass parameters, and pinned benchmark classes in workload profiles documentation. * Fix functional tests and remove dc benchmark from profile - Fix NASParallelBenchProfileTests to derive expected ThreadCount from mock CpuInfo.LogicalProcessorCount rather than Environment.ProcessorCount, matching how the ProfileExpressionEvaluator resolves {LogicalCoreCount}. - Remove dc benchmark action from profile (dc not reliably compiled). - Remove dc.B.x from expected commands and expectedFiles in tests. - Deduplicate X64/Arm64 test branches using platformDir variable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * unpinned benchmark that didn't need to be * Updated documentation for last commit --------- Co-authored-by: Alex Williams-Ferreira <alexwill@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f1d5410 commit af70532

6 files changed

Lines changed: 244 additions & 121 deletions

File tree

src/VirtualClient/VirtualClient.Actions.FunctionalTests/NASParallelBenchProfileTests.cs

Lines changed: 37 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void NASParallelWorkloadProfileParametersAreInlinedCorrectly(string profi
3838
WorkloadAssert.ParameterReferencesInlined(executor.Profile);
3939
}
4040
}
41-
41+
4242
[Test]
4343
[TestCase("PERF-HPC-NASPARALLELBENCH.json", PlatformID.Unix, Architecture.X64)]
4444
[TestCase("PERF-HPC-NASPARALLELBENCH.json", PlatformID.Unix, Architecture.Arm64)]
@@ -73,8 +73,14 @@ public async Task NASParallelWorkloadProfileExecutesTheExpectedWorkloadsOnUnixPl
7373
{
7474
await executor.ExecuteAsync(ProfileTiming.OneIteration(), CancellationToken.None).ConfigureAwait(false);
7575

76-
var expectedCommands = this.GetProfileExpectedCommands(platform, architecture);
77-
76+
// The profile uses {calculate({LogicalCoreCount} - 2)} for ThreadCount.
77+
// Read the mock CpuInfo to derive the expected value dynamically.
78+
CpuInfo cpuInfo = await this.mockFixture.SystemManagement.Object
79+
.GetCpuInfoAsync(CancellationToken.None).ConfigureAwait(false);
80+
81+
int expectedThreadCount = cpuInfo.LogicalProcessorCount - 2;
82+
var expectedCommands = this.GetProfileExpectedCommands(expectedThreadCount, platform, architecture);
83+
7884
WorkloadAssert.CommandsExecuted(this.mockFixture, expectedCommands.ToArray());
7985
}
8086
}
@@ -86,7 +92,7 @@ public void NASParallelWorkloadProfileActionsWillNotBeExecutedIfTheWorkloadPacka
8692
{
8793
this.SetupDefaultMockBehavior(platform, architecture);
8894
// We ensure the workload package does not exist.
89-
95+
9096
this.mockFixture.PackageManager.Clear();
9197

9298
using (ProfileExecutor executor = TestDependencies.CreateProfileExecutor(profile, this.mockFixture.Dependencies))
@@ -97,84 +103,44 @@ public void NASParallelWorkloadProfileActionsWillNotBeExecutedIfTheWorkloadPacka
97103
}
98104
}
99105

100-
private IEnumerable<string> GetProfileExpectedCommands(PlatformID platform = PlatformID.Unix, Architecture architecture = Architecture.X64)
106+
private IEnumerable<string> GetProfileExpectedCommands(int expectedThreadCount, PlatformID platform = PlatformID.Unix, Architecture architecture = Architecture.X64)
101107
{
102-
List<string> commands = null;
103-
if (architecture == Architecture.X64)
104-
{
105-
commands = new List<string>
106-
{
107-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/bt.D.x\"",
108-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/cg.D.x\"",
109-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/ep.D.x\"",
110-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/ft.D.x\"",
111-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/is.C.x\"",
112-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/lu.D.x\"",
113-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/mg.D.x\"",
114-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/sp.D.x\"",
115-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/ua.D.x\"",
116-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-x64/NPB-OMP/bin/dc.B.x\"",
117-
};
118-
}
119-
else
108+
string platformDir = architecture == Architecture.X64 ? "linux-x64" : "linux-arm64";
109+
110+
List<string> commands = new List<string>
120111
{
121-
commands = new List<string>
122-
{
123-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/bt.D.x",
124-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/cg.D.x\"",
125-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/ep.D.x\"",
126-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/ft.D.x\"",
127-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/is.C.x\"",
128-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/lu.D.x\"",
129-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/mg.D.x\"",
130-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/sp.D.x\"",
131-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/ua.D.x\"",
132-
$"bash -c \"export OMP_NUM_THREADS={Environment.ProcessorCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/linux-arm64/NPB-OMP/bin/dc.B.x\"",
133-
};
134-
}
112+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/bt.C.x\"",
113+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/cg.C.x\"",
114+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/ep.C.x\"",
115+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/ft.C.x\"",
116+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/is.C.x\"",
117+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/lu.C.x\"",
118+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/mg.C.x\"",
119+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/sp.C.x\"",
120+
$"bash -c \"export OMP_NUM_THREADS={expectedThreadCount} && /home/user/tools/VirtualClient/packages/nasparallelbench/{platformDir}/NPB-OMP/bin/ua.C.x\"",
121+
};
135122

136123
return commands;
137124
}
138125

139126
private void SetupDefaultMockBehavior(PlatformID platform = PlatformID.Unix, Architecture architecture = Architecture.X64)
140127
{
141128
this.mockFixture.Setup(platform, architecture);
142-
string[] expectedFiles = null;
129+
string platformDir = architecture == Architecture.X64 ? "linux-x64" : "linux-arm64";
143130

144-
if (architecture == Architecture.X64)
145-
{
146-
expectedFiles = new string[]
147-
{
148-
@"linux-x64/NPB-OMP/bin/bt.D.x",
149-
@"linux-x64/NPB-OMP/bin/cg.D.x",
150-
@"linux-x64/NPB-OMP/bin/ep.D.x",
151-
@"linux-x64/NPB-OMP/bin/ft.D.x",
152-
@"linux-x64/NPB-OMP/bin/is.C.x",
153-
@"linux-x64/NPB-OMP/bin/lu.D.x",
154-
@"linux-x64/NPB-OMP/bin/mg.D.x",
155-
@"linux-x64/NPB-OMP/bin/sp.D.x",
156-
@"linux-x64/NPB-OMP/bin/ua.D.x",
157-
@"linux-x64/NPB-OMP/bin/dc.B.x",
158-
@"linux-x64/NPB-OMP/bin/dt.D.x"
159-
};
160-
}
161-
else
131+
string[] expectedFiles = new string[]
162132
{
163-
expectedFiles = new string[]
164-
{
165-
@"linux-arm64/NPB-OMP/bin/bt.D.x",
166-
@"linux-arm64/NPB-OMP/bin/cg.D.x",
167-
@"linux-arm64/NPB-OMP/bin/ep.D.x",
168-
@"linux-arm64/NPB-OMP/bin/ft.D.x",
169-
@"linux-arm64/NPB-OMP/bin/is.C.x",
170-
@"linux-arm64/NPB-OMP/bin/lu.D.x",
171-
@"linux-arm64/NPB-OMP/bin/mg.D.x",
172-
@"linux-arm64/NPB-OMP/bin/sp.D.x",
173-
@"linux-arm64/NPB-OMP/bin/ua.D.x",
174-
@"linux-arm64/NPB-OMP/bin/dc.B.x",
175-
@"linux-arm64/NPB-OMP/bin/dt.D.x"
176-
};
177-
}
133+
$@"{platformDir}/NPB-OMP/bin/bt.C.x",
134+
$@"{platformDir}/NPB-OMP/bin/cg.C.x",
135+
$@"{platformDir}/NPB-OMP/bin/ep.C.x",
136+
$@"{platformDir}/NPB-OMP/bin/ft.C.x",
137+
$@"{platformDir}/NPB-OMP/bin/is.C.x",
138+
$@"{platformDir}/NPB-OMP/bin/lu.C.x",
139+
$@"{platformDir}/NPB-OMP/bin/mg.C.x",
140+
$@"{platformDir}/NPB-OMP/bin/sp.C.x",
141+
$@"{platformDir}/NPB-OMP/bin/ua.C.x",
142+
$@"{platformDir}/NPB-OMP/bin/dt.C.x"
143+
};
178144

179145
this.mockFixture.SetupPackage("nasparallelbench", expectedFiles: expectedFiles);
180146
}

src/VirtualClient/VirtualClient.Actions.UnitTests/NASParallelBench/NASParallelBenchClientExecutorTests.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public void SetupTest(PlatformID platformID)
4040
{
4141
["PackageName"] = this.mockPackage.Name,
4242
["Benchmark"] = NASParallelBenchClientExecutorTests.ExampleBenchmark,
43-
["Username"] = NASParallelBenchClientExecutorTests.ExampleUsername
43+
["Username"] = NASParallelBenchClientExecutorTests.ExampleUsername,
44+
["ThreadCount"] = Environment.ProcessorCount
4445
};
4546

4647
this.mockFixture.File.Setup(f => f.Exists(It.IsAny<string>())).Returns(true);
@@ -151,5 +152,28 @@ public async Task NASParallelBenchClientExecutorUsesOMPOptionInSingleSystemScena
151152
await executor.ExecuteAsync(CancellationToken.None);
152153
}
153154
}
155+
156+
[Test]
157+
public async Task NASParallelBenchClientExecutorUsesCustomThreadCountWhenSpecified()
158+
{
159+
this.SetupTest(PlatformID.Unix);
160+
161+
this.mockFixture.Layout = null;
162+
this.mockFixture.Parameters["ThreadCount"] = 8;
163+
this.mockFixture.ProcessManager.OnCreateProcess = (cmd, args, wd) =>
164+
{
165+
Assert.AreEqual(cmd, "sudo");
166+
Assert.AreEqual(args, $"bash -c \"export OMP_NUM_THREADS=8 " +
167+
$"&& {this.mockFixture.GetPackagePath()}/nasparallelbench/linux-x64/NPB-OMP/bin/" +
168+
$"bt.S.x\"");
169+
return this.mockFixture.Process;
170+
};
171+
172+
using NASParallelBenchClientExecutor executor = new NASParallelBenchClientExecutor(
173+
this.mockFixture.Dependencies, this.mockFixture.Parameters);
174+
{
175+
await executor.ExecuteAsync(CancellationToken.None);
176+
}
177+
}
154178
}
155179
}

src/VirtualClient/VirtualClient.Actions/NASParallelBench/NASParallelBenchClientExecutor.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ public NASParallelBenchClientExecutor(IServiceCollection dependencies, IDictiona
4545
/// <summary>
4646
/// Name of the benchmark to be executed.
4747
/// </summary>
48-
public string Benchmark => this.Parameters.GetValue<string>(nameof(NASParallelBenchClientExecutor.Benchmark));
48+
public string Benchmark => this.ApplyParameters(
49+
this.Parameters.GetValue<string>(nameof(NASParallelBenchClientExecutor.Benchmark)),
50+
this.Parameters);
4951

5052
/// <summary>
5153
/// The user who has the ssh identity registered for.
@@ -64,6 +66,19 @@ public string Username
6466
}
6567
}
6668

69+
/// <summary>
70+
/// The number of threads to use for OpenMP parallelism (OMP_NUM_THREADS).
71+
/// Defaults to the system processor count if not specified.
72+
/// </summary>
73+
public int ThreadCount
74+
{
75+
get
76+
{
77+
int threadCount = this.Parameters.GetValue<int>(nameof(NASParallelBenchClientExecutor.ThreadCount), 0);
78+
return threadCount > 0 ? threadCount : Environment.ProcessorCount;
79+
}
80+
}
81+
6782
/// <summary>
6883
/// The timeout to apply to polling for individual/target client instances
6984
/// of the Virtual Client to come online.
@@ -102,7 +117,7 @@ private Task ExecuteWorkloadAsync(EventContext telemetryContext, CancellationTok
102117

103118
// Number of threads used by the process.
104119
// Open Multi Threading number of threads.
105-
string ompNumThreads = $"export OMP_NUM_THREADS={Environment.ProcessorCount}";
120+
string ompNumThreads = $"export OMP_NUM_THREADS={this.ThreadCount}";
106121
string command = string.Empty;
107122
string args = string.Empty;
108123
string scenarioArguments = string.Empty;

0 commit comments

Comments
 (0)