1+ // Copyright (c) Microsoft Corporation.
2+ // Licensed under the MIT License.
3+
4+ namespace VirtualClient . Actions
5+ {
6+ using System ;
7+ using System . Collections . Generic ;
8+ using System . Linq ;
9+ using System . Runtime . InteropServices ;
10+ using System . Threading ;
11+ using System . Threading . Tasks ;
12+ using Moq ;
13+ using NUnit . Framework ;
14+ using VirtualClient ;
15+ using VirtualClient . Common ;
16+ using VirtualClient . Contracts ;
17+
18+ [ TestFixture ]
19+ [ Category ( "Functional" ) ]
20+ public class StreamProfileTests
21+ {
22+ private DependencyFixture mockFixture ;
23+
24+ [ OneTimeSetUp ]
25+ public void SetupFixture ( )
26+ {
27+ this . mockFixture = new DependencyFixture ( ) ;
28+ ComponentTypeCache . Instance . LoadComponentTypes ( TestDependencies . TestDirectory ) ;
29+ }
30+
31+ [ Test ]
32+ [ TestCase ( "PERF-MEM-STREAMTRIAD.json" ) ]
33+ public void StreamTriadWorkloadProfileParametersAreInlinedCorrectly ( string profile )
34+ {
35+ this . mockFixture . Setup ( PlatformID . Unix ) ;
36+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
37+ {
38+ WorkloadAssert . ParameterReferencesInlined ( executor . Profile ) ;
39+ }
40+ }
41+
42+ [ Test ]
43+ [ TestCase ( "PERF-MEM-STREAMTRIAD.json" ) ]
44+ public async Task StreamTriadWorkloadProfileExecutesTheExpectedWorkloadsOnUnixPlatform ( string profile )
45+ {
46+ IEnumerable < string > expectedCommands = StreamProfileTests . GetStreamTriadProfileExpectedCommands ( ) ;
47+
48+ // Setup the expectations for the workload
49+ // - Workload package is installed and exists.
50+ // - The workload generates valid results.
51+ this . mockFixture . Setup ( PlatformID . Unix ) ;
52+ this . mockFixture . SystemManagement . Setup ( mgr => mgr . GetCpuInfoAsync ( It . IsAny < CancellationToken > ( ) ) )
53+ . ReturnsAsync ( new CpuInfo ( "Name" , "Description" , 1 , 2 , 1 , 1 , true ) ) ;
54+
55+ this . mockFixture . SetupPackage ( "stream" , expectedFiles : "linux-x64/stream" ) ;
56+
57+ this . mockFixture . ProcessManager . OnCreateProcess = ( command , arguments , workingDir ) =>
58+ {
59+ IProcessProxy process = this . mockFixture . CreateProcess ( command , arguments , workingDir ) ;
60+ if ( arguments . Contains ( "Stream" , StringComparison . OrdinalIgnoreCase ) )
61+ {
62+ process . StandardOutput . Append ( TestDependencies . GetResourceFileContents ( "Results_Stream.txt" ) ) ;
63+ }
64+ else if ( arguments . Contains ( "lscpu | grep 'Flags'" ) )
65+ {
66+ process . StandardOutput . AppendLine ( "Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx512vbmi" ) ;
67+ }
68+
69+ return process ;
70+ } ;
71+
72+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
73+ {
74+ executor . ExecuteDependencies = false ;
75+ await executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) . ConfigureAwait ( false ) ;
76+ await executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) . ConfigureAwait ( false ) ;
77+
78+ WorkloadAssert . CommandsExecuted ( this . mockFixture , expectedCommands . ToArray ( ) ) ;
79+ }
80+ }
81+
82+ [ Test ]
83+ [ Ignore ( "We need to rethink how to do dependency testing with extension model." ) ]
84+ [ TestCase ( "PERF-MEM-STREAMTRIAD.json" ) ]
85+ public async Task StreamTriadWorkloadProfileInstallsTheExpectedDependenciesOnUnixPlatform ( string profile )
86+ {
87+ // The setup in a typical Azure VM scenario
88+ this . mockFixture . Setup ( PlatformID . Unix ) ;
89+
90+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies , dependenciesOnly : true ) )
91+ {
92+ executor . ExecuteDependencies = false ;
93+ await executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) . ConfigureAwait ( false ) ;
94+
95+ // Workload dependency package expectations
96+ // The workload dependency package should have been installed at this point.
97+ WorkloadAssert . WorkloadPackageInstalled ( this . mockFixture , "stream" ) ;
98+ }
99+ }
100+
101+ [ Test ]
102+ [ TestCase ( "PERF-MEM-STREAMTRIAD.json" ) ]
103+ public void StreamTriadProfileActionsWillNotBeExecutedIfTheWorkloadPackageDoesNotExist ( string profile )
104+ {
105+ this . mockFixture . Setup ( PlatformID . Unix ) ;
106+ this . mockFixture . SystemManagement . Setup ( mgr => mgr . GetCpuInfoAsync ( It . IsAny < CancellationToken > ( ) ) )
107+ . ReturnsAsync ( new CpuInfo ( "Name" , "Description" , 1 , 2 , 1 , 1 , true ) ) ;
108+
109+ // We ensure the workload package does not exist.
110+ this . mockFixture . PackageManager . Clear ( ) ;
111+
112+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
113+ {
114+ executor . ExecuteDependencies = false ;
115+
116+ DependencyException error = Assert . ThrowsAsync < DependencyException > ( ( ) => executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) ) ;
117+ Assert . IsTrue ( error . Reason == ErrorReason . WorkloadDependencyMissing ) ;
118+ }
119+ }
120+
121+ [ Test ]
122+ [ TestCase ( "PERF-MEM-STREAMMSFT.json" ) ]
123+ public void StreamMsftWorkloadProfileParametersAreInlinedCorrectly ( string profile )
124+ {
125+ this . mockFixture . Setup ( PlatformID . Unix ) ;
126+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
127+ {
128+ WorkloadAssert . ParameterReferencesInlined ( executor . Profile ) ;
129+ }
130+ }
131+
132+ [ Test ]
133+ [ TestCase ( "PERF-MEM-STREAMMSFT.json" ) ]
134+ public async Task StreamMsftWorkloadProfileExecutesTheExpectedWorkloadsOnUnixPlatform ( string profile )
135+ {
136+ IEnumerable < string > expectedCommands = StreamProfileTests . GetStreamMsftProfileExpectedCommands ( ) ;
137+
138+ // Setup the expectations for the workload
139+ // - Workload package is installed and exists.
140+ // - The workload generates valid results.
141+ this . mockFixture . Setup ( PlatformID . Unix , Architecture . Arm64 ) ;
142+ this . mockFixture . SetupPackage ( "streammsft" , expectedFiles : "linux-arm64/stream" ) ;
143+
144+ this . mockFixture . SystemManagement . Setup ( mgr => mgr . GetCpuInfoAsync ( It . IsAny < CancellationToken > ( ) ) )
145+ . ReturnsAsync ( new CpuInfo ( "Name" , "Description" , 1 , 2 , 1 , 1 , true ) ) ;
146+
147+ this . mockFixture . ProcessManager . OnCreateProcess = ( command , arguments , workingDir ) =>
148+ {
149+ IProcessProxy process = this . mockFixture . CreateProcess ( command , arguments , workingDir ) ;
150+ if ( arguments . Contains ( "perfrunner" , StringComparison . OrdinalIgnoreCase ) )
151+ {
152+ process . StandardOutput . Append ( TestDependencies . GetResourceFileContents ( "Results_StreamMsft.txt" ) ) ;
153+ }
154+ else if ( arguments . Contains ( "make" , StringComparison . OrdinalIgnoreCase ) )
155+ {
156+ // Make command should succeed without output
157+ }
158+
159+ return process ;
160+ } ;
161+
162+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
163+ {
164+ executor . ExecuteDependencies = false ;
165+ await executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) . ConfigureAwait ( false ) ;
166+
167+ WorkloadAssert . CommandsExecuted ( this . mockFixture , expectedCommands . ToArray ( ) ) ;
168+ }
169+ }
170+
171+ [ Test ]
172+ [ TestCase ( "PERF-MEM-STREAM.json" ) ]
173+ public void StreamWorkloadProfileParametersAreInlinedCorrectly ( string profile )
174+ {
175+ this . mockFixture . Setup ( PlatformID . Unix ) ;
176+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
177+ {
178+ WorkloadAssert . ParameterReferencesInlined ( executor . Profile ) ;
179+ }
180+ }
181+
182+ [ Test ]
183+ [ TestCase ( "PERF-MEM-STREAM.json" ) ]
184+ public async Task StreamWorkloadProfileExecutesTheExpectedWorkloadsOnUnixPlatform ( string profile )
185+ {
186+ IEnumerable < string > expectedCommands = StreamProfileTests . GetStreamProfileExpectedCommands ( ) ;
187+
188+ // Setup the expectations for the workload
189+ // - Workload package is installed and exists.
190+ // - The workload generates valid results.
191+ this . mockFixture . Setup ( PlatformID . Unix ) ;
192+ this . mockFixture . SetupPackage ( "stream" , expectedFiles : "linux-x64/stream" ) ;
193+ this . mockFixture . SystemManagement . Setup ( mgr => mgr . GetCpuInfoAsync ( It . IsAny < CancellationToken > ( ) ) )
194+ . ReturnsAsync ( new CpuInfo ( "Name" , "Description" , 1 , 2 , 1 , 1 , true ) ) ;
195+
196+ this . mockFixture . ProcessManager . OnCreateProcess = ( command , arguments , workingDir ) =>
197+ {
198+ IProcessProxy process = this . mockFixture . CreateProcess ( command , arguments , workingDir ) ;
199+ if ( arguments . Contains ( "streamworkload" , StringComparison . OrdinalIgnoreCase ) )
200+ {
201+ process . StandardOutput . Append ( TestDependencies . GetResourceFileContents ( "Results_Stream.txt" ) ) ;
202+ }
203+ else if ( arguments . Contains ( "gcc" , StringComparison . OrdinalIgnoreCase ) )
204+ {
205+ // Compilation command - no output needed
206+ }
207+
208+ return process ;
209+ } ;
210+
211+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
212+ {
213+ executor . ExecuteDependencies = false ;
214+ await executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) . ConfigureAwait ( false ) ;
215+
216+ await executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) . ConfigureAwait ( false ) ;
217+
218+ WorkloadAssert . CommandsExecuted ( this . mockFixture , expectedCommands . ToArray ( ) ) ;
219+ }
220+ }
221+
222+ [ Test ]
223+ [ TestCase ( "PERF-MEM-STREAM.json" ) ]
224+ public void StreamProfileActionsWillNotBeExecutedIfTheWorkloadPackageDoesNotExist ( string profile )
225+ {
226+ this . mockFixture . Setup ( PlatformID . Unix ) ;
227+ this . mockFixture . SystemManagement . Setup ( mgr => mgr . GetCpuInfoAsync ( It . IsAny < CancellationToken > ( ) ) )
228+ . ReturnsAsync ( new CpuInfo ( "Name" , "Description" , 1 , 2 , 1 , 1 , true ) ) ;
229+
230+ // We ensure the workload package does not exist.
231+ this . mockFixture . PackageManager . Clear ( ) ;
232+
233+ this . mockFixture . ProcessManager . OnCreateProcess = ( exe , arguments , workingDir ) =>
234+ {
235+ IProcessProxy process = this . mockFixture . CreateProcess ( exe , arguments , workingDir ) ;
236+ process . StandardOutput . AppendLine ( "gcc (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0" ) ;
237+ process . StandardOutput . AppendLine ( "cc (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0" ) ;
238+ return process ;
239+ } ;
240+
241+ using ( ProfileExecutor executor = TestDependencies . CreateProfileExecutor ( profile , this . mockFixture . Dependencies ) )
242+ {
243+ executor . ExecuteDependencies = false ;
244+
245+ DependencyException error = Assert . ThrowsAsync < DependencyException > ( ( ) => executor . ExecuteAsync ( ProfileTiming . OneIteration ( ) , CancellationToken . None ) ) ;
246+ Assert . IsTrue ( error . Reason == ErrorReason . WorkloadDependencyMissing ) ;
247+ }
248+ }
249+
250+ private static IEnumerable < string > GetStreamTriadProfileExpectedCommands ( )
251+ {
252+ return new List < string >
253+ {
254+ "bash -c \" lscpu \\ | grep 'Flags'\" " ,
255+ "bash -c \" export KMP_AFFINITY=.*&& export OMP_NUM_THREADS=.*&& export LD_LIBRARY_PATH=.*&& chmod \\ +x.*&&.*Stream.*\" "
256+ } ;
257+ }
258+
259+ private static IEnumerable < string > GetStreamProfileExpectedCommands ( )
260+ {
261+ return new List < string >
262+ {
263+ "bash -c \" gcc.*stream\\ .c.*-o.*streamworkload.*\" " ,
264+ "bash -c \" export OMP_NUM_THREADS=.*&&.*chmod.*\\ +x.*streamworkload.*&&.*streamworkload.*\" " ,
265+ } ;
266+ }
267+
268+ private static IEnumerable < string > GetStreamMsftProfileExpectedCommands ( )
269+ {
270+ return new List < string >
271+ {
272+ "bash.*make" ,
273+ "bash.*perfrunner.*--threads.*--internal-iter" ,
274+ } ;
275+ }
276+
277+ private static IEnumerable < string > GetStreamWindowsProfileExpectedCommands ( )
278+ {
279+ return new List < string >
280+ {
281+ "cmd\\ .exe.*stream\\ .exe.*-n 50.*-s 320000000" ,
282+ } ;
283+ }
284+ }
285+ }
0 commit comments