From 111b204580020b961991cabd0c412ce1e36dec61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 31 Jul 2023 15:02:55 +0200 Subject: [PATCH 1/4] Fix timing issue in parallel execution --- playground/TestPlatform.Playground/Program.cs | 232 ++++++++++-------- .../Parallel/ParallelOperationManager.cs | 63 ++++- .../Parallel/ParallelProxyDiscoveryManager.cs | 6 + .../Parallel/ParallelProxyExecutionManager.cs | 98 ++++---- .../Parallel/ParallelRunEventsHandler.cs | 6 + 5 files changed, 249 insertions(+), 156 deletions(-) diff --git a/playground/TestPlatform.Playground/Program.cs b/playground/TestPlatform.Playground/Program.cs index 875026c24e..aac04753aa 100644 --- a/playground/TestPlatform.Playground/Program.cs +++ b/playground/TestPlatform.Playground/Program.cs @@ -10,7 +10,7 @@ using System.Reflection; using System.Threading; -using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; +// using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; @@ -35,7 +35,6 @@ static void Main() var thisAssemblyPath = Assembly.GetEntryAssembly()!.Location; var here = Path.GetDirectoryName(thisAssemblyPath)!; - var playground = Path.GetFullPath(Path.Combine(here, "..", "..", "..", "..")); var console = Path.Combine(here, "vstest.console", "vstest.console.exe"); @@ -43,120 +42,139 @@ static void Main() - - - - - - - - - - False - True - - - 999999 - - - - - - - - - - + + """; var sources = new[] { - Path.Combine(playground, "bin", "MSTest1", "Debug", "net472", "MSTest1.dll"), - Path.Combine(playground, "bin", "MSTest2", "Debug", "net472", "MSTest2.dll"), - // The built in .NET projects don't now work right now in Playground, there is some conflict with Arcade. - // But if you create one outside of Playground it will work. - //Path.Combine(playground, "bin", "MSTest1", "Debug", "net7.0", "MSTest1.dll"), + @"S:\t\dlls99\mstest1\bin\Debug\net8.0\mstest1.dll", +@"S:\t\dlls99\mstest10\bin\Debug\net8.0\mstest10.dll", +@"S:\t\dlls99\mstest11\bin\Debug\net8.0\mstest11.dll", +@"S:\t\dlls99\mstest12\bin\Debug\net8.0\mstest12.dll", +@"S:\t\dlls99\mstest13\bin\Debug\net8.0\mstest13.dll", +@"S:\t\dlls99\mstest14\bin\Debug\net8.0\mstest14.dll", +@"S:\t\dlls99\mstest15\bin\Debug\net8.0\mstest15.dll", +@"S:\t\dlls99\mstest16\bin\Debug\net8.0\mstest16.dll", +@"S:\t\dlls99\mstest17\bin\Debug\net8.0\mstest17.dll", +@"S:\t\dlls99\mstest18\bin\Debug\net8.0\mstest18.dll", +@"S:\t\dlls99\mstest19\bin\Debug\net8.0\mstest19.dll", +@"S:\t\dlls99\mstest2\bin\Debug\net8.0\mstest2.dll", +@"S:\t\dlls99\mstest20\bin\Debug\net8.0\mstest20.dll", +@"S:\t\dlls99\mstest21\bin\Debug\net8.0\mstest21.dll", +@"S:\t\dlls99\mstest22\bin\Debug\net8.0\mstest22.dll", +@"S:\t\dlls99\mstest23\bin\Debug\net8.0\mstest23.dll", +@"S:\t\dlls99\mstest24\bin\Debug\net8.0\mstest24.dll", +@"S:\t\dlls99\mstest25\bin\Debug\net8.0\mstest25.dll", +@"S:\t\dlls99\mstest26\bin\Debug\net8.0\mstest26.dll", +@"S:\t\dlls99\mstest27\bin\Debug\net8.0\mstest27.dll", +@"S:\t\dlls99\mstest28\bin\Debug\net8.0\mstest28.dll", +@"S:\t\dlls99\mstest29\bin\Debug\net8.0\mstest29.dll", +@"S:\t\dlls99\mstest3\bin\Debug\net8.0\mstest3.dll", +@"S:\t\dlls99\mstest30\bin\Debug\net8.0\mstest30.dll", +@"S:\t\dlls99\mstest31\bin\Debug\net8.0\mstest31.dll", +@"S:\t\dlls99\mstest32\bin\Debug\net8.0\mstest32.dll", +@"S:\t\dlls99\mstest33\bin\Debug\net8.0\mstest33.dll", +@"S:\t\dlls99\mstest34\bin\Debug\net8.0\mstest34.dll", +@"S:\t\dlls99\mstest35\bin\Debug\net8.0\mstest35.dll", +@"S:\t\dlls99\mstest36\bin\Debug\net8.0\mstest36.dll", +@"S:\t\dlls99\mstest37\bin\Debug\net8.0\mstest37.dll", +@"S:\t\dlls99\mstest38\bin\Debug\net8.0\mstest38.dll", +@"S:\t\dlls99\mstest39\bin\Debug\net8.0\mstest39.dll", +@"S:\t\dlls99\mstest4\bin\Debug\net8.0\mstest4.dll", +@"S:\t\dlls99\mstest40\bin\Debug\net8.0\mstest40.dll", +@"S:\t\dlls99\mstest41\bin\Debug\net8.0\mstest41.dll", +@"S:\t\dlls99\mstest42\bin\Debug\net8.0\mstest42.dll", +@"S:\t\dlls99\mstest43\bin\Debug\net8.0\mstest43.dll", +@"S:\t\dlls99\mstest44\bin\Debug\net8.0\mstest44.dll", +@"S:\t\dlls99\mstest45\bin\Debug\net8.0\mstest45.dll", +@"S:\t\dlls99\mstest46\bin\Debug\net8.0\mstest46.dll", +@"S:\t\dlls99\mstest47\bin\Debug\net8.0\mstest47.dll", +@"S:\t\dlls99\mstest48\bin\Debug\net8.0\mstest48.dll", +@"S:\t\dlls99\mstest49\bin\Debug\net8.0\mstest49.dll", +@"S:\t\dlls99\mstest5\bin\Debug\net8.0\mstest5.dll", +@"S:\t\dlls99\mstest50\bin\Debug\net8.0\mstest50.dll", +@"S:\t\dlls99\mstest51\bin\Debug\net8.0\mstest51.dll", +@"S:\t\dlls99\mstest52\bin\Debug\net8.0\mstest52.dll", +@"S:\t\dlls99\mstest53\bin\Debug\net8.0\mstest53.dll", +@"S:\t\dlls99\mstest54\bin\Debug\net8.0\mstest54.dll", +@"S:\t\dlls99\mstest55\bin\Debug\net8.0\mstest55.dll", +@"S:\t\dlls99\mstest56\bin\Debug\net8.0\mstest56.dll", +@"S:\t\dlls99\mstest57\bin\Debug\net8.0\mstest57.dll", +@"S:\t\dlls99\mstest58\bin\Debug\net8.0\mstest58.dll", +@"S:\t\dlls99\mstest59\bin\Debug\net8.0\mstest59.dll", +@"S:\t\dlls99\mstest6\bin\Debug\net8.0\mstest6.dll", +@"S:\t\dlls99\mstest60\bin\Debug\net8.0\mstest60.dll", +@"S:\t\dlls99\mstest61\bin\Debug\net8.0\mstest61.dll", +@"S:\t\dlls99\mstest62\bin\Debug\net8.0\mstest62.dll", +@"S:\t\dlls99\mstest63\bin\Debug\net8.0\mstest63.dll", +@"S:\t\dlls99\mstest64\bin\Debug\net8.0\mstest64.dll", +@"S:\t\dlls99\mstest65\bin\Debug\net8.0\mstest65.dll", +@"S:\t\dlls99\mstest66\bin\Debug\net8.0\mstest66.dll", +@"S:\t\dlls99\mstest67\bin\Debug\net8.0\mstest67.dll", +@"S:\t\dlls99\mstest68\bin\Debug\net8.0\mstest68.dll", +@"S:\t\dlls99\mstest69\bin\Debug\net8.0\mstest69.dll", +@"S:\t\dlls99\mstest7\bin\Debug\net8.0\mstest7.dll", +@"S:\t\dlls99\mstest70\bin\Debug\net8.0\mstest70.dll", +@"S:\t\dlls99\mstest71\bin\Debug\net8.0\mstest71.dll", +@"S:\t\dlls99\mstest72\bin\Debug\net8.0\mstest72.dll", +@"S:\t\dlls99\mstest73\bin\Debug\net8.0\mstest73.dll", +@"S:\t\dlls99\mstest74\bin\Debug\net8.0\mstest74.dll", +@"S:\t\dlls99\mstest75\bin\Debug\net8.0\mstest75.dll", +@"S:\t\dlls99\mstest76\bin\Debug\net8.0\mstest76.dll", +@"S:\t\dlls99\mstest77\bin\Debug\net8.0\mstest77.dll", +@"S:\t\dlls99\mstest78\bin\Debug\net8.0\mstest78.dll", +@"S:\t\dlls99\mstest79\bin\Debug\net8.0\mstest79.dll", +@"S:\t\dlls99\mstest8\bin\Debug\net8.0\mstest8.dll", +@"S:\t\dlls99\mstest80\bin\Debug\net8.0\mstest80.dll", +@"S:\t\dlls99\mstest81\bin\Debug\net8.0\mstest81.dll", +@"S:\t\dlls99\mstest82\bin\Debug\net8.0\mstest82.dll", +@"S:\t\dlls99\mstest83\bin\Debug\net8.0\mstest83.dll", +@"S:\t\dlls99\mstest84\bin\Debug\net8.0\mstest84.dll", +@"S:\t\dlls99\mstest85\bin\Debug\net8.0\mstest85.dll", +@"S:\t\dlls99\mstest86\bin\Debug\net8.0\mstest86.dll", +@"S:\t\dlls99\mstest87\bin\Debug\net8.0\mstest87.dll", +@"S:\t\dlls99\mstest88\bin\Debug\net8.0\mstest88.dll", +@"S:\t\dlls99\mstest89\bin\Debug\net8.0\mstest89.dll", +@"S:\t\dlls99\mstest9\bin\Debug\net8.0\mstest9.dll", +@"S:\t\dlls99\mstest90\bin\Debug\net8.0\mstest90.dll", +@"S:\t\dlls99\mstest91\bin\Debug\net8.0\mstest91.dll", +@"S:\t\dlls99\mstest92\bin\Debug\net8.0\mstest92.dll", +@"S:\t\dlls99\mstest93\bin\Debug\net8.0\mstest93.dll", +@"S:\t\dlls99\mstest94\bin\Debug\net8.0\mstest94.dll", +@"S:\t\dlls99\mstest95\bin\Debug\net8.0\mstest95.dll", +@"S:\t\dlls99\mstest96\bin\Debug\net8.0\mstest96.dll", +@"S:\t\dlls99\mstest97\bin\Debug\net8.0\mstest97.dll", +@"S:\t\dlls99\mstest98\bin\Debug\net8.0\mstest98.dll", +@"S:\t\dlls99\mstest99\bin\Debug\net8.0\mstest99.dll" }; - //// Console mode - //// Uncomment if providing command line parameters is easier for you - //// than converting them to settings, or when you debug command line scenario specifically. - //var settingsFile = Path.GetTempFileName(); - //try - //{ - // File.WriteAllText(settingsFile, sourceSettings); - // var processStartInfo = new ProcessStartInfo - // { - // FileName = console, - // Arguments = $"{string.Join(" ", sources)} --settings:{settingsFile} --listtests", - // UseShellExecute = false, - // }; - // EnvironmentVariables.Variables.ToList().ForEach(processStartInfo.Environment.Add); - // var process = Process.Start(processStartInfo); - // process.WaitForExit(); - // if (process.ExitCode != 0) - // { - // throw new Exception($"Process failed with {process.ExitCode}"); - // } - //} - //finally - //{ - // try { File.Delete(settingsFile); } catch { } - //} - - // design mode - var detailedOutput = true; - var consoleOptions = new ConsoleParameters + // Console mode + // Uncomment if providing command line parameters is easier for you + // than converting them to settings, or when you debug command line scenario specifically. + var settingsFile = Path.GetTempFileName(); + try { - EnvironmentVariables = EnvironmentVariables.Variables, - // LogFilePath = Path.Combine(here, "logs", "log.txt"), - // TraceLevel = TraceLevel.Verbose, - }; - var options = new TestPlatformOptions + File.WriteAllText(settingsFile, sourceSettings); + var processStartInfo = new ProcessStartInfo + { + FileName = console, + Arguments = $"{string.Join(" ", sources)} --settings:{settingsFile}", + UseShellExecute = false, + }; + EnvironmentVariables.Variables.ToList().ForEach(processStartInfo.Environment.Add); + var process = Process.Start(processStartInfo); + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception($"Process failed with {process.ExitCode}"); + } + } + finally { - CollectMetrics = true, - }; - var r = new VsTestConsoleWrapper(console, consoleOptions); - var sessionHandler = new TestSessionHandler(); -#pragma warning disable CS0618 // Type or member is obsolete - //// TestSessions - // r.StartTestSession(sources, sourceSettings, sessionHandler); -#pragma warning restore CS0618 // Type or member is obsolete - var discoveryHandler = new PlaygroundTestDiscoveryHandler(detailedOutput); - var sw = Stopwatch.StartNew(); - // Discovery - r.DiscoverTests(sources, sourceSettings, options, sessionHandler.TestSessionInfo, discoveryHandler); - var discoveryDuration = sw.ElapsedMilliseconds; - Console.WriteLine($"Discovery done in {discoveryDuration} ms"); - sw.Restart(); - // Run with test cases and custom testhost launcher - //r.RunTestsWithCustomTestHost(discoveryHandler.TestCases, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput), new DebuggerTestHostLauncher()); - //// Run with test cases and without custom testhost launcher - r.RunTests(discoveryHandler.TestCases, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput)); - //// Run with sources and custom testhost launcher and debugging - //r.RunTestsWithCustomTestHost(sources, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput), new DebuggerTestHostLauncher()); - //// Run with sources - //r.RunTests(sources, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput)); - var rd = sw.ElapsedMilliseconds; - Console.WriteLine($"Discovery: {discoveryDuration} ms, Run: {rd} ms, Total: {discoveryDuration + rd} ms"); - // Console.WriteLine($"Settings:\n{sourceSettings}"); + try { File.Delete(settingsFile); } catch { } + } } public class PlaygroundTestDiscoveryHandler : ITestDiscoveryEventsHandler, ITestDiscoveryEventsHandler2 diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs index f61c535771..ccbaa0d659 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs @@ -5,10 +5,12 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel; using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; @@ -63,6 +65,8 @@ public ParallelOperationManager(Func !s.HasWork); OccupiedSlotCount = _managerSlots.Count - AvailableSlotCount; + + if (EqtTrace.IsVerboseEnabled) + { + EqtTrace.Verbose($"ParallelOperationManager.SetOccupiedSlotCount: Setting slot counts AvailableSlotCount = {AvailableSlotCount}, OccupiedSlotCount = {OccupiedSlotCount}."); + EqtTrace.Verbose($"Occupied slots:\n{(string.Join("\n", _managerSlots.Where(s => s.HasWork).Select((slot) => $"{slot.Index}: {GetSourcesForSlotExpensive(slot)}").ToArray()))}"); + + } } public void StartWork( @@ -91,6 +102,7 @@ public void StartWork( _initializeWorkload = initializeWorkload ?? throw new ArgumentNullException(nameof(initializeWorkload)); _runWorkload = runWorkload ?? throw new ArgumentNullException(nameof(runWorkload)); + EqtTrace.Verbose($"ParallelOperationManager.StartWork: Starting adding {workloads.Count} workloads."); _workloads.AddRange(workloads); ClearSlots(acceptMoreWork: true); @@ -123,7 +135,10 @@ private bool RunWorkInParallel() // so when it is allowed to enter it will try to add more work, but we already cancelled, // so we should not start more work. if (!_acceptMoreWork) + { + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: We don't accept more work, returning false."); return false; + } // We grab all empty slots. var availableSlots = _managerSlots.Where(slot => !slot.HasWork).ToImmutableArray(); @@ -136,11 +151,10 @@ private bool RunWorkInParallel() var workloadsToAdd = availableWorkloads.Take(amount).ToImmutableArray(); // We associate each workload to a slot, if we reached the max parallel - // level, then we will run only initalize step of the given workload. + // level, then we will run only initialize step of the given workload. for (int i = 0; i < amount; i++) { var slot = availableSlots[i]; - slot.HasWork = true; var workload = workloadsToAdd[i]; slot.ShouldPreStart = occupiedSlots + i + 1 > MaxParallelLevel; @@ -152,6 +166,13 @@ private bool RunWorkInParallel() slot.Work = workload.Work; _workloads.Remove(workload); + + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Adding 1 workload to slot, remaining workloads {_workloads.Count}."); + + // This must be set last, every loop below looks at this property, + // and they can do so from a different thread. So if we mark it as HasWork before actually assigning the work + // we can pick up the slot, but it has no associated work yet. + slot.HasWork = true; } slots = _managerSlots.ToArray(); @@ -172,12 +193,16 @@ private bool RunWorkInParallel() { startedWork++; slot.IsRunning = true; - EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Running on pre-started host: {(DateTime.Now.TimeOfDay - slot.PreStartTime).TotalMilliseconds}ms {slot.InitTask?.Status}"); + if (EqtTrace.IsVerboseEnabled) + { + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Running on pre-started host for work (source) {GetSourcesForSlotExpensive(slot)}: {(DateTime.Now.TimeOfDay - slot.PreStartTime).TotalMilliseconds}ms {slot.InitTask?.Status}"); + } _runWorkload(slot.Manager!, slot.EventHandler!, slot.Work!, slot.IsPreStarted, slot.InitTask); // We already started as many as we were allowed, jump out; if (startedWork == MaxParallelLevel) { + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: We started {startedWork} work items, which is the max parallel level. Won't start more work."); break; } } @@ -194,7 +219,15 @@ private bool RunWorkInParallel() { startedWork++; slot.IsRunning = true; - EqtTrace.Verbose("ParallelOperationManager.RunWorkInParallel: Started work on a host."); + if (EqtTrace.IsVerboseEnabled) + { + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Started host in slot number {slot.Index} for work (source): {GetSourcesForSlotExpensive(slot)}."); + if (string.IsNullOrWhiteSpace(GetSourcesForSlotExpensive(slot))) + { + Thread.Sleep(100); + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Started host AGAIN in slot number {slot.Index} for work (source): {GetSourcesForSlotExpensive(slot)}."); + } + } _runWorkload(slot.Manager!, slot.EventHandler!, slot.Work!, slot.IsPreStarted, slot.InitTask); } } @@ -202,6 +235,7 @@ private bool RunWorkInParallel() // We already started as many as we were allowed, jump out; if (startedWork == MaxParallelLevel) { + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: We started {startedWork} work items, which is the max parallel level. Won't start more work."); break; } } @@ -215,14 +249,19 @@ private bool RunWorkInParallel() preStartedWork++; slot.PreStartTime = DateTime.Now.TimeOfDay; slot.IsPreStarted = true; - EqtTrace.Verbose("ParallelOperationManager.RunWorkInParallel: Pre-starting a host."); + if (EqtTrace.IsVerboseEnabled) + { + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Pre-starting a host for work (source): {GetSourcesForSlotExpensive(slot)}."); + } slot.InitTask = _initializeWorkload!(slot.Manager!, slot.EventHandler!, slot.Work!); } } // Return true when we started more work. Or false, when there was nothing more to do. // This will propagate to handling of partial discovery or partial run. - return preStartedWork + startedWork > 0; + var weAddedMoreWork = preStartedWork + startedWork > 0; + EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: We started {preStartedWork + startedWork} work items in here, returning {weAddedMoreWork}."); + return weAddedMoreWork; } public bool RunNextWork(TManager completedManager) @@ -258,6 +297,10 @@ private void ClearCompletedSlot(TManager completedManager) throw new InvalidOperationException("The provided manager was found in multiple slots."); } + if (EqtTrace.IsVerboseEnabled) + { + EqtTrace.Verbose($"ParallelOperationManager.ClearCompletedSlot: Clearing slot number {completedSlot[0].Index} with work (source): {GetSourcesForSlotExpensive(completedSlot[0])}."); + } var slot = completedSlot[0]; slot.PreStartTime = TimeSpan.Zero; slot.Work = default(TWorkload); @@ -273,8 +316,14 @@ private void ClearCompletedSlot(TManager completedManager) } } + private static string GetSourcesForSlotExpensive(ParallelOperationManager.Slot slot) + { + return string.Join(", ", (slot.Work as DiscoveryCriteria)?.Sources ?? (slot.Work as TestRunCriteria)?.Sources ?? Array.Empty()); + } + public void DoActionOnAllManagers(Action action, bool doActionsInParallel = false) { + EqtTrace.Verbose($"ParallelOperationManager.DoActionOnAllManagers: Calling an action on all managers."); // We don't need to lock here, we just grab the current list of // slots that are occupied (have managers) and run action on each one of them. var managers = _managerSlots.Where(slot => slot.HasWork).Select(slot => slot.Manager).ToImmutableArray(); @@ -320,11 +369,13 @@ private static void DoManagerAction(Action action) internal void StopAllManagers() { + EqtTrace.Verbose($"ParallelOperationManager.StopAllManagers: Stopping all managers."); ClearSlots(acceptMoreWork: false); } public void Dispose() { + EqtTrace.Verbose($"ParallelOperationManager.Dispose: Disposing all managers."); ClearSlots(acceptMoreWork: false); } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs index bb2179e792..7b871e4e91 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyDiscoveryManager.cs @@ -287,6 +287,12 @@ private void DiscoverTestsOnConcurrentManager( bool initialized, Task? task) { + // If we do the scheduling incorrectly this will get null. It should not happen, but it has happened before. + if (discoveryCriteria == null) + { + throw new ArgumentNullException(nameof(discoveryCriteria)); + } + // Kick off another discovery task for the next source Task.Run(() => { diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs index ba99581863..b586cfe934 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelProxyExecutionManager.cs @@ -159,11 +159,12 @@ public bool HandlePartialRunComplete( ? _runCompletedClients == _runStartedClients : _runCompletedClients == _availableWorkloads; - EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: Total completed clients = {0}, Run complete = {1}, Run canceled: {2}.", _runCompletedClients, allRunsCompleted, testRunCompleteArgs.IsCanceled); + EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: Total workloads = {0}, Total started clients = {1} Total completed clients = {2}, Run complete = {3}, Run canceled: {4}.", _availableWorkloads, _runStartedClients, _runCompletedClients, allRunsCompleted, testRunCompleteArgs.IsCanceled); } if (allRunsCompleted) { + EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: All runs completed stopping all managers."); _parallelOperationManager.StopAllManagers(); return true; } @@ -185,8 +186,13 @@ public bool HandlePartialRunComplete( // { // return true; // } + EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: Not cancelled or aborted, running next work."); var _ = _parallelOperationManager.RunNextWork(proxyExecutionManager); } + else + { + EqtTrace.Verbose("ParallelProxyExecutionManager: HandlePartialRunComplete: Cancelled or aborted, not running next work."); + } return false; } @@ -403,7 +409,7 @@ private Task PrepareTestRunOnConcurrentManager(IProxyExecutionManager proxyExecu // clients to be done running their workloads when aborting/cancelling and that doesn't // happen with an initialized workload that is never run. // - // Interlocked.Increment(ref _runStartedClients); + // Interlocked.Increment(ref _runStartedClients); <- BUG: Is this a bug waiting to happen for pre-started hosts? proxyExecutionManager.InitializeTestRun(testRunCriteria, eventHandler); }); } @@ -421,54 +427,60 @@ private void StartTestRunOnConcurrentManager( bool initialized, Task? initTask) { - if (testRunCriteria != null) + // If we do the scheduling incorrectly this will get null. It should not happen, but it has happened before. + if (testRunCriteria == null) { - Task.Run(() => - { - if (!initialized) - { - if (!proxyExecutionManager.IsInitialized) - { - proxyExecutionManager.Initialize(_skipDefaultAdapters); - } + throw new ArgumentNullException(nameof(testRunCriteria)); + } - Interlocked.Increment(ref _runStartedClients); - proxyExecutionManager.InitializeTestRun(testRunCriteria, eventHandler); - } - else + Task.Run(() => + { + if (!initialized) + { + if (!proxyExecutionManager.IsInitialized) { - initTask!.Wait(); + EqtTrace.Verbose("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Initializing uninitialized client. Started clients: " + _runStartedClients); + proxyExecutionManager.Initialize(_skipDefaultAdapters); } - EqtTrace.Verbose("ParallelProxyExecutionManager: Execution started. Started clients: " + _runStartedClients); + EqtTrace.Verbose("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Initializing test run. Started clients: " + _runStartedClients); + Interlocked.Increment(ref _runStartedClients); + proxyExecutionManager.InitializeTestRun(testRunCriteria, eventHandler); + } + else + { + EqtTrace.Verbose("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Waiting for pre-initialized client to finish initialization. Started clients: " + _runStartedClients); + initTask!.Wait(); + EqtTrace.Verbose("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Pre-initialized client finished initialization. Started clients: " + _runStartedClients); + } - proxyExecutionManager.StartTestRun(testRunCriteria, eventHandler); - }) - .ContinueWith(t => - { - // Just in case, the actual execution couldn't start for an instance. Ensure that - // we call execution complete since we have already fetched a source. Otherwise - // execution will not terminate - EqtTrace.Error("ParallelProxyExecutionManager: Failed to trigger execution. Exception: " + t.Exception); - - var handler = eventHandler; - var exceptionToString = t.Exception?.ToString(); - var testMessagePayload = new TestMessagePayload { MessageLevel = TestMessageLevel.Error, Message = exceptionToString }; - handler.HandleRawMessage(_dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload)); - handler.HandleLogMessage(TestMessageLevel.Error, exceptionToString); - - // Send a run complete to caller. Similar logic is also used in ProxyExecutionManager.StartTestRun - // Differences: - // Aborted is sent to allow the current execution manager replaced with another instance - // Ensure that the test run aggregator in parallel run events handler doesn't add these statistics - // (since the test run didn't even start) - var completeArgs = new TestRunCompleteEventArgs(null, false, true, null, new Collection(), new Collection(), TimeSpan.Zero); - handler.HandleTestRunComplete(completeArgs, null, null, null); - }, - TaskContinuationOptions.OnlyOnFaulted); - } + EqtTrace.Verbose("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Execution starting. Started clients: " + _runStartedClients); - EqtTrace.Verbose("ProxyParallelExecutionManager: No sources available for execution."); + proxyExecutionManager.StartTestRun(testRunCriteria, eventHandler); + EqtTrace.Verbose("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Execution started. Started clients: " + _runStartedClients); + }) + .ContinueWith(t => + { + // Just in case, the actual execution couldn't start for an instance. Ensure that + // we call execution complete since we have already fetched a source. Otherwise + // execution will not terminate + EqtTrace.Error("ParallelProxyExecutionManager.StartTestRunOnConcurrentManager(continuation): Failed to trigger execution. Exception: " + t.Exception); + + var handler = eventHandler; + var exceptionToString = t.Exception?.ToString(); + var testMessagePayload = new TestMessagePayload { MessageLevel = TestMessageLevel.Error, Message = exceptionToString }; + handler.HandleRawMessage(_dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload)); + handler.HandleLogMessage(TestMessageLevel.Error, exceptionToString); + + // Send a run complete to caller. Similar logic is also used in ProxyExecutionManager.StartTestRun + // Differences: + // Aborted is sent to allow the current execution manager replaced with another instance + // Ensure that the test run aggregator in parallel run events handler doesn't add these statistics + // (since the test run didn't even start) + var completeArgs = new TestRunCompleteEventArgs(null, false, true, null, new Collection(), new Collection(), TimeSpan.Zero); + handler.HandleTestRunComplete(completeArgs, null, null, null); + }, + TaskContinuationOptions.OnlyOnFaulted); } public void InitializeTestRun(TestRunCriteria testRunCriteria, IInternalTestRunEventsHandler eventHandler) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelRunEventsHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelRunEventsHandler.cs index 1ea36cfd62..9890cf5586 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelRunEventsHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelRunEventsHandler.cs @@ -66,10 +66,12 @@ public virtual void HandleTestRunComplete( ICollection? runContextAttachments, ICollection? executorUris) { + EqtTrace.Verbose($"ParallelRunEventsHandler.HandleTestRunComplete: Handling a run completion, this can be either one part of parallel run completing, or the whole parallel run completing."); var parallelRunComplete = HandleSingleTestRunComplete(testRunCompleteArgs, lastChunkArgs, runContextAttachments, executorUris); if (parallelRunComplete) { + EqtTrace.Verbose($"ParallelRunEventsHandler.HandleTestRunComplete: Whole parallel run completed."); var completedArgs = new TestRunCompleteEventArgs(_runDataAggregator.GetAggregatedRunStats(), _runDataAggregator.IsCanceled, _runDataAggregator.IsAborted, @@ -96,6 +98,10 @@ public virtual void HandleTestRunComplete( HandleParallelTestRunComplete(completedArgs); } + else + { + EqtTrace.Verbose($"ParallelRunEventsHandler.HandleTestRunComplete: Single part of parallel run completed, but whole run is not complete yet."); + } } protected bool HandleSingleTestRunComplete(TestRunCompleteEventArgs testRunCompleteArgs, From 41f1bd2856d5973f9fab5af278fd00b6c6ee78d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 31 Jul 2023 15:06:49 +0200 Subject: [PATCH 2/4] Revert playground --- playground/TestPlatform.Playground/Program.cs | 232 ++++++++---------- 1 file changed, 107 insertions(+), 125 deletions(-) diff --git a/playground/TestPlatform.Playground/Program.cs b/playground/TestPlatform.Playground/Program.cs index aac04753aa..875026c24e 100644 --- a/playground/TestPlatform.Playground/Program.cs +++ b/playground/TestPlatform.Playground/Program.cs @@ -10,7 +10,7 @@ using System.Reflection; using System.Threading; -// using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; +using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; @@ -35,6 +35,7 @@ static void Main() var thisAssemblyPath = Assembly.GetEntryAssembly()!.Location; var here = Path.GetDirectoryName(thisAssemblyPath)!; + var playground = Path.GetFullPath(Path.Combine(here, "..", "..", "..", "..")); var console = Path.Combine(here, "vstest.console", "vstest.console.exe"); @@ -42,139 +43,120 @@ static void Main() - 0 - + + + + + + + + + False + True + + + 999999 + + + + + + + + + + """; var sources = new[] { - @"S:\t\dlls99\mstest1\bin\Debug\net8.0\mstest1.dll", -@"S:\t\dlls99\mstest10\bin\Debug\net8.0\mstest10.dll", -@"S:\t\dlls99\mstest11\bin\Debug\net8.0\mstest11.dll", -@"S:\t\dlls99\mstest12\bin\Debug\net8.0\mstest12.dll", -@"S:\t\dlls99\mstest13\bin\Debug\net8.0\mstest13.dll", -@"S:\t\dlls99\mstest14\bin\Debug\net8.0\mstest14.dll", -@"S:\t\dlls99\mstest15\bin\Debug\net8.0\mstest15.dll", -@"S:\t\dlls99\mstest16\bin\Debug\net8.0\mstest16.dll", -@"S:\t\dlls99\mstest17\bin\Debug\net8.0\mstest17.dll", -@"S:\t\dlls99\mstest18\bin\Debug\net8.0\mstest18.dll", -@"S:\t\dlls99\mstest19\bin\Debug\net8.0\mstest19.dll", -@"S:\t\dlls99\mstest2\bin\Debug\net8.0\mstest2.dll", -@"S:\t\dlls99\mstest20\bin\Debug\net8.0\mstest20.dll", -@"S:\t\dlls99\mstest21\bin\Debug\net8.0\mstest21.dll", -@"S:\t\dlls99\mstest22\bin\Debug\net8.0\mstest22.dll", -@"S:\t\dlls99\mstest23\bin\Debug\net8.0\mstest23.dll", -@"S:\t\dlls99\mstest24\bin\Debug\net8.0\mstest24.dll", -@"S:\t\dlls99\mstest25\bin\Debug\net8.0\mstest25.dll", -@"S:\t\dlls99\mstest26\bin\Debug\net8.0\mstest26.dll", -@"S:\t\dlls99\mstest27\bin\Debug\net8.0\mstest27.dll", -@"S:\t\dlls99\mstest28\bin\Debug\net8.0\mstest28.dll", -@"S:\t\dlls99\mstest29\bin\Debug\net8.0\mstest29.dll", -@"S:\t\dlls99\mstest3\bin\Debug\net8.0\mstest3.dll", -@"S:\t\dlls99\mstest30\bin\Debug\net8.0\mstest30.dll", -@"S:\t\dlls99\mstest31\bin\Debug\net8.0\mstest31.dll", -@"S:\t\dlls99\mstest32\bin\Debug\net8.0\mstest32.dll", -@"S:\t\dlls99\mstest33\bin\Debug\net8.0\mstest33.dll", -@"S:\t\dlls99\mstest34\bin\Debug\net8.0\mstest34.dll", -@"S:\t\dlls99\mstest35\bin\Debug\net8.0\mstest35.dll", -@"S:\t\dlls99\mstest36\bin\Debug\net8.0\mstest36.dll", -@"S:\t\dlls99\mstest37\bin\Debug\net8.0\mstest37.dll", -@"S:\t\dlls99\mstest38\bin\Debug\net8.0\mstest38.dll", -@"S:\t\dlls99\mstest39\bin\Debug\net8.0\mstest39.dll", -@"S:\t\dlls99\mstest4\bin\Debug\net8.0\mstest4.dll", -@"S:\t\dlls99\mstest40\bin\Debug\net8.0\mstest40.dll", -@"S:\t\dlls99\mstest41\bin\Debug\net8.0\mstest41.dll", -@"S:\t\dlls99\mstest42\bin\Debug\net8.0\mstest42.dll", -@"S:\t\dlls99\mstest43\bin\Debug\net8.0\mstest43.dll", -@"S:\t\dlls99\mstest44\bin\Debug\net8.0\mstest44.dll", -@"S:\t\dlls99\mstest45\bin\Debug\net8.0\mstest45.dll", -@"S:\t\dlls99\mstest46\bin\Debug\net8.0\mstest46.dll", -@"S:\t\dlls99\mstest47\bin\Debug\net8.0\mstest47.dll", -@"S:\t\dlls99\mstest48\bin\Debug\net8.0\mstest48.dll", -@"S:\t\dlls99\mstest49\bin\Debug\net8.0\mstest49.dll", -@"S:\t\dlls99\mstest5\bin\Debug\net8.0\mstest5.dll", -@"S:\t\dlls99\mstest50\bin\Debug\net8.0\mstest50.dll", -@"S:\t\dlls99\mstest51\bin\Debug\net8.0\mstest51.dll", -@"S:\t\dlls99\mstest52\bin\Debug\net8.0\mstest52.dll", -@"S:\t\dlls99\mstest53\bin\Debug\net8.0\mstest53.dll", -@"S:\t\dlls99\mstest54\bin\Debug\net8.0\mstest54.dll", -@"S:\t\dlls99\mstest55\bin\Debug\net8.0\mstest55.dll", -@"S:\t\dlls99\mstest56\bin\Debug\net8.0\mstest56.dll", -@"S:\t\dlls99\mstest57\bin\Debug\net8.0\mstest57.dll", -@"S:\t\dlls99\mstest58\bin\Debug\net8.0\mstest58.dll", -@"S:\t\dlls99\mstest59\bin\Debug\net8.0\mstest59.dll", -@"S:\t\dlls99\mstest6\bin\Debug\net8.0\mstest6.dll", -@"S:\t\dlls99\mstest60\bin\Debug\net8.0\mstest60.dll", -@"S:\t\dlls99\mstest61\bin\Debug\net8.0\mstest61.dll", -@"S:\t\dlls99\mstest62\bin\Debug\net8.0\mstest62.dll", -@"S:\t\dlls99\mstest63\bin\Debug\net8.0\mstest63.dll", -@"S:\t\dlls99\mstest64\bin\Debug\net8.0\mstest64.dll", -@"S:\t\dlls99\mstest65\bin\Debug\net8.0\mstest65.dll", -@"S:\t\dlls99\mstest66\bin\Debug\net8.0\mstest66.dll", -@"S:\t\dlls99\mstest67\bin\Debug\net8.0\mstest67.dll", -@"S:\t\dlls99\mstest68\bin\Debug\net8.0\mstest68.dll", -@"S:\t\dlls99\mstest69\bin\Debug\net8.0\mstest69.dll", -@"S:\t\dlls99\mstest7\bin\Debug\net8.0\mstest7.dll", -@"S:\t\dlls99\mstest70\bin\Debug\net8.0\mstest70.dll", -@"S:\t\dlls99\mstest71\bin\Debug\net8.0\mstest71.dll", -@"S:\t\dlls99\mstest72\bin\Debug\net8.0\mstest72.dll", -@"S:\t\dlls99\mstest73\bin\Debug\net8.0\mstest73.dll", -@"S:\t\dlls99\mstest74\bin\Debug\net8.0\mstest74.dll", -@"S:\t\dlls99\mstest75\bin\Debug\net8.0\mstest75.dll", -@"S:\t\dlls99\mstest76\bin\Debug\net8.0\mstest76.dll", -@"S:\t\dlls99\mstest77\bin\Debug\net8.0\mstest77.dll", -@"S:\t\dlls99\mstest78\bin\Debug\net8.0\mstest78.dll", -@"S:\t\dlls99\mstest79\bin\Debug\net8.0\mstest79.dll", -@"S:\t\dlls99\mstest8\bin\Debug\net8.0\mstest8.dll", -@"S:\t\dlls99\mstest80\bin\Debug\net8.0\mstest80.dll", -@"S:\t\dlls99\mstest81\bin\Debug\net8.0\mstest81.dll", -@"S:\t\dlls99\mstest82\bin\Debug\net8.0\mstest82.dll", -@"S:\t\dlls99\mstest83\bin\Debug\net8.0\mstest83.dll", -@"S:\t\dlls99\mstest84\bin\Debug\net8.0\mstest84.dll", -@"S:\t\dlls99\mstest85\bin\Debug\net8.0\mstest85.dll", -@"S:\t\dlls99\mstest86\bin\Debug\net8.0\mstest86.dll", -@"S:\t\dlls99\mstest87\bin\Debug\net8.0\mstest87.dll", -@"S:\t\dlls99\mstest88\bin\Debug\net8.0\mstest88.dll", -@"S:\t\dlls99\mstest89\bin\Debug\net8.0\mstest89.dll", -@"S:\t\dlls99\mstest9\bin\Debug\net8.0\mstest9.dll", -@"S:\t\dlls99\mstest90\bin\Debug\net8.0\mstest90.dll", -@"S:\t\dlls99\mstest91\bin\Debug\net8.0\mstest91.dll", -@"S:\t\dlls99\mstest92\bin\Debug\net8.0\mstest92.dll", -@"S:\t\dlls99\mstest93\bin\Debug\net8.0\mstest93.dll", -@"S:\t\dlls99\mstest94\bin\Debug\net8.0\mstest94.dll", -@"S:\t\dlls99\mstest95\bin\Debug\net8.0\mstest95.dll", -@"S:\t\dlls99\mstest96\bin\Debug\net8.0\mstest96.dll", -@"S:\t\dlls99\mstest97\bin\Debug\net8.0\mstest97.dll", -@"S:\t\dlls99\mstest98\bin\Debug\net8.0\mstest98.dll", -@"S:\t\dlls99\mstest99\bin\Debug\net8.0\mstest99.dll" + Path.Combine(playground, "bin", "MSTest1", "Debug", "net472", "MSTest1.dll"), + Path.Combine(playground, "bin", "MSTest2", "Debug", "net472", "MSTest2.dll"), + // The built in .NET projects don't now work right now in Playground, there is some conflict with Arcade. + // But if you create one outside of Playground it will work. + //Path.Combine(playground, "bin", "MSTest1", "Debug", "net7.0", "MSTest1.dll"), }; - // Console mode - // Uncomment if providing command line parameters is easier for you - // than converting them to settings, or when you debug command line scenario specifically. - var settingsFile = Path.GetTempFileName(); - try + //// Console mode + //// Uncomment if providing command line parameters is easier for you + //// than converting them to settings, or when you debug command line scenario specifically. + //var settingsFile = Path.GetTempFileName(); + //try + //{ + // File.WriteAllText(settingsFile, sourceSettings); + // var processStartInfo = new ProcessStartInfo + // { + // FileName = console, + // Arguments = $"{string.Join(" ", sources)} --settings:{settingsFile} --listtests", + // UseShellExecute = false, + // }; + // EnvironmentVariables.Variables.ToList().ForEach(processStartInfo.Environment.Add); + // var process = Process.Start(processStartInfo); + // process.WaitForExit(); + // if (process.ExitCode != 0) + // { + // throw new Exception($"Process failed with {process.ExitCode}"); + // } + //} + //finally + //{ + // try { File.Delete(settingsFile); } catch { } + //} + + // design mode + var detailedOutput = true; + var consoleOptions = new ConsoleParameters { - File.WriteAllText(settingsFile, sourceSettings); - var processStartInfo = new ProcessStartInfo - { - FileName = console, - Arguments = $"{string.Join(" ", sources)} --settings:{settingsFile}", - UseShellExecute = false, - }; - EnvironmentVariables.Variables.ToList().ForEach(processStartInfo.Environment.Add); - var process = Process.Start(processStartInfo); - process.WaitForExit(); - if (process.ExitCode != 0) - { - throw new Exception($"Process failed with {process.ExitCode}"); - } - } - finally + EnvironmentVariables = EnvironmentVariables.Variables, + // LogFilePath = Path.Combine(here, "logs", "log.txt"), + // TraceLevel = TraceLevel.Verbose, + }; + var options = new TestPlatformOptions { - try { File.Delete(settingsFile); } catch { } - } + CollectMetrics = true, + }; + var r = new VsTestConsoleWrapper(console, consoleOptions); + var sessionHandler = new TestSessionHandler(); +#pragma warning disable CS0618 // Type or member is obsolete + //// TestSessions + // r.StartTestSession(sources, sourceSettings, sessionHandler); +#pragma warning restore CS0618 // Type or member is obsolete + var discoveryHandler = new PlaygroundTestDiscoveryHandler(detailedOutput); + var sw = Stopwatch.StartNew(); + // Discovery + r.DiscoverTests(sources, sourceSettings, options, sessionHandler.TestSessionInfo, discoveryHandler); + var discoveryDuration = sw.ElapsedMilliseconds; + Console.WriteLine($"Discovery done in {discoveryDuration} ms"); + sw.Restart(); + // Run with test cases and custom testhost launcher + //r.RunTestsWithCustomTestHost(discoveryHandler.TestCases, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput), new DebuggerTestHostLauncher()); + //// Run with test cases and without custom testhost launcher + r.RunTests(discoveryHandler.TestCases, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput)); + //// Run with sources and custom testhost launcher and debugging + //r.RunTestsWithCustomTestHost(sources, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput), new DebuggerTestHostLauncher()); + //// Run with sources + //r.RunTests(sources, sourceSettings, options, sessionHandler.TestSessionInfo, new TestRunHandler(detailedOutput)); + var rd = sw.ElapsedMilliseconds; + Console.WriteLine($"Discovery: {discoveryDuration} ms, Run: {rd} ms, Total: {discoveryDuration + rd} ms"); + // Console.WriteLine($"Settings:\n{sourceSettings}"); } public class PlaygroundTestDiscoveryHandler : ITestDiscoveryEventsHandler, ITestDiscoveryEventsHandler2 From 43df4e4b2cec05056a4524ccae176367da3b3657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 31 Jul 2023 15:08:38 +0200 Subject: [PATCH 3/4] Revert delay --- .../Client/Parallel/ParallelOperationManager.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs index ccbaa0d659..f7f5bd6f65 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs @@ -222,11 +222,6 @@ private bool RunWorkInParallel() if (EqtTrace.IsVerboseEnabled) { EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Started host in slot number {slot.Index} for work (source): {GetSourcesForSlotExpensive(slot)}."); - if (string.IsNullOrWhiteSpace(GetSourcesForSlotExpensive(slot))) - { - Thread.Sleep(100); - EqtTrace.Verbose($"ParallelOperationManager.RunWorkInParallel: Started host AGAIN in slot number {slot.Index} for work (source): {GetSourcesForSlotExpensive(slot)}."); - } } _runWorkload(slot.Manager!, slot.EventHandler!, slot.Work!, slot.IsPreStarted, slot.InitTask); } From d67deb94a5bc1b28f5ac8b4aee56dab8225c8186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Mon, 31 Jul 2023 15:26:47 +0200 Subject: [PATCH 4/4] Remove extra using --- .../Client/Parallel/ParallelOperationManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs index f7f5bd6f65..df2ef9133a 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/Parallel/ParallelOperationManager.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel;