diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index db4ce658d6c767..546ebc61e0e015 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -899,7 +899,9 @@ %(PayloadDirectory) $(_WorkaroundForNuGetMigrationsForPrepending) dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) + $(_WorkaroundForNuGetMigrationsForPrepending) dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) && ls -R $(_WorkaroundForNuGetMigrationsForPrepending) dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) -trait TestGroup=%(TestGroup) + $(_WorkaroundForNuGetMigrationsForPrepending) dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) -trait TestGroup=%(TestGroup) && ls -R $([System.TimeSpan]::FromMinutes($(TimeoutPerTestCollectionInMinutes))) coreclr_tests.run.$(TargetOS).$(TargetArchitecture).$(Configuration).mch;coreclr_tests.run.$(TargetOS).$(TargetArchitecture).$(Configuration).log diff --git a/src/tests/Directory.Build.targets b/src/tests/Directory.Build.targets index 7c0dbf9e492ffa..ec6b557a5929f5 100644 --- a/src/tests/Directory.Build.targets +++ b/src/tests/Directory.Build.targets @@ -153,6 +153,7 @@ - + true diff --git a/src/tests/readytorun/JittedMethodsCountingTest/HelloWorld/HelloWorld.cs b/src/tests/readytorun/JittedMethodsCountingTest/HelloWorld/HelloWorld.cs new file mode 100644 index 00000000000000..1ca273d0f84576 --- /dev/null +++ b/src/tests/readytorun/JittedMethodsCountingTest/HelloWorld/HelloWorld.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +internal class HelloWorld +{ + static int Main(string[] args) + { + Console.WriteLine("Hello World!"); + return 0; + } +} diff --git a/src/tests/readytorun/JittedMethodsCountingTest/HelloWorld/HelloWorld.csproj b/src/tests/readytorun/JittedMethodsCountingTest/HelloWorld/HelloWorld.csproj new file mode 100644 index 00000000000000..e9b456897a2c77 --- /dev/null +++ b/src/tests/readytorun/JittedMethodsCountingTest/HelloWorld/HelloWorld.csproj @@ -0,0 +1,13 @@ + + + + Exe + $(NetCoreAppToolCurrent) + BuildOnly + + + + + + + diff --git a/src/tests/readytorun/JittedMethodsCountingTest/JittedMethodsCountingTest.cs b/src/tests/readytorun/JittedMethodsCountingTest/JittedMethodsCountingTest.cs new file mode 100644 index 00000000000000..a4e4dad567cd32 --- /dev/null +++ b/src/tests/readytorun/JittedMethodsCountingTest/JittedMethodsCountingTest.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Xunit; + +using Reflection = System.Reflection; + +public class JittedMethodsCountingTest +{ + private const int MAX_JITTED_METHODS_ACCEPTED = 120; + + [Fact] + public static int TestEntryPoint() + { + // If DOTNET_ReadyToRun is disabled, then this test ought to be skipped. + if (!IsReadyToRunEnvSet()) + { + Console.WriteLine("\nThis test is only supported in ReadyToRun scenarios." + + " Skipping...\n"); + return 100; + } + + string testAppLocation = Path.GetDirectoryName(Reflection + .Assembly + .GetExecutingAssembly() + .Location); + + string appName = Path.Combine(testAppLocation, "HelloWorld.dll"); + string jitOutputFile = Path.Combine(testAppLocation, "jits.txt"); + + // DOTNET_JitStdOutFile appends to the file in question if it exists. + // This can potentially cause issues, so we have to make sure it is + // created exclusively for this test's purpose. + if (File.Exists(jitOutputFile)) + { + File.Delete(jitOutputFile); + } + + // For adding any new apps for this test, make sure their success return + // code is 0, so we can universally handle when they fail. + int appResult = RunHelloWorldApp(appName, jitOutputFile); + + if (appResult != 0) + { + Console.WriteLine("App failed somewhere and so we can't proceed with" + + " the Jitted Methods analysis. Exiting..."); + return 101; + } + + // App finished successfully. We can now take a look at the methods that + // got jitted at runtime. + int jits = GetNumberOfJittedMethods(jitOutputFile); + return jits > 0 && jits <= MAX_JITTED_METHODS_ACCEPTED ? 100 : 101; + } + + private static bool IsReadyToRunEnvSet() + { + string? dotnetR2R = Environment.GetEnvironmentVariable("DOTNET_ReadyToRun"); + return (string.IsNullOrEmpty(dotnetR2R) || dotnetR2R == "1") ? true : false; + } + + private static int RunHelloWorldApp(string appName, string jitOutputFile) + { + int appExitCode = -1; + + // Set up our CoreRun call. + string coreRoot = Environment.GetEnvironmentVariable("CORE_ROOT"); + string exeSuffix = OperatingSystem.IsWindows() ? ".exe" : ""; + string coreRun = Path.Combine(coreRoot, $"corerun{exeSuffix}"); + + using (Process app = new Process()) + { + var startInfo = new ProcessStartInfo + { + FileName = coreRun, + Arguments = appName, + CreateNoWindow = true, + UseShellExecute = false, + }; + + // Set up the environment for running the test app. We are looking + // to seeing how many methods were jitted at runtime. So, we ask + // the runtime to print them out with DOTNET_JitDisasmSummary, and + // write them out to a file we can parse and investigate later + // with DOTNET_JitStdOutFile. + startInfo.EnvironmentVariables.Add("DOTNET_JitDisasmSummary", "1"); + startInfo.EnvironmentVariables.Add("DOTNET_JitStdOutFile", jitOutputFile); + + Console.WriteLine("\nLaunching Test App: {0} {1}", startInfo.FileName, + startInfo.Arguments); + + app.StartInfo = startInfo; + app.Start(); + app.WaitForExit(); + + appExitCode = app.ExitCode; + Console.WriteLine("App Exit Code: {0}", appExitCode); + Console.WriteLine("Jitted Methods Generated File: {0}", jitOutputFile); + } + + return appExitCode; + } + + private static int GetNumberOfJittedMethods(string jitOutputFile) + { + string[] lines = File.ReadAllLines(jitOutputFile); + + // Print out the jitted methods from the app run previously. This is + // mostly done as additional logging to simplify potential bug investigations + // in the future. + + Console.WriteLine("\n========== App Jitted Methods Start =========="); + foreach (string line in lines) + { + Console.WriteLine(line); + } + Console.WriteLine("========== App Jitted Methods End ==========\n"); + + // The jitted methods are printed in the following format: + // + // method number: method description + // + // This is why we split by ':' and parse the left side as a number. + + string[] tokens = lines.Last().Split(":"); + int numJittedMethods = Int32.Parse(tokens[0]); + Console.WriteLine("Total Jitted Methods: {0}\n", numJittedMethods); + + return numJittedMethods; + } +} + diff --git a/src/tests/readytorun/JittedMethodsCountingTest/JittedMethodsCountingTest.csproj b/src/tests/readytorun/JittedMethodsCountingTest/JittedMethodsCountingTest.csproj new file mode 100644 index 00000000000000..8b12af71561fbd --- /dev/null +++ b/src/tests/readytorun/JittedMethodsCountingTest/JittedMethodsCountingTest.csproj @@ -0,0 +1,22 @@ + + + + pdbonly + true + true + + + + + + + + + false + Content + Always + + + + +