diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResults.txt b/src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResultsArm.txt similarity index 100% rename from src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResults.txt rename to src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResultsArm.txt diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResultsIntel.txt b/src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResultsIntel.txt new file mode 100644 index 0000000000..8bd9f038db --- /dev/null +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/Examples/HPLinpack/HPLResultsIntel.txt @@ -0,0 +1,179 @@ +This is a SAMPLE run script. Change it to reflect the correct number +of CPUs/threads, number of nodes, MPI processes per node, etc.. +This run was done on: Thu May 29 06:59:31 UTC 2025 +RANK=0, NODE=0-0 +================================================================================ +HPLinpack 2.3 -- High-Performance Linpack benchmark -- December 2, 2018 +Written by A. Petitet and R. Clint Whaley, Innovative Computing Laboratory, UTK +Modified by Piotr Luszczek, Innovative Computing Laboratory, UTK +Modified by Julien Langou, University of Colorado Denver +================================================================================ + +An explanation of the input/output parameters follows: +T/V : Wall time / encoded variant. +N : The order of the coefficient matrix A. +NB : The partitioning blocking factor. +P : The number of process rows. +Q : The number of process columns. +Time : Time in seconds to solve the linear system. +Gflops : Rate of execution for solving the linear system. + +The following parameter values will be used: + +N : 82081 +NB : 256 +PMAP : Column-major process mapping +P : 1 +Q : 1 +PFACT : Left +NBMIN : 1 +NDIV : 2 +RFACT : Right +BCAST : 1ring +DEPTH : 0 +SWAP : Binary-exchange +L1 : no-transposed form +U : no-transposed form +EQUIL : no +ALIGN : 8 double precision words + +-------------------------------------------------------------------------------- + +- The matrix A is randomly generated for each test. +- The following scaled residual check will be computed: + ||Ax-b||_oo / ( eps * ( || x ||_oo * || A ||_oo + || b ||_oo ) * N ) +- The relative machine precision (eps) is taken to be 1.110223e-16 +- Computational tests pass if scaled residuals are less than 1.0 + +RakeshIntelub22 : Column=000512 Fraction=0.005 Kernel= 0.21 Mflops=1268334.82 +RakeshIntelub22 : Column=001024 Fraction=0.010 Kernel=666265.85 Mflops=875324.97 +RakeshIntelub22 : Column=001280 Fraction=0.015 Kernel=655308.59 Mflops=820894.74 +RakeshIntelub22 : Column=001792 Fraction=0.020 Kernel=667668.21 Mflops=771127.79 +RakeshIntelub22 : Column=002304 Fraction=0.025 Kernel=667635.57 Mflops=745997.64 +RakeshIntelub22 : Column=002560 Fraction=0.030 Kernel=663520.09 Mflops=737095.45 +RakeshIntelub22 : Column=003072 Fraction=0.035 Kernel=669753.70 Mflops=725325.21 +RakeshIntelub22 : Column=003328 Fraction=0.040 Kernel=659563.91 Mflops=720012.72 +RakeshIntelub22 : Column=003840 Fraction=0.045 Kernel=670323.43 Mflops=713254.08 +RakeshIntelub22 : Column=004352 Fraction=0.050 Kernel=671159.69 Mflops=708277.26 +RakeshIntelub22 : Column=004608 Fraction=0.055 Kernel=660836.80 Mflops=705615.26 +RakeshIntelub22 : Column=005120 Fraction=0.060 Kernel=670662.80 Mflops=702165.99 +RakeshIntelub22 : Column=005376 Fraction=0.065 Kernel=649590.41 Mflops=699641.54 +RakeshIntelub22 : Column=005888 Fraction=0.070 Kernel=671290.28 Mflops=697252.96 +RakeshIntelub22 : Column=006400 Fraction=0.075 Kernel=668118.13 Mflops=695007.19 +RakeshIntelub22 : Column=006656 Fraction=0.080 Kernel=668036.21 Mflops=694015.90 +RakeshIntelub22 : Column=007168 Fraction=0.085 Kernel=662833.64 Mflops=691885.40 +RakeshIntelub22 : Column=007424 Fraction=0.090 Kernel=663095.99 Mflops=690944.12 +RakeshIntelub22 : Column=007936 Fraction=0.095 Kernel=671273.29 Mflops=689762.09 +RakeshIntelub22 : Column=008448 Fraction=0.100 Kernel=660854.57 Mflops=688120.65 +RakeshIntelub22 : Column=008704 Fraction=0.105 Kernel=666492.33 Mflops=687534.43 +RakeshIntelub22 : Column=009216 Fraction=0.110 Kernel=667876.05 Mflops=686535.55 +RakeshIntelub22 : Column=009472 Fraction=0.115 Kernel=659123.21 Mflops=685854.60 +RakeshIntelub22 : Column=009984 Fraction=0.120 Kernel=670795.25 Mflops=685160.70 +RakeshIntelub22 : Column=010496 Fraction=0.125 Kernel=665501.64 Mflops=684299.94 +RakeshIntelub22 : Column=010752 Fraction=0.130 Kernel=658620.48 Mflops=683749.98 +RakeshIntelub22 : Column=011264 Fraction=0.135 Kernel=668371.24 Mflops=683133.57 +RakeshIntelub22 : Column=011520 Fraction=0.140 Kernel=667999.66 Mflops=682839.21 +RakeshIntelub22 : Column=012032 Fraction=0.145 Kernel=660338.58 Mflops=681996.18 +RakeshIntelub22 : Column=012544 Fraction=0.150 Kernel=667707.16 Mflops=681492.79 +RakeshIntelub22 : Column=012800 Fraction=0.155 Kernel=664645.58 Mflops=681203.01 +RakeshIntelub22 : Column=013312 Fraction=0.160 Kernel=663288.50 Mflops=680612.42 +RakeshIntelub22 : Column=013568 Fraction=0.165 Kernel=676041.89 Mflops=680540.47 +RakeshIntelub22 : Column=014080 Fraction=0.170 Kernel=658680.83 Mflops=679863.64 +RakeshIntelub22 : Column=014592 Fraction=0.175 Kernel=665657.22 Mflops=679447.44 +RakeshIntelub22 : Column=014848 Fraction=0.180 Kernel=666992.17 Mflops=679269.98 +RakeshIntelub22 : Column=015360 Fraction=0.185 Kernel=668174.31 Mflops=678966.49 +RakeshIntelub22 : Column=015616 Fraction=0.190 Kernel=655927.83 Mflops=678653.51 +RakeshIntelub22 : Column=016128 Fraction=0.195 Kernel=663909.37 Mflops=678272.39 +RakeshIntelub22 : Column=016640 Fraction=0.200 Kernel=656695.78 Mflops=677731.14 +RakeshIntelub22 : Column=016896 Fraction=0.205 Kernel=675137.97 Mflops=677700.25 +RakeshIntelub22 : Column=017408 Fraction=0.210 Kernel=661103.40 Mflops=677310.49 +RakeshIntelub22 : Column=017664 Fraction=0.215 Kernel=667421.36 Mflops=677198.12 +RakeshIntelub22 : Column=018176 Fraction=0.220 Kernel=661226.75 Mflops=676844.13 +RakeshIntelub22 : Column=018688 Fraction=0.225 Kernel=666292.16 Mflops=676620.56 +RakeshIntelub22 : Column=018944 Fraction=0.230 Kernel=666020.91 Mflops=676510.73 +RakeshIntelub22 : Column=019456 Fraction=0.235 Kernel=663706.21 Mflops=676252.96 +RakeshIntelub22 : Column=019712 Fraction=0.240 Kernel=663332.93 Mflops=676125.69 +RakeshIntelub22 : Column=020224 Fraction=0.245 Kernel=667312.31 Mflops=675958.44 +RakeshIntelub22 : Column=020736 Fraction=0.250 Kernel=656838.54 Mflops=675602.62 +RakeshIntelub22 : Column=020992 Fraction=0.255 Kernel=676776.92 Mflops=675613.00 +RakeshIntelub22 : Column=021504 Fraction=0.260 Kernel=661931.44 Mflops=675373.07 +RakeshIntelub22 : Column=021760 Fraction=0.265 Kernel=662519.38 Mflops=675262.83 +RakeshIntelub22 : Column=022272 Fraction=0.270 Kernel=667418.43 Mflops=675133.14 +RakeshIntelub22 : Column=022784 Fraction=0.275 Kernel=662806.71 Mflops=674934.66 +RakeshIntelub22 : Column=023040 Fraction=0.280 Kernel=674655.32 Mflops=674932.50 +RakeshIntelub22 : Column=023552 Fraction=0.285 Kernel=660954.27 Mflops=674717.63 +RakeshIntelub22 : Column=023808 Fraction=0.290 Kernel=648254.26 Mflops=674514.53 +RakeshIntelub22 : Column=024320 Fraction=0.295 Kernel=665768.74 Mflops=674387.40 +RakeshIntelub22 : Column=024832 Fraction=0.300 Kernel=665010.05 Mflops=674255.23 +RakeshIntelub22 : Column=025088 Fraction=0.305 Kernel=652135.63 Mflops=674099.49 +RakeshIntelub22 : Column=025600 Fraction=0.310 Kernel=665580.82 Mflops=673985.08 +RakeshIntelub22 : Column=025856 Fraction=0.315 Kernel=659615.01 Mflops=673889.66 +RakeshIntelub22 : Column=026368 Fraction=0.320 Kernel=666658.77 Mflops=673797.14 +RakeshIntelub22 : Column=026880 Fraction=0.325 Kernel=661200.94 Mflops=673639.60 +RakeshIntelub22 : Column=027136 Fraction=0.330 Kernel=662972.20 Mflops=673574.38 +RakeshIntelub22 : Column=027648 Fraction=0.335 Kernel=656818.26 Mflops=673372.92 +RakeshIntelub22 : Column=028160 Fraction=0.340 Kernel=672539.93 Mflops=673363.43 +RakeshIntelub22 : Column=028416 Fraction=0.345 Kernel=664380.80 Mflops=673312.66 +RakeshIntelub22 : Column=028928 Fraction=0.350 Kernel=658784.89 Mflops=673151.20 +RakeshIntelub22 : Column=029184 Fraction=0.355 Kernel=657696.15 Mflops=673066.87 +RakeshIntelub22 : Column=029696 Fraction=0.360 Kernel=663551.81 Mflops=672966.50 +RakeshIntelub22 : Column=030208 Fraction=0.365 Kernel=663250.65 Mflops=672866.98 +RakeshIntelub22 : Column=030464 Fraction=0.370 Kernel=660682.66 Mflops=672805.57 +RakeshIntelub22 : Column=030976 Fraction=0.375 Kernel=657259.39 Mflops=672651.91 +RakeshIntelub22 : Column=031232 Fraction=0.380 Kernel=669983.72 Mflops=672639.23 +RakeshIntelub22 : Column=031744 Fraction=0.385 Kernel=667523.97 Mflops=672591.60 +RakeshIntelub22 : Column=032256 Fraction=0.390 Kernel=659387.80 Mflops=672470.76 +RakeshIntelub22 : Column=032512 Fraction=0.395 Kernel=674751.87 Mflops=672480.76 +RakeshIntelub22 : Column=033024 Fraction=0.400 Kernel=658060.16 Mflops=672354.23 +RakeshIntelub22 : Column=033280 Fraction=0.405 Kernel=664847.16 Mflops=672322.27 +RakeshIntelub22 : Column=033792 Fraction=0.410 Kernel=653976.19 Mflops=672167.29 +RakeshIntelub22 : Column=034304 Fraction=0.415 Kernel=673441.90 Mflops=672177.44 +RakeshIntelub22 : Column=034560 Fraction=0.420 Kernel=646487.51 Mflops=672072.96 +RakeshIntelub22 : Column=035072 Fraction=0.425 Kernel=665190.73 Mflops=672019.83 +RakeshIntelub22 : Column=035328 Fraction=0.430 Kernel=660656.47 Mflops=671976.56 +RakeshIntelub22 : Column=035840 Fraction=0.435 Kernel=670194.19 Mflops=671963.49 +RakeshIntelub22 : Column=036352 Fraction=0.440 Kernel=651285.14 Mflops=671812.01 +RakeshIntelub22 : Column=036608 Fraction=0.445 Kernel=655672.98 Mflops=671754.48 +RakeshIntelub22 : Column=037120 Fraction=0.450 Kernel=665973.67 Mflops=671714.85 +RakeshIntelub22 : Column=037376 Fraction=0.455 Kernel=671438.84 Mflops=671713.93 +RakeshIntelub22 : Column=037888 Fraction=0.460 Kernel=660974.93 Mflops=671642.98 +RakeshIntelub22 : Column=038400 Fraction=0.465 Kernel=652786.16 Mflops=671520.51 +RakeshIntelub22 : Column=038656 Fraction=0.470 Kernel=662935.35 Mflops=671493.62 +RakeshIntelub22 : Column=039168 Fraction=0.475 Kernel=658152.28 Mflops=671411.42 +RakeshIntelub22 : Column=039424 Fraction=0.480 Kernel=676176.46 Mflops=671425.41 +RakeshIntelub22 : Column=039936 Fraction=0.485 Kernel=659271.64 Mflops=671353.93 +RakeshIntelub22 : Column=040448 Fraction=0.490 Kernel=659773.99 Mflops=671287.89 +RakeshIntelub22 : Column=040704 Fraction=0.495 Kernel=668675.67 Mflops=671280.70 +RakeshIntelub22 : Column=042496 Fraction=0.515 Kernel=658417.64 Mflops=671045.43 +RakeshIntelub22 : Column=044032 Fraction=0.535 Kernel=657112.56 Mflops=670847.05 +RakeshIntelub22 : Column=045568 Fraction=0.555 Kernel=651349.83 Mflops=670592.10 +RakeshIntelub22 : Column=047360 Fraction=0.575 Kernel=655697.09 Mflops=670388.88 +RakeshIntelub22 : Column=048896 Fraction=0.595 Kernel=655390.78 Mflops=670231.09 +RakeshIntelub22 : Column=050688 Fraction=0.615 Kernel=653935.67 Mflops=670051.78 +RakeshIntelub22 : Column=052224 Fraction=0.635 Kernel=646724.40 Mflops=669853.37 +RakeshIntelub22 : Column=054016 Fraction=0.655 Kernel=654602.46 Mflops=669720.80 +RakeshIntelub22 : Column=055552 Fraction=0.675 Kernel=647656.74 Mflops=669574.19 +RakeshIntelub22 : Column=057088 Fraction=0.695 Kernel=645617.71 Mflops=669432.79 +RakeshIntelub22 : Column=065280 Fraction=0.795 Kernel=642569.28 Mflops=668878.41 +RakeshIntelub22 : Column=073472 Fraction=0.895 Kernel=626205.50 Mflops=668539.89 +RakeshIntelub22 : Column=081920 Fraction=0.995 Kernel=562289.91 Mflops=668394.17 +================================================================================ +T/V N NB P Q Time Gflops +-------------------------------------------------------------------------------- +WC00R2L1 82081 256 1 1 551.89 6.68032e+02 +HPL_pdgesv() start time Thu May 29 06:59:46 2025 + +HPL_pdgesv() end time Thu May 29 07:08:58 2025 + +-------------------------------------------------------------------------------- +||Ax-b||_oo/(eps*(||A||_oo*||x||_oo+||b||_oo)*N)= 3.59653282e-03 ...... PASSED +================================================================================ + +Finished 1 tests with the following results: + 1 tests completed and passed residual checks, + 0 tests completed and failed residual checks, + 0 tests skipped because of illegal input values. +-------------------------------------------------------------------------------- + +End of Tests. +================================================================================ \ No newline at end of file diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackExecutorTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackExecutorTests.cs index 364e17bbc7..09ff8a1327 100644 --- a/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackExecutorTests.cs +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackExecutorTests.cs @@ -39,7 +39,7 @@ private void SetupTest(PlatformID platform = PlatformID.Unix, Architecture archi this.mockFixture.FileSystem.Setup(fe => fe.File.Exists(It.IsAny())).Returns(true); this.mockFixture.FileSystem.Setup(fe => fe.File.Exists(null)).Returns(false); - this.exampleResults = File.ReadAllText(this.mockFixture.Combine(HPLinpackExecutorTests.ExamplesDirectory, "HPLResults.txt")); + this.exampleResults = File.ReadAllText(this.mockFixture.Combine(HPLinpackExecutorTests.ExamplesDirectory, "HPLResultsArm.txt")); this.mockFixture.FileSystem.Setup(rt => rt.File.ReadAllText(It.IsAny())) .Returns(this.exampleResults); @@ -257,6 +257,172 @@ await executor.ExecuteAsync(EventContext.None, CancellationToken.None) } } + [Test] + [TestCase(PlatformID.Unix, Architecture.X64, "4.2.0")] + [TestCase(PlatformID.Unix, Architecture.X64, "5.0.0")] + [TestCase(PlatformID.Unix, Architecture.X64, "5.1.0")] + public async Task HPLinpackExecutorExecutesWorkloadAsExpectedWithPerformanceLibrariesOnUbuntuX64AMDPlatform(PlatformID platform, Architecture architecture, string performanceLibraryVersion) + { + this.SetupTest(platform, architecture); + this.mockFixture.Parameters["PerformanceLibrary"] = "AMD"; + this.mockFixture.Parameters["PerformanceLibraryVersion"] = $"{performanceLibraryVersion}"; + + using (TestHPLExecutor executor = new TestHPLExecutor(this.mockFixture)) + { + List expectedCommands = new List() + { + $"sudo chmod +x {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "AMD", performanceLibraryVersion, "install.sh")}", + $"sudo ./install.sh -t {executor.GetHPLDirectory} -i lp64", + $"sudo bash -c \"source make_generic\"", + $"mv Make.UNKNOWN Make.Linux_GCC", + $"ln -s {this.mockFixture.PlatformSpecifics.Combine(executor.GetHPLDirectory, "setup", "Make.Linux_GCC" )} Make.Linux_GCC", + $"make arch=Linux_GCC", + $"sudo runuser -u {Environment.UserName} -- mpirun --use-hwthread-cpus -np {this.mockFixture.Parameters["NumberOfProcesses"] ?? Environment.ProcessorCount} ./xhpl" + }; + + this.mockFixture.ProcessManager.OnCreateProcess = (command, arguments, workingDirectory) => + { + expectedCommands.Remove(expectedCommands[0]); + if (arguments == $"runuser -u {Environment.UserName} -- mpirun --use-hwthread-cpus -np {this.mockFixture.Parameters["NumberOfProcesses"] ?? Environment.ProcessorCount} ./xhpl") + { + this.mockFixture.Process.StandardOutput.Append(this.exampleResults); + } + + return this.mockFixture.Process; + }; + + await executor.ExecuteAsync(EventContext.None, CancellationToken.None) + .ConfigureAwait(false); + + Assert.AreEqual(expectedCommands.Count, 0); + } + } + + + [Test] + [TestCase(PlatformID.Unix, Architecture.X64, "1.0.0")] + public void HPLinpackExecutorThrowsExceptionForUnsupportedAMDPerformanceLibraryVersions(PlatformID platform, Architecture architecture, string performanceLibraryVersion) + { + this.SetupTest(platform, architecture); + this.mockFixture.Parameters["PerformanceLibrary"] = "AMD"; + this.mockFixture.Parameters["PerformanceLibraryVersion"] = performanceLibraryVersion; + + using (TestHPLExecutor executor = new TestHPLExecutor(this.mockFixture)) + { + WorkloadException exception = Assert.ThrowsAsync( + () => executor.ExecuteAsync(EventContext.None, CancellationToken.None)); + + Assert.AreEqual( + $"The HPL workload currently only supports 4.2.0, 5.0.0 and 5.1.0 versions of AMD performance libraries", + exception.Message); + } + } + + [Test] + [TestCase(PlatformID.Unix, Architecture.X64, "2025.1.0.803")] + public async Task HPLinpackExecutorExecutesWorkloadAsExpectedWithPerformanceLibraries25OnUbuntuX64IntelPlatform(PlatformID platform, Architecture architecture, string performanceLibraryVersion) + { + this.SetupTest(platform, architecture); + this.mockFixture.Parameters["PerformanceLibrary"] = "INTEL"; + this.mockFixture.Parameters["PerformanceLibraryVersion"] = $"{performanceLibraryVersion}"; + + // Setup CPU info with socket count for Intel execution path + this.mockFixture.SystemManagement.Setup(mgr => mgr.GetCpuInfoAsync(It.IsAny())) + .ReturnsAsync(new CpuInfo("cpu", "description", 2, 9, 11, 13, true)); + + using (TestHPLExecutor executor = new TestHPLExecutor(this.mockFixture)) + { + List expectedCommands = new List() + { + $"sudo chmod +x {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "INTEL", $"{performanceLibraryVersion}", "intel-onemkl-2025.1.0.803_offline.sh")}", + $"sudo ./intel-onemkl-2025.1.0.803_offline.sh -a --silent --eula accept", + $"sudo chmod +x {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "INTEL", "2025.1.0.803", "intel-oneapi-hpc-toolkit-2025.1.3.10_offline.sh")}", + $"sudo ./intel-oneapi-hpc-toolkit-2025.1.3.10_offline.sh -a --silent --eula accept", + $"cp -r /opt/intel/oneapi/mkl/2025.1/share/mkl/benchmarks/mp_linpack {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "INTEL", "2025.1.0.803")}", + $"make arch=Linux_GCC", + $"sudo bash -c \". /opt/intel/oneapi/mpi/latest/env/vars.sh && ./runme_intel64_dynamic\"" + }; + + this.mockFixture.ProcessManager.OnCreateProcess = (command, arguments, workingDirectory) => + { + expectedCommands.Remove(expectedCommands[0]); + if (arguments == $"-c \". /opt/intel/oneapi/mpi/latest/env/vars.sh && ./runme_intel64_dynamic\"") + { + this.mockFixture.Process.StandardOutput.Append(this.exampleResults); + } + + return this.mockFixture.Process; + }; + + await executor.ExecuteAsync(EventContext.None, CancellationToken.None) + .ConfigureAwait(false); + + Assert.AreEqual(expectedCommands.Count, 0); + } + } + + [Test] + [TestCase(PlatformID.Unix, Architecture.X64, "2024.2.2.17")] + public async Task HPLinpackExecutorExecutesWorkloadAsExpectedWithPerformanceLibraries24OnUbuntuX64IntelPlatform(PlatformID platform, Architecture architecture, string performanceLibraryVersion) + { + this.SetupTest(platform, architecture); + this.mockFixture.Parameters["PerformanceLibrary"] = "INTEL"; + this.mockFixture.Parameters["PerformanceLibraryVersion"] = $"{performanceLibraryVersion}"; + + // Setup CPU info with socket count for Intel execution path + this.mockFixture.SystemManagement.Setup(mgr => mgr.GetCpuInfoAsync(It.IsAny())) + .ReturnsAsync(new CpuInfo("cpu", "description", 2, 9, 11, 13, true)); + + using (TestHPLExecutor executor = new TestHPLExecutor(this.mockFixture)) + { + List expectedCommands = new List() + { + $"sudo chmod +x {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "INTEL", $"{performanceLibraryVersion}", "l_onemkl_p_2024.2.2.17_offline.sh")}", + $"sudo ./l_onemkl_p_2024.2.2.17_offline.sh -a --silent --eula accept", + $"sudo chmod +x {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "INTEL", "2024.2.2.17", "l_HPCKit_p_2024.2.1.79_offline.sh")}", + $"sudo ./l_HPCKit_p_2024.2.1.79_offline.sh -a --silent --eula accept", + $"cp -r /opt/intel/oneapi/mkl/2024.2/share/mkl/benchmarks/mp_linpack {this.mockFixture.PlatformSpecifics.Combine(this.mockFixture.GetPackagePath("hplperformancelibraries"), "INTEL", "2024.2.2.17")}", + $"make arch=Linux_GCC", + $"sudo bash -c \". /opt/intel/oneapi/mpi/latest/env/vars.sh && ./runme_intel64_dynamic\"" + }; + + this.mockFixture.ProcessManager.OnCreateProcess = (command, arguments, workingDirectory) => + { + expectedCommands.Remove(expectedCommands[0]); + if (arguments == $"-c \". /opt/intel/oneapi/mpi/latest/env/vars.sh && ./runme_intel64_dynamic\"") + { + this.mockFixture.Process.StandardOutput.Append(this.exampleResults); + } + + return this.mockFixture.Process; + }; + + await executor.ExecuteAsync(EventContext.None, CancellationToken.None) + .ConfigureAwait(false); + + Assert.AreEqual(expectedCommands.Count, 0); + } + } + + [Test] + [TestCase(PlatformID.Unix, Architecture.X64, "1.0.0")] + public void HPLinpackExecutorThrowsExceptionForUnsupportedIntelPerformanceLibraryVersions(PlatformID platform, Architecture architecture, string performanceLibraryVersion) + { + this.SetupTest(platform, architecture); + this.mockFixture.Parameters["PerformanceLibrary"] = "INTEL"; + this.mockFixture.Parameters["PerformanceLibraryVersion"] = performanceLibraryVersion; + + using (TestHPLExecutor executor = new TestHPLExecutor(this.mockFixture)) + { + WorkloadException exception = Assert.ThrowsAsync( + () => executor.ExecuteAsync(EventContext.None, CancellationToken.None)); + + Assert.AreEqual( + $"The HPL workload currently only supports 2024.2.2.17 and 2025.1.0.803 versions of INTEL Math Kernel Library", + exception.Message); + } + } + private class TestHPLExecutor : HPLinpackExecutor { public TestHPLExecutor(MockFixture fixture) diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackMetricsParserTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackMetricsParserTests.cs index 83b0d94f90..9abe05924a 100644 --- a/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackMetricsParserTests.cs +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/HPLinpack/HPLinpackMetricsParserTests.cs @@ -20,34 +20,52 @@ class HPLinpackMetricsParserTests private string rawText; private HPLinpackMetricsParser testParser; - [SetUp] - public void Setup() + [Test] + public void HPLParserVerifyArmResults() { string workingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - string outputPath = Path.Combine(workingDirectory, "Examples", "HPLinpack", "HPLResults.txt"); - this.rawText = File.ReadAllText(outputPath); + string armoutputPath = Path.Combine(workingDirectory, "Examples", "HPLinpack", "HPLResultsArm.txt"); + this.rawText = File.ReadAllText(armoutputPath); this.testParser = new HPLinpackMetricsParser(this.rawText); - } - [Test] - public void HPLParserVerifyResults() - { IList metrics = this.testParser.Parse(); Assert.AreEqual(4, metrics.Count); - Assert.IsTrue(metrics[0].Metadata.ContainsKey("N_WR01R2R4")); - Assert.IsTrue(metrics[0].Metadata["N_WR01R2R4"].Equals("8029")); - Assert.IsTrue(metrics[0].Metadata.ContainsKey("NB_WR01R2R4")); - Assert.IsTrue(metrics[0].Metadata["NB_WR01R2R4"].Equals("400")); - Assert.IsTrue(metrics[0].Metadata.ContainsKey("P_WR01R2R4")); - Assert.IsTrue(metrics[0].Metadata["P_WR01R2R4"].Equals("1")); - Assert.IsTrue(metrics[0].Metadata.ContainsKey("Q_WR01R2R4")); - Assert.IsTrue(metrics[0].Metadata["Q_WR01R2R4"].Equals("2")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("N_W01R2R4")); + Assert.IsTrue(metrics[0].Metadata["N_W01R2R4"].Equals("8029")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("NB_W01R2R4")); + Assert.IsTrue(metrics[0].Metadata["NB_W01R2R4"].Equals("400")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("P_W01R2R4")); + Assert.IsTrue(metrics[0].Metadata["P_W01R2R4"].Equals("1")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("Q_W01R2R4")); + Assert.IsTrue(metrics[0].Metadata["Q_W01R2R4"].Equals("2")); MetricAssert.Exists(metrics, "Time", 11.55); MetricAssert.Exists(metrics, "GFlops", 29.874); MetricAssert.Exists(metrics, "Time", 11.55); MetricAssert.Exists(metrics, "GFlops", 29.874); } + [Test] + public void HPLParserVerifyIntelResults() + { + string workingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string inteloutputPath = Path.Combine(workingDirectory, "Examples", "HPLinpack", "HPLResultsIntel.txt"); + this.rawText = File.ReadAllText(inteloutputPath); + this.testParser = new HPLinpackMetricsParser(this.rawText); + + IList metrics = this.testParser.Parse(); + Assert.AreEqual(2, metrics.Count); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("N_W00R2L1")); + Assert.IsTrue(metrics[0].Metadata["N_W00R2L1"].Equals("82081")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("NB_W00R2L1")); + Assert.IsTrue(metrics[0].Metadata["NB_W00R2L1"].Equals("256")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("P_W00R2L1")); + Assert.IsTrue(metrics[0].Metadata["P_W00R2L1"].Equals("1")); + Assert.IsTrue(metrics[0].Metadata.ContainsKey("Q_W00R2L1")); + Assert.IsTrue(metrics[0].Metadata["Q_W00R2L1"].Equals("1")); + MetricAssert.Exists(metrics, "Time", 551.89); + MetricAssert.Exists(metrics, "GFlops", 668.032); + } + [Test] public void HPLParserThrowIfInvalidOutput() { @@ -58,5 +76,25 @@ public void HPLParserThrowIfInvalidOutput() SchemaException exception = Assert.Throws(() => this.testParser.Parse()); StringAssert.Contains("The HPLinpack output file has incorrect format for parsing", exception.Message); } + + [Test] + public void HPLParserExtractsVersionCorrectly() + { + string workingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string armoutputPath = Path.Combine(workingDirectory, "Examples", "HPLinpack", "HPLResultsArm.txt"); + this.rawText = File.ReadAllText(armoutputPath); + this.testParser = new HPLinpackMetricsParser(this.rawText); + + IList metrics = this.testParser.Parse(); + Assert.AreEqual("2.3", this.testParser.Version); + + // Test Intel output version extraction + string inteloutputPath = Path.Combine(workingDirectory, "Examples", "HPLinpack", "HPLResultsIntel.txt"); + this.rawText = File.ReadAllText(inteloutputPath); + this.testParser = new HPLinpackMetricsParser(this.rawText); + + metrics = this.testParser.Parse(); + Assert.AreEqual("2.3", this.testParser.Version); + } } } diff --git a/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackExecutor.cs b/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackExecutor.cs index 36e7d28d28..a50623ae7b 100644 --- a/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackExecutor.cs @@ -31,7 +31,12 @@ public class HPLinpackExecutor : VirtualClientComponent private int coreCount; private string makeFileName = "Make.Linux_GCC"; private string commandArguments; - private string hplPerfLibraryInfo; + private string hplArmPerfLibrary; + private string hplIntelMKL; + private string hplIntelHpcToolkit; + private string armPerfLibrariesPath; + private string amdPerfLibrariesPath; + private string intelPerfLibrariesPath; private CpuInfo cpuInfo; private long totalMemoryKiloBytes; @@ -142,7 +147,7 @@ public string PerformanceLibrary get { this.Parameters.TryGetValue(nameof(this.PerformanceLibrary), out IConvertible performanceLibrary); - return performanceLibrary?.ToString(); + return performanceLibrary?.ToString()?.ToUpperInvariant(); } } @@ -179,8 +184,6 @@ public string PerformanceLibraryVersion protected override async Task InitializeAsync(EventContext telemetryContext, CancellationToken cancellationToken) { await this.EvaluateParametersAsync(cancellationToken); - this.ThrowIfPlatformIsNotSupported(); - await this.CheckDistroSupportAsync(telemetryContext, cancellationToken); this.coreCount = this.cpuInfo.LogicalProcessorCount; MemoryInfo memoryInfo = await this.systemManagement.GetMemoryInfoAsync(CancellationToken.None); @@ -189,17 +192,39 @@ protected override async Task InitializeAsync(EventContext telemetryContext, Can this.ValidateParameters(); DependencyPath workloadPackage = await this.GetPlatformSpecificPackageAsync(this.PackageName, cancellationToken); - this.HPLDirectory = workloadPackage.Path; - await this.ConfigurePerformanceLibrary(telemetryContext, cancellationToken); - await this.DeleteFileAsync(this.PlatformSpecifics.Combine(this.HPLDirectory, this.makeFileName)); - await this.DeleteFileAsync(this.PlatformSpecifics.Combine(this.HPLDirectory, "setup", this.makeFileName)); + DependencyPath performanceLibrariesPackage = await this.packageManager.GetPackageAsync(this.PerformanceLibrariesPackageName, cancellationToken) + .ConfigureAwait(false); - await this.ExecuteCommandAsync("bash", "-c \"source make_generic\"", this.PlatformSpecifics.Combine(this.HPLDirectory, $"setup"), telemetryContext, cancellationToken, runElevated: true); - await this.ConfigureMakeFileAsync(telemetryContext, cancellationToken); - await this.ExecuteCommandAsync("ln", $"-s {this.PlatformSpecifics.Combine(this.HPLDirectory, $"setup", this.makeFileName)} {this.makeFileName}", this.HPLDirectory, telemetryContext, cancellationToken); + await this.ConfigurePerformanceLibrary(telemetryContext, cancellationToken); + if (this.CpuArchitecture == Architecture.X64 && this.PerformanceLibrary == "INTEL") + { + // Use PlatformSpecifics.Combine for paths instead of string concatenation + if (this.PerformanceLibraryVersion == "2024.2.2.17") + { + string intelMklPath = "/opt/intel/oneapi/mkl/2024.2/share/mkl/benchmarks/mp_linpack"; + await this.ExecuteCommandAsync("cp", $"-r {intelMklPath} {this.intelPerfLibrariesPath}", this.HPLDirectory, telemetryContext, cancellationToken); + } + else if (this.PerformanceLibraryVersion == "2025.1.0.803") + { + string intelMklPath = "~/intel/oneapi/mkl/2025.1/share/mkl/benchmarks/mp_linpack"; + await this.ExecuteCommandAsync("cp", $"-r {intelMklPath} {this.intelPerfLibrariesPath}", this.HPLDirectory, telemetryContext, cancellationToken); + } + else + { + throw new WorkloadException($"The HPL workload currently only supports 2024.2.2.17 and 2025.1.0.803 versions of INTEL Math Kernel Library"); + } + } + else + { + await this.DeleteFileAsync(this.PlatformSpecifics.Combine(this.HPLDirectory, this.makeFileName)); + await this.DeleteFileAsync(this.PlatformSpecifics.Combine(this.HPLDirectory, "setup", this.makeFileName)); + await this.ExecuteCommandAsync("bash", "-c \"source make_generic\"", this.PlatformSpecifics.Combine(this.HPLDirectory, "setup"), telemetryContext, cancellationToken, runElevated: true); + await this.ConfigureMakeFileAsync(telemetryContext, cancellationToken); + await this.ExecuteCommandAsync("ln", $"-s {this.PlatformSpecifics.Combine(this.HPLDirectory, "setup", this.makeFileName)} {this.makeFileName}", this.HPLDirectory, telemetryContext, cancellationToken); + } } /// @@ -213,26 +238,32 @@ protected override async Task ExecuteAsync(EventContext telemetryContext, Cancel await this.ExecuteCommandAsync("make", $"arch=Linux_GCC", this.HPLDirectory, telemetryContext, cancellationToken) .ConfigureAwait(false); - this.SetParameters(); await this.ConfigureDatFileAsync(telemetryContext, cancellationToken).ConfigureAwait(false); - IProcessProxy process; - if (this.cpuInfo.IsHyperthreadingEnabled) + if (this.CpuArchitecture == Architecture.X64 && this.PerformanceLibrary == "INTEL") { - this.commandArguments = $"--use-hwthread-cpus -np {this.NumberOfProcesses} --allow-run-as-root"; + this.commandArguments = "./runme_intel64_dynamic"; + process = await this.ExecuteCommandAsync("bash", $"-c \". /opt/intel/oneapi/mpi/latest/env/vars.sh && {this.commandArguments}\"", this.PlatformSpecifics.Combine(this.intelPerfLibrariesPath, "mp_linpack"), telemetryContext, cancellationToken, runElevated: true); } else { - this.commandArguments = $"-np {this.NumberOfProcesses} --allow-run-as-root"; - } + if (this.cpuInfo.IsHyperthreadingEnabled) + { + this.commandArguments = $"--use-hwthread-cpus -np {this.NumberOfProcesses} --allow-run-as-root"; + } + else + { + this.commandArguments = $"-np {this.NumberOfProcesses} --allow-run-as-root"; + } - if (this.BindToCores) - { - this.commandArguments += $" --bind-to core"; - } + if (this.BindToCores) + { + this.commandArguments += $" --bind-to core"; + } - process = await this.ExecuteCommandAsync("runuser", $"-u {Environment.UserName} -- mpirun {this.commandArguments} ./xhpl", this.PlatformSpecifics.Combine(this.HPLDirectory, "bin", "Linux_GCC"), telemetryContext, cancellationToken, runElevated: true); + process = await this.ExecuteCommandAsync("runuser", $"-u {Environment.UserName} -- mpirun {this.commandArguments} ./xhpl", this.PlatformSpecifics.Combine(this.HPLDirectory, "bin", "Linux_GCC"), telemetryContext, cancellationToken, runElevated: true); + } using (process) { @@ -242,23 +273,23 @@ await this.LogProcessDetailsAsync(process, telemetryContext, "HPLinpack", logToF .ConfigureAwait(); process.ThrowIfErrored(errorReason: ErrorReason.WorkloadFailed); - this.CaptureMetrics(process.StandardOutput.ToString(), $"runuser {this.commandArguments}", startTime, DateTime.UtcNow, telemetryContext, cancellationToken); + this.CaptureMetrics(process.StandardOutput.ToString(), $"{this.commandArguments}", startTime, DateTime.UtcNow, telemetryContext, cancellationToken); } } } } - private void SetParameters() + private void SetParameters(int count) { // gives you P*Q = Number of processes( Default: Environment.ProcessorCount, overwrite to value from command line to VC if supplied) and P <= Q and Q-P to be the minimum possible value. this.ProcessRows = 1; - this.ProcessColumns = this.NumberOfProcesses; - for (int i = 2; i <= Math.Sqrt(this.NumberOfProcesses); i++) + this.ProcessColumns = count; + for (int i = 2; i <= Math.Sqrt(count); i++) { - if (this.NumberOfProcesses % i == 0) + if (count % i == 0) { - int j = this.NumberOfProcesses / i; + int j = count / i; if (j - i < this.ProcessColumns - this.ProcessRows) { this.ProcessRows = i; @@ -268,37 +299,6 @@ private void SetParameters() } } - private void ThrowIfPlatformIsNotSupported() - { - if (this.Platform == PlatformID.Unix && this.CpuArchitecture != Architecture.Arm64 && this.PerformanceLibrary != null) - { - throw new WorkloadException( - $"The HPL workload with performance Libraries is currently only supported on the following platform/architectures: " + - $"'{PlatformSpecifics.LinuxArm64}'", - ErrorReason.PlatformNotSupported); - } - } - - private async Task CheckDistroSupportAsync(EventContext telemetryContext, CancellationToken cancellationToken) - { - if (this.Platform == PlatformID.Unix) - { - LinuxDistributionInfo distroInfo = await this.systemManagement.GetLinuxDistributionAsync(cancellationToken) - .ConfigureAwait(); - - switch (distroInfo.LinuxDistribution) - { - case LinuxDistribution.Ubuntu: - break; - default: - throw new WorkloadException( - $"The HPLinpack benchmark workload is not supported by Virtual Client on the current Linux distro " + - $"'{distroInfo.LinuxDistribution}'.", - ErrorReason.LinuxDistributionNotSupported); - } - } - } - private void ValidateParameters() { if (this.cpuInfo.IsHyperthreadingEnabled && this.NumberOfProcesses > this.coreCount) @@ -310,33 +310,75 @@ private void ValidateParameters() private async Task ConfigurePerformanceLibrary(EventContext telemetryContext, CancellationToken cancellationToken) { + DependencyPath performanceLibrariesPackage = await this.packageManager.GetPackageAsync(this.PerformanceLibrariesPackageName, cancellationToken) + .ConfigureAwait(false); + if (this.CpuArchitecture == Architecture.Arm64 && this.PerformanceLibrary == "ARM") { - // Switch between perf lib versions here + // Switch between ARM perf lib versions switch (this.PerformanceLibraryVersion) { case "23.04.1": - this.hplPerfLibraryInfo = "arm-performance-libraries_23.04.1"; + this.hplArmPerfLibrary = "arm-performance-libraries_23.04.1.sh"; break; case "24.10": - this.hplPerfLibraryInfo = "arm-performance-libraries_24.10"; + this.hplArmPerfLibrary = "arm-performance-libraries_24.10.sh"; break; case "25.04.1": - this.hplPerfLibraryInfo = "arm-performance-libraries_25.04.1"; + this.hplArmPerfLibrary = "arm-performance-libraries_25.04.1.sh"; break; default: - throw new WorkloadException( - $"The HPL workload is currently only supports the perf libraries versions 23.04.1, 24.10 and 25.04.1 on the following platform/architectures: " + - $"'{PlatformSpecifics.LinuxArm64}'.", - ErrorReason.PlatformNotSupported); + throw new WorkloadException($"The HPL workload currently only supports versions 23.04.1, 24.10 and 25.04.1 of the ARM performance libraries"); + } + + this.armPerfLibrariesPath = this.PlatformSpecifics.Combine(performanceLibrariesPackage.Path, "ARM"); + await this.systemManagement.MakeFileExecutableAsync(this.PlatformSpecifics.Combine(this.armPerfLibrariesPath, $"{this.hplArmPerfLibrary}"), this.Platform, cancellationToken).ConfigureAwait(false); + await this.ExecuteCommandAsync($"./{this.hplArmPerfLibrary}", $"-a", this.armPerfLibrariesPath, telemetryContext, cancellationToken, runElevated: true); + } + + if (this.CpuArchitecture == Architecture.X64) + { + if (this.PerformanceLibrary == "AMD") + { + switch (this.PerformanceLibraryVersion) + { + case "4.2.0": + case "5.0.0": + case "5.1.0": + this.amdPerfLibrariesPath = this.PlatformSpecifics.Combine(performanceLibrariesPackage.Path, "AMD", this.PerformanceLibraryVersion); + break; + default: + throw new WorkloadException($"The HPL workload currently only supports 4.2.0, 5.0.0 and 5.1.0 versions of AMD performance libraries"); + } + + string installPath = this.PlatformSpecifics.Combine(this.HPLDirectory); + await this.systemManagement.MakeFileExecutableAsync(this.PlatformSpecifics.Combine(this.amdPerfLibrariesPath, "install.sh"), this.Platform, cancellationToken).ConfigureAwait(false); + await this.ExecuteCommandAsync($"./install.sh", $"-t {installPath} -i lp64", this.amdPerfLibrariesPath, telemetryContext, cancellationToken, runElevated: true).ConfigureAwait(false); } - DependencyPath performanceLibrariesPackage = await this.packageManager.GetPackageAsync(this.PerformanceLibrariesPackageName, cancellationToken) - .ConfigureAwait(false); + if (this.PerformanceLibrary == "INTEL") + { + // Switch between different versions of INTEL Math Kernel Library + switch (this.PerformanceLibraryVersion) + { + case "2024.2.2.17": + this.hplIntelMKL = "l_onemkl_p_2024.2.2.17_offline.sh"; + this.hplIntelHpcToolkit = "l_HPCKit_p_2024.2.1.79_offline.sh"; + break; + case "2025.1.0.803": + this.hplIntelMKL = "intel-onemkl-2025.1.0.803_offline.sh"; + this.hplIntelHpcToolkit = "intel-oneapi-hpc-toolkit-2025.1.3.10_offline.sh"; + break; + default: + throw new WorkloadException($"The HPL workload currently only supports 2024.2.2.17 and 2025.1.0.803 versions of INTEL Math Kernel Library"); + } - string armperfLibrariesPath = this.PlatformSpecifics.Combine(performanceLibrariesPackage.Path, "ARM"); - await this.systemManagement.MakeFileExecutableAsync(this.PlatformSpecifics.Combine(armperfLibrariesPath, $"{this.hplPerfLibraryInfo}.sh"), this.Platform, cancellationToken).ConfigureAwait(false); - await this.ExecuteCommandAsync($"./{this.hplPerfLibraryInfo}.sh", $"-a", armperfLibrariesPath, telemetryContext, cancellationToken, runElevated: true); + this.intelPerfLibrariesPath = this.PlatformSpecifics.Combine(performanceLibrariesPackage.Path, "INTEL", this.PerformanceLibraryVersion); + await this.systemManagement.MakeFileExecutableAsync(this.PlatformSpecifics.Combine(this.intelPerfLibrariesPath, $"{this.hplIntelHpcToolkit}"), this.Platform, cancellationToken).ConfigureAwait(false); + await this.ExecuteCommandAsync($"./{this.hplIntelHpcToolkit}", "-a --silent --eula accept", this.intelPerfLibrariesPath, telemetryContext, cancellationToken, runElevated: true); + await this.systemManagement.MakeFileExecutableAsync(this.PlatformSpecifics.Combine(this.intelPerfLibrariesPath, $"{this.hplIntelMKL}"), this.Platform, cancellationToken).ConfigureAwait(false); + await this.ExecuteCommandAsync($"./{this.hplIntelMKL}", "-a --silent --eula accept", this.intelPerfLibrariesPath, telemetryContext, cancellationToken, runElevated: true); + } } } @@ -389,12 +431,13 @@ await this.fileSystem.File.ReplaceInFileAsync( await this.fileSystem.File.ReplaceInFileAsync( makeFilePath, @"LINKER *= *[^\n]*", "LINKER = mpifort", cancellationToken); } - else if (this.PerformanceLibrary != null && this.CpuArchitecture != Architecture.Arm64) + else if (this.PerformanceLibrary == "AMD" && this.CpuArchitecture == Architecture.X64) { - throw new WorkloadException( - $"The HPL workload is currently only supports with perf libraries on the following platform/architectures: " + - $"'{PlatformSpecifics.LinuxArm64}'.", - ErrorReason.PlatformNotSupported); + await this.fileSystem.File.ReplaceInFileAsync( + makeFilePath, @"LAdir *=", $"LAdir = {this.PlatformSpecifics.Combine(this.HPLDirectory, this.PerformanceLibraryVersion, "gcc")}", cancellationToken); + + await this.fileSystem.File.ReplaceInFileAsync( + makeFilePath, @"LAlib *= *[^\n]*", $"LAlib = {this.PlatformSpecifics.Combine(this.HPLDirectory, this.PerformanceLibraryVersion, "gcc", "lib", "libblis.a")}", cancellationToken); } else { @@ -421,7 +464,28 @@ await this.fileSystem.File.ReplaceInFileAsync( private async Task ConfigureDatFileAsync(EventContext telemetryContext, CancellationToken cancellationToken) { - string hplDatFile = this.PlatformSpecifics.Combine(this.HPLDirectory, "bin", "Linux_GCC", "HPL.dat"); + string hplDatFile; + if (this.CpuArchitecture == Architecture.X64 && this.PerformanceLibrary == "INTEL") + { + this.SetParameters(this.cpuInfo.SocketCount); + hplDatFile = this.PlatformSpecifics.Combine(this.intelPerfLibrariesPath, "mp_linpack", "HPL.dat"); + + string hplRunmeFile = this.PlatformSpecifics.Combine(this.intelPerfLibrariesPath, "mp_linpack", "runme_intel64_dynamic"); + await this.fileSystem.File.ReplaceInFileAsync( + hplRunmeFile, @"export MPI_PROC_NUM *= *[^\n]*", $"export MPI_PROC_NUM={this.cpuInfo.SocketCount}", cancellationToken); + + await this.fileSystem.File.ReplaceInFileAsync( + hplRunmeFile, @"export MPI_PER_NODE *= *[^\n]*", $"export MPI_PER_NODE={this.cpuInfo.SocketCount}", cancellationToken); + + await this.fileSystem.File.ReplaceInFileAsync( + hplRunmeFile, @"export NUMA_PER_MPI *= *[^\n]*", $"export NUMA_PER_MPI={this.cpuInfo.SocketCount}", cancellationToken); + } + else + { + hplDatFile = this.PlatformSpecifics.Combine(this.HPLDirectory, "bin", "Linux_GCC", "HPL.dat"); + this.SetParameters(this.NumberOfProcesses); + } + await this.fileSystem.File.ReplaceInFileAsync( hplDatFile, @"([0-9]+\s+)+# of problems sizes", $"1 # of problems sizes", cancellationToken); @@ -466,7 +530,6 @@ await this.fileSystem.File.ReplaceInFileAsync( await this.fileSystem.File.ReplaceInFileAsync( hplDatFile, @"([0-9]+\s+)+RFACTs", $"2 RFACTs", cancellationToken); - } private async Task DeleteFileAsync(string filePath) @@ -480,23 +543,45 @@ await this.systemManagement.FileSystem.File.DeleteAsync(filePath) private void CaptureMetrics(string results, string commandArguments, DateTime startTime, DateTime endTime, EventContext telemetryContext, CancellationToken cancellationToken) { + HPLinpackMetricsParser parser = new HPLinpackMetricsParser(results); + IList metrics = parser.Parse(); + var additionalMetadata = new Dictionary(); additionalMetadata[$"{nameof(this.PerformanceLibrary)}"] = this.PerformanceLibrary; additionalMetadata[$"{nameof(this.PerformanceLibraryVersion)}"] = this.PerformanceLibraryVersion; + + // Add GCC version to metadata + string gccVersion = this.GetGccVersion(); + additionalMetadata["GccVersion"] = gccVersion; + + if (this.PerformanceLibrary == "ARM") + { + additionalMetadata["Origin"] = "Netlib HPL configured with Arm Performance Libraries"; + } + else if (this.PerformanceLibrary == "AMD" && this.CpuArchitecture == Architecture.X64) + { + additionalMetadata["Origin"] = "Netlib HPL configured with Amd Performance Libraries"; + } + else if (this.PerformanceLibrary == "INTEL" && this.CpuArchitecture == Architecture.X64) + { + additionalMetadata["Origin"] = "Intel's Distro for HPL based on Netlib HPLinpack 2.3"; + } + else + { + additionalMetadata["Origin"] = "Netlib HPL with no Performance Libraries"; + } + this.MetadataContract.AddForScenario( "HPLinpack", commandArguments, - toolVersion: null, + toolVersion: parser.Version, additionalMetadata: additionalMetadata); this.MetadataContract.Apply(telemetryContext); - HPLinpackMetricsParser parser = new HPLinpackMetricsParser(results); - IList metrics = parser.Parse(); - foreach (Metric result in metrics) { - this.Logger.LogMetric( + this.Logger.LogMetric( "HPLinpack", $"{this.Scenario}_{this.ProblemSizeN}N_{this.BlockSizeNB}NB_{this.ProcessRows}P_{this.ProcessColumns}Q", startTime, @@ -505,7 +590,7 @@ private void CaptureMetrics(string results, string commandArguments, DateTime st result.Value, result.Unit, null, - $"[ -N {this.ProblemSizeN} -NB {this.BlockSizeNB} -P {this.ProcessRows} -Q {this.ProcessColumns} {this.commandArguments} --perfLibrary={this.hplPerfLibraryInfo} ]", + $"[ -N {this.ProblemSizeN} -NB {this.BlockSizeNB} -P {this.ProcessRows} -Q {this.ProcessColumns} --perfLibrary={this.PerformanceLibrary} --perfLibraryVersion={this.PerformanceLibraryVersion} ]", this.Tags, telemetryContext, result.Relativity, @@ -513,6 +598,26 @@ private void CaptureMetrics(string results, string commandArguments, DateTime st } } + private string GetGccVersion() + { + string version = string.Empty; + try + { + using (IProcessProxy process = this.systemManagement.ProcessManager.CreateProcess("gcc", "-dumpversion")) + { + process.StartAndWaitAsync(CancellationToken.None).GetAwaiter().GetResult(); + version = process.StandardOutput.ToString().Trim(); + } + } + catch + { + // If GCC is not installed or there's an error, return empty string + version = string.Empty; + } + + return version; + } + internal class HPLinpackState : State { public HPLinpackState(IDictionary properties = null) diff --git a/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackMetricsParser.cs b/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackMetricsParser.cs index f96bac30ab..b0b2a8e583 100644 --- a/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackMetricsParser.cs +++ b/src/VirtualClient/VirtualClient.Actions/HPLinpack/HPLinpackMetricsParser.cs @@ -18,13 +18,18 @@ public class HPLinpackMetricsParser : MetricsParser /// /// To match metrics line of the result. /// - private const string GetMetricsLine = @"(?<=WR).*(?=\n)"; + private const string GetMetricsLine = @"(?<=W[RC]).*(?=\n)"; /// /// Split string at one or more spaces. /// private const string SplitAtSpace = @"\s{1,}"; + /// + /// To match HPLinpack version from the output. + /// + private const string HPLinpackVersionRegex = @"HPLinpack\s+(\d+\.\d+)"; + private List metrics; /// @@ -41,9 +46,21 @@ public HPLinpackMetricsParser(string rawText) /// public DataTable LinpackResult { get; set; } + /// + /// The HPLinpack version extracted from results. + /// + public string Version { get; private set; } + /// public override IList Parse() { + // Extract HPLinpack version + Match versionMatch = Regex.Match(this.RawText, HPLinpackVersionRegex); + if (versionMatch.Success && versionMatch.Groups.Count > 1) + { + this.Version = versionMatch.Groups[1].Value; + } + var matches = Regex.Matches(this.RawText, GetMetricsLine); if (matches.Count == 0) { @@ -58,10 +75,10 @@ public override IList Parse() Dictionary metadata = new Dictionary() { - { $"N_WR{st[0]}", st[1] }, - { $"NB_WR{st[0]}", st[2] }, - { $"P_WR{st[0]}", st[3] }, - { $"Q_WR{st[0]}", st[4] }, + { $"N_W{st[0]}", st[1] }, + { $"NB_W{st[0]}", st[2] }, + { $"P_W{st[0]}", st[3] }, + { $"Q_W{st[0]}", st[4] }, }; this.metrics.Add(new Metric($"Time", Convert.ToDouble(st[5]), "secs", MetricRelativity.Undefined, metadata: metadata, verbosity: 2)); diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-CPU-HPLINPACK.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-CPU-HPLINPACK.json index 29153615b2..d6b2afd86b 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-CPU-HPLINPACK.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-CPU-HPLINPACK.json @@ -61,7 +61,7 @@ "Parameters": { "Scenario": "DownloadHPLPerformanceLibrariesPackage", "BlobContainer": "packages", - "BlobName": "hplperformancelibraries.1.1.2.zip", + "BlobName": "hplperformancelibraries.2.0.0.zip", "PackageName": "hplperformancelibraries", "Extract": true } diff --git a/website/docs/workloads/hplinpack/hplinpack-profiles.md b/website/docs/workloads/hplinpack/hplinpack-profiles.md index 4318625948..588de58dc0 100644 --- a/website/docs/workloads/hplinpack/hplinpack-profiles.md +++ b/website/docs/workloads/hplinpack/hplinpack-profiles.md @@ -59,8 +59,7 @@ This profile is designed to identify general/broad regressions when compared aga * [Resources for above input parameters(ProblemSizeN,BlockSizeNB) configuration setting](https://netlib.org/utk/people/JackDongarra/faq-linpack.html#_For_HPL_What_problem%20size%20N%20should) * [Inputs Tuning](https://community.arm.com/arm-community-blogs/b/high-performance-computing-blog/posts/profiling-and-tuning-linpack-step-step-guide) - - + * **Profile Runtimes** See the 'Metadata' section of the profile for estimated runtimes. These timings represent the length of time required to run a single round of profile actions. These timings can be used to determine minimum required runtimes for the Virtual Client in order to get results. These are often estimates based on the @@ -80,6 +79,15 @@ This profile is designed to identify general/broad regressions when compared aga ``` + * **Performance Library Parameter set** + The following parameter sets are supported. + + | Platform | PerformanceLibrary | PerformanceLibraryVersion | CompilerName | CompilerVersion | Commandline Usage | + |--------------------------|-----------------------------|-----------------------------------------------|------------|------------| + | arm64 | ARM | 23.04.1, 24.10 and 25.04.1 | gcc | 11 | --parameters=PerformanceLibrary=ARM,,,PerformanceLibraryVersion=23.04.10,,,CompilerName=gcc,,,CompilerVersion=11 | + | x64 | AMD | 4.2.0, 5.0.0, 5.1.0 | gcc | 11 | --parameters=PerformanceLibrary=AMD,,,PerformanceLibraryVersion=4.2.0,,,CompilerName=gcc,,,CompilerVersion=11 | +* | x64 | INTEL | 2024.2.2.17, 2025.1.0.803 | gcc | 13 | --parameters=PerformanceLibrary=INTEL,,,PerformanceLibraryVersion=4.2.0,,,CompilerVersion=13 | + * **Resources** * [Performance Libraries for ARM] (https://developer.arm.com/downloads/-/arm-performance-libraries)