diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs index d903209a5d..ef5dc13cf1 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs @@ -513,28 +513,42 @@ private int VerifyParallelSettingAndCalculateParallelLevel( try { // Check the user parallel setting. - int userParallelSetting = RunSettingsUtilities.GetMaxCpuCount(runSettings); - parallelLevelToUse = userParallelSetting == 0 + int maxCpuCount = RunSettingsUtilities.GetMaxCpuCount(runSettings); + parallelLevelToUse = maxCpuCount == 0 ? _environment.ProcessorCount - : userParallelSetting; + : maxCpuCount; EqtTrace.Verbose( "TestEngine: Initializing Parallel Execution as MaxCpuCount is set to: {0}", parallelLevelToUse); - // TODO: EXPERIMENTAL FEATURE - will need to be removed or strengthen/tested. - // A negative value is used to indicate that the value should be used as a percentage of the number of cores. - if (parallelLevelToUse < 0) - { - parallelLevelToUse = (int)Math.Max(1, Math.Round((double)-parallelLevelToUse * _environment.ProcessorCount / 100.0, MidpointRounding.AwayFromZero)); - } - var enableParallel = parallelLevelToUse > 1; // Verify if the number of sources is less than user setting of parallel. // We should use number of sources as the parallel level, if sources count is less // than parallel level. if (enableParallel) { + // In case of a background discovery we want to reduce the number of cores utilized + // to leave enough power for other tasks. + var runSettingsEnvVariables = InferRunSettingsHelper.GetEnvironmentVariables(runSettings); + string isBackgroundDiscoveryEnabled = null; + if (runSettingsEnvVariables is not null + && runSettingsEnvVariables.TryGetValue("VSTEST_BACKGROUND_DISCOVERY", out isBackgroundDiscoveryEnabled) + && isBackgroundDiscoveryEnabled == "1" + && maxCpuCount == 0) // If user specifies a CPU count, respect it + { + // Dummy logic based on some observations, might need to be tweaked/improved. + parallelLevelToUse = parallelLevelToUse switch + { + 1 => 1, + < 8 => (int)Math.Round(parallelLevelToUse / 2.0, MidpointRounding.AwayFromZero), + _ => (int)Math.Round(0.75 * parallelLevelToUse, MidpointRounding.AwayFromZero), + }; + } + + EqtTrace.Verbose("TestEngine.VerifyParallelSettingAndCalculateParallelLevel: Parallel execution is enabled (cpu count: {0}, max cpu count is {1}, calculated cpu count is {2}, background mode is {3}, number of sources is {4})", _environment.ProcessorCount, maxCpuCount, parallelLevelToUse, isBackgroundDiscoveryEnabled == "1" ? "enabled" : "disabled", sourceCount); + + parallelLevelToUse = Math.Min(sourceCount, parallelLevelToUse); // If only one source, no need to use parallel service client. diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs index e6bc1da63b..8d9ca315c1 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs @@ -337,6 +337,7 @@ public void Initialize(IMessageLogger logger, string runsettingsXml) Shared = !runConfiguration.DisableAppDomain; _hostExitedEventRaised = false; + IsInitialized = true; } @@ -506,20 +507,24 @@ private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToke return false; } - SetProcessPriority(_testHostProcess, _environmentVariableHelper); + AdjustProcessPriorityBasedOnSettings(_testHostProcess, testHostStartInfo.EnvironmentVariables); OnHostLaunched(new HostProviderEventArgs("Test Runtime launched", 0, _testHostProcess.Id)); return true; } - internal static void SetProcessPriority(Process testHostProcess, IEnvironmentVariableHelper environmentVariableHelper) + internal static void AdjustProcessPriorityBasedOnSettings(Process testHostProcess, IDictionary? testHostEnvironmentVariables) { ProcessPriorityClass testHostPriority = ProcessPriorityClass.BelowNormal; try { - testHostPriority = environmentVariableHelper.GetEnvironmentVariableAsEnum("VSTEST_HOST_INTERNAL_PRIORITY", testHostPriority); - testHostProcess.PriorityClass = testHostPriority; - EqtTrace.Verbose("Setting test host process priority to {0}", testHostProcess.PriorityClass); + if (testHostEnvironmentVariables is not null + && testHostEnvironmentVariables.TryGetValue("VSTEST_BACKGROUND_DISCOVERY", out var isBackgroundDiscoveryEnabled) + && isBackgroundDiscoveryEnabled == "1") + { + testHostProcess.PriorityClass = testHostPriority; + EqtTrace.Verbose("Setting test host process priority to {0}", testHostProcess.PriorityClass); + } } // Setting the process Priority can fail with Win32Exception, NotSupportedException or InvalidOperationException. catch (Exception ex) diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs index cbbdec935f..88825066a4 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs @@ -748,7 +748,7 @@ private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToke return false; } - DefaultTestHostManager.SetProcessPriority(_testHostProcess, _environmentVariableHelper); + DefaultTestHostManager.AdjustProcessPriorityBasedOnSettings(_testHostProcess, testHostStartInfo.EnvironmentVariables); OnHostLaunched(new HostProviderEventArgs("Test Runtime launched", 0, _testHostProcess.Id)); return true; }