--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using Xunit.Abstractions;
+using System.Threading;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using EventPipe.UnitTests.Common;
+using Microsoft.Diagnostics.Tracing;
+
+namespace EventPipe.UnitTests.ContentionValidation
+{
+
+ public class TestClass{
+ public int a;
+ public void DoSomething(TestClass obj)
+ {
+ lock(obj)
+ {
+ obj.a = 3;
+ Thread.Sleep(100);
+ }
+ }
+ }
+ public class ProviderTests
+ {
+ private readonly ITestOutputHelper output;
+
+ public ProviderTests(ITestOutputHelper outputHelper)
+ {
+ output = outputHelper;
+ }
+
+ [Fact]
+ public async void Contention_ProducesEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ //ContentionKeyword (0x4000): 0b100_0000_0000_0000
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b100_0000_0000_0000, EventLevel.Informational)
+ };
+
+ Action _eventGeneratingAction = () =>
+ {
+ for (int i = 0; i < 50; i++)
+ {
+ if (i % 10 == 0)
+ Logger.logger.Log($"Thread lock occured {i} times...");
+ var myobject = new TestClass();
+ Thread thread1 = new Thread(new ThreadStart(() => myobject.DoSomething(myobject)));
+ Thread thread2 = new Thread(new ThreadStart(() => myobject.DoSomething(myobject)));
+ thread1.Start();
+ thread2.Start();
+ thread1.Join();
+ thread2.Join();
+ }
+ };
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int ContentionStartEvents = 0;
+ source.Clr.ContentionStart += (eventData) => ContentionStartEvents += 1;
+ int ContentionStopEvents = 0;
+ source.Clr.ContentionStop += (eventData) => ContentionStopEvents += 1;
+ return () => {
+ Logger.logger.Log("Event counts validation");
+ Logger.logger.Log("ContentionStartEvents: " + ContentionStartEvents);
+ Logger.logger.Log("ContentionStopEvents: " + ContentionStopEvents);
+ return ContentionStartEvents >= 50 && ContentionStopEvents >= 50 ? 100 : -1;
+ };
+ };
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using Xunit.Abstractions;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using EventPipe.UnitTests.Common;
+using Microsoft.Diagnostics.Tracing;
+using System.Threading;
+
+namespace EventPipe.UnitTests.GCEventsValidation
+{
+
+ public class TestClass
+ {
+ public int a;
+ public string b;
+
+ public TestClass()
+ {
+ a = 0;
+ b = "";
+ }
+ }
+ public class ProviderTests
+ {
+ private readonly ITestOutputHelper output;
+
+ public ProviderTests(ITestOutputHelper outputHelper)
+ {
+ output = outputHelper;
+ }
+
+ [Fact]
+ public async void GCCollect_ProducesEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntime", -1 },
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 },
+ { "Microsoft-DotNETCore-SampleProfiler", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ //GCKeyword (0x1): 0b1
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b1, EventLevel.Informational)
+ };
+
+ Action _eventGeneratingAction = () =>
+ {
+ for (int i = 0; i < 50; i++)
+ {
+ if (i % 10 == 0)
+ Logger.logger.Log($"Called GC.Collect() {i} times...");
+ TestClass testClass = new TestClass();
+ testClass = null;
+ GC.Collect();
+ }
+ };
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int GCStartEvents = 0;
+ int GCEndEvents = 0;
+ source.Clr.GCStart += (eventData) => GCStartEvents += 1;
+ source.Clr.GCStop += (eventData) => GCEndEvents += 1;
+
+ int GCRestartEEStartEvents = 0;
+ int GCRestartEEStopEvents = 0;
+ source.Clr.GCRestartEEStart += (eventData) => GCRestartEEStartEvents += 1;
+ source.Clr.GCRestartEEStop += (eventData) => GCRestartEEStopEvents += 1;
+
+ int GCSuspendEEEvents = 0;
+ int GCSuspendEEEndEvents = 0;
+ source.Clr.GCSuspendEEStart += (eventData) => GCSuspendEEEvents += 1;
+ source.Clr.GCSuspendEEStop += (eventData) => GCSuspendEEEndEvents += 1;
+
+ int GCHeapStatsEvents =0;
+ source.Clr.GCHeapStats += (eventData) => GCHeapStatsEvents +=1;
+
+ return () => {
+ Logger.logger.Log("Event counts validation");
+
+ Logger.logger.Log("GCStartEvents: " + GCStartEvents);
+ Logger.logger.Log("GCEndEvents: " + GCEndEvents);
+ bool GCStartStopResult = GCStartEvents >= 50 && GCEndEvents >= 50 && Math.Abs(GCStartEvents - GCEndEvents) <=2;
+ Logger.logger.Log("GCStartStopResult check: " + GCStartStopResult);
+
+ Logger.logger.Log("GCRestartEEStartEvents: " + GCRestartEEStartEvents);
+ Logger.logger.Log("GCRestartEEStopEvents: " + GCRestartEEStopEvents);
+ bool GCRestartEEStartStopResult = GCRestartEEStartEvents >= 50 && GCRestartEEStopEvents >= 50;
+ Logger.logger.Log("GCRestartEEStartStopResult check: " + GCRestartEEStartStopResult);
+
+ Logger.logger.Log("GCSuspendEEEvents: " + GCSuspendEEEvents);
+ Logger.logger.Log("GCSuspendEEEndEvents: " + GCSuspendEEEndEvents);
+ bool GCSuspendEEStartStopResult = GCSuspendEEEvents >= 50 && GCSuspendEEEndEvents >= 50;
+ Logger.logger.Log("GCSuspendEEStartStopResult check: " + GCSuspendEEStartStopResult);
+
+ Logger.logger.Log("GCHeapStatsEvents: " + GCHeapStatsEvents);
+ bool GCHeapStatsEventsResult = GCHeapStatsEvents >= 50 && GCHeapStatsEvents >= 50;
+ Logger.logger.Log("GCHeapStatsEventsResult check: " + GCHeapStatsEventsResult);
+
+ return GCStartStopResult && GCRestartEEStartStopResult && GCSuspendEEStartStopResult && GCHeapStatsEventsResult ? 100 : -1;
+ };
+ };
+
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+
+ [Fact]
+ public async void GCWaitForPendingFinalizers_ProducesEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntime", -1 },
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 },
+ { "Microsoft-DotNETCore-SampleProfiler", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ //GCKeyword (0x1): 0b1
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b1, EventLevel.Informational)
+ };
+
+ Action _eventGeneratingAction = () =>
+ {
+ for (int i = 0; i < 50; i++)
+ {
+ if (i % 10 == 0)
+ Logger.logger.Log($"Called GC.Collect() {i} times...");
+ TestClass testClass = new TestClass();
+ testClass = null;
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
+ };
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int GCFinalizersEndEvents = 0;
+ source.Clr.GCFinalizersStop += (eventData) => GCFinalizersEndEvents += 1;
+ int GCFinalizersStartEvents = 0;
+ source.Clr.GCFinalizersStart += (eventData) => GCFinalizersStartEvents += 1;
+ return () => {
+ Logger.logger.Log("Event counts validation");
+ Logger.logger.Log("GCFinalizersEndEvents: " + GCFinalizersEndEvents);
+ Logger.logger.Log("GCFinalizersStartEvents: " + GCFinalizersStartEvents);
+ return GCFinalizersEndEvents >= 50 && GCFinalizersStartEvents >= 50 ? 100 : -1;
+ };
+ };
+
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+
+ [Fact]
+ public async void GCCollect_ProducesVerboseEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntime", -1 },
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 },
+ { "Microsoft-DotNETCore-SampleProfiler", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ //GCKeyword (0x1): 0b1
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b1, EventLevel.Verbose)
+ };
+
+ Action _eventGeneratingAction = () =>
+ {
+ List<string> testList = new List<string>();
+ for(int i = 0; i < 100000000; i ++)
+ {
+ string t = "Test string!";
+ testList.Add(t);
+ }
+ GC.Collect();
+ };
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int GCCreateSegmentEvents = 0;
+ int GCFreeSegmentEvents = 0;
+ source.Clr.GCCreateSegment += (eventData) => GCCreateSegmentEvents += 1;
+ source.Clr.GCFreeSegment += (eventData) => GCFreeSegmentEvents += 1;
+
+ int GCAllocationTickEvents = 0;
+ source.Clr.GCAllocationTick += (eventData) => GCAllocationTickEvents += 1;
+
+ int GCCreateConcurrentThreadEvents = 0;
+ int GCTerminateConcurrentThreadEvents = 0;
+ source.Clr.GCCreateConcurrentThread += (eventData) => GCCreateConcurrentThreadEvents += 1;
+ source.Clr.GCTerminateConcurrentThread += (eventData) => GCTerminateConcurrentThreadEvents += 1;
+
+ return () => {
+ Logger.logger.Log("Event counts validation");
+
+ Logger.logger.Log("GCCreateSegmentEvents: " + GCCreateSegmentEvents);
+ Logger.logger.Log("GCFreeSegmentEvents: " + GCFreeSegmentEvents);
+ bool GCSegmentResult = GCCreateSegmentEvents > 0 && GCFreeSegmentEvents > 0;
+ Logger.logger.Log("GCSegmentResult: " + GCSegmentResult);
+
+ Logger.logger.Log("GCAllocationTickEvents: " + GCAllocationTickEvents);
+ bool GCAllocationTickResult = GCAllocationTickEvents > 0;
+ Logger.logger.Log("GCAllocationTickResult: " + GCAllocationTickResult);
+
+ Logger.logger.Log("GCCreateConcurrentThreadEvents: " + GCCreateConcurrentThreadEvents);
+ //GCTerminateConcurrentThreadEvents not stable, ignore the verification
+ Logger.logger.Log("GCTerminateConcurrentThreadEvents: " + GCTerminateConcurrentThreadEvents);
+ bool GCConcurrentResult = GCCreateConcurrentThreadEvents > 0 && GCTerminateConcurrentThreadEvents >= 0;
+ Logger.logger.Log("GCConcurrentResult: " + GCConcurrentResult);
+
+ bool GCCollectResults = GCSegmentResult && GCAllocationTickResult && GCConcurrentResult;
+ Logger.logger.Log("GCCollectResults: " + GCCollectResults);
+
+ return GCCollectResults ? 100 : -1;
+ };
+ };
+
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using System.IO;
+using System.Runtime.Loader;
+using System.Threading;
+using System.Reflection;
+using Xunit.Abstractions;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using EventPipe.UnitTests.Common;
+using Microsoft.Diagnostics.Tracing;
+
+namespace EventPipe.UnitTests.LoaderEventsValidation
+{
+ public class AssemblyLoad : AssemblyLoadContext
+ {
+ public AssemblyLoad() : base(true)
+ {
+ }
+ }
+ public class ProviderTests
+ {
+ private readonly ITestOutputHelper output;
+
+ public ProviderTests(ITestOutputHelper outputHelper)
+ {
+ output = outputHelper;
+ }
+
+ [Fact]
+ public async void AssemblyLoad_ProducesEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntime", -1 },
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ //LoaderKeyword (0x8): 0b1000
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b1000, EventLevel.Informational)
+ };
+
+ string assemblyPath=null;
+ Action _eventGeneratingAction = () =>
+ {
+ GetAssemblyPath();
+ try
+ {
+ for(int i=0; i<100; i++)
+ {
+ if (i % 10 == 0)
+ Logger.logger.Log($"Load/Unload Assembly {i} times...");
+ AssemblyLoad assemblyLoad = new AssemblyLoad();
+ assemblyLoad.LoadFromAssemblyPath(assemblyPath+"\\Microsoft.Diagnostics.Runtime.dll");
+ assemblyLoad.Unload();
+ }
+ }
+ catch(Exception ex)
+ {
+ Logger.logger.Log(ex.Message+ex.StackTrace);
+ }
+ };
+
+ void GetAssemblyPath()
+ {
+ assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ }
+
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int LoaderAssemblyLoadEvents = 0;
+ int LoaderAssemblyUnloadEvents = 0;
+ source.Clr.LoaderAssemblyLoad += (eventData) => LoaderAssemblyLoadEvents += 1;
+ source.Clr.LoaderAssemblyUnload += (eventData) => LoaderAssemblyUnloadEvents += 1;
+
+ int LoaderModuleLoadEvents = 0;
+ int LoaderModuleUnloadEvents = 0;
+ source.Clr.LoaderModuleLoad += (eventData) => LoaderModuleLoadEvents += 1;
+ source.Clr.LoaderModuleUnload += (eventData) => LoaderModuleUnloadEvents += 1;
+
+ return () => {
+ Logger.logger.Log("Event counts validation");
+
+ Logger.logger.Log("LoaderAssemblyLoadEvents: " + LoaderAssemblyLoadEvents);
+ Logger.logger.Log("LoaderAssemblyUnloadEvents: " + LoaderAssemblyUnloadEvents);
+ //Unload method just marks as unloadable, not unload immediately, so we check the unload events >=1 to make the tests stable
+ bool LoaderAssemblyResult = LoaderAssemblyLoadEvents >= 100 && LoaderAssemblyUnloadEvents >= 1;
+ Logger.logger.Log("LoaderAssemblyResult check: " + LoaderAssemblyResult);
+
+ Logger.logger.Log("LoaderModuleLoadEvents: " + LoaderModuleLoadEvents);
+ Logger.logger.Log("LoaderModuleUnloadEvents: " + LoaderModuleUnloadEvents);
+ //Unload method just marks as unloadable, not unload immediately, so we check the unload events >=1 to make the tests stable
+ bool LoaderModuleResult = LoaderModuleLoadEvents >= 100 && LoaderModuleUnloadEvents >= 1;
+ Logger.logger.Log("LoaderModuleResult check: " + LoaderModuleResult);
+
+ return LoaderAssemblyResult && LoaderModuleResult ? 100 : -1;
+ };
+ };
+
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using System.ComponentModel;
+using Xunit.Abstractions;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using EventPipe.UnitTests.Common;
+using Microsoft.Diagnostics.Tracing;
+
+namespace EventPipe.UnitTests.MethodEventsValidation
+{
+ public class M_verbose : IDisposable
+ {
+ public bool IsZero(char c)
+ {
+ return c == 0;
+ }
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+ }
+ public class ProviderTests
+ {
+ private readonly ITestOutputHelper output;
+
+ public ProviderTests(ITestOutputHelper outputHelper)
+ {
+ output = outputHelper;
+ }
+
+ [Fact]
+ public async void MethodVerbose_ProducesEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ //registering Dynamic_All and Clr event callbacks will override each other, disable the check for the provider and check the events counts in the callback
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 },
+ { "Microsoft-DotNETCore-SampleProfiler", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ //MethodVerboseKeyword (0x10): 0b10000
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b10000, EventLevel.Verbose)
+ };
+
+ Action _eventGeneratingAction = () =>
+ {
+ for(int i=0; i<100; i++)
+ {
+ if (i % 10 == 0)
+ Logger.logger.Log($"M_verbose occured {i} times...");
+
+ using(M_verbose verbose = new M_verbose())
+ {
+ verbose.IsZero('f');
+ verbose.Dispose();
+ }
+ }
+ };
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int MethodLoadVerboseEvents = 0;
+ int MethodUnloadVerboseEvents = 0;
+ source.Clr.MethodLoadVerbose += (eventData) => MethodLoadVerboseEvents += 1;
+ source.Clr.MethodUnloadVerbose += (eventData) => MethodUnloadVerboseEvents += 1;
+
+ int MethodJittingStartedEvents = 0;
+ source.Clr.MethodJittingStarted += (eventData) => MethodJittingStartedEvents += 1;
+
+ return () => {
+ Logger.logger.Log("Event counts validation");
+ Logger.logger.Log("MethodLoadVerboseEvents: " + MethodLoadVerboseEvents);
+ Logger.logger.Log("MethodUnloadVerboseEvents: " + MethodUnloadVerboseEvents);
+ //MethodUnloadVerboseEvents not stable, ignore the verification
+ bool MethodVerboseResult = MethodLoadVerboseEvents >= 1 && MethodUnloadVerboseEvents >= 0;
+ Logger.logger.Log("MethodVerboseResult check: " + MethodVerboseResult);
+
+ Logger.logger.Log("MethodJittingStartedEvents: " + MethodJittingStartedEvents);
+ bool MethodJittingStartedResult = MethodJittingStartedEvents >= 1;
+ Logger.logger.Log("MethodJittingStartedResult check: " + MethodJittingStartedResult);
+ return MethodVerboseResult && MethodJittingStartedResult ? 100 : -1;
+ };
+ };
+
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit.Abstractions;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using EventPipe.UnitTests.Common;
+using Microsoft.Diagnostics.Tracing;
+
+namespace EventPipe.UnitTests.ThreadPoolValidation
+{
+ public class ProviderTests
+ {
+ private readonly ITestOutputHelper output;
+
+ public ProviderTests(ITestOutputHelper outputHelper)
+ {
+ output = outputHelper;
+ }
+
+ [Fact]
+ public async void ThreadPool_ProducesEvents()
+ {
+ await RemoteTestExecutorHelper.RunTestCaseAsync(() =>
+ {
+ Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntime", -1 },
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 }
+ };
+
+ var providers = new List<Provider>()
+ {
+ //ThreadingKeyword (0x10000): 0b10000_0000_0000_0000
+ new Provider("Microsoft-Windows-DotNETRuntime", 0b10000_0000_0000_0000, EventLevel.Informational)
+ };
+
+ Action _eventGeneratingAction = () =>
+ {
+ Task[] taskArray = new Task[1000];
+ for (int i = 0; i < 1000; i++)
+ {
+ if (i % 10 == 0)
+ Logger.logger.Log($"Create new task {i} times...");
+ taskArray[i] = Task.Run(() => TestTask());
+ }
+ Task.WaitAll(taskArray);
+ };
+
+ void TestTask()
+ {
+ Thread.Sleep(100);
+ }
+
+ Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
+ {
+ int ThreadStartEvents = 0;
+ source.Clr.ThreadPoolWorkerThreadStart += (eventData) => ThreadStartEvents += 1;
+
+ int ThreadPoolWorkerThreadAdjustmentSampleEvents = 0;
+ int ThreadPoolWorkerThreadAdjustmentAdjustmentEvents = 0;
+ source.Clr.ThreadPoolWorkerThreadAdjustmentSample += (eventData) => ThreadPoolWorkerThreadAdjustmentSampleEvents += 1;
+ source.Clr.ThreadPoolWorkerThreadAdjustmentAdjustment += (eventData) => ThreadPoolWorkerThreadAdjustmentAdjustmentEvents += 1;
+
+ return () => {
+ Logger.logger.Log("Event counts validation");
+
+ Logger.logger.Log("ThreadStartEvents: " + ThreadStartEvents);
+ bool ThreadStartStopResult = ThreadStartEvents >= 1;
+ Logger.logger.Log("ThreadStartStopResult check: " + ThreadStartStopResult);
+
+ Logger.logger.Log("ThreadPoolWorkerThreadAdjustmentSampleEvents: " + ThreadPoolWorkerThreadAdjustmentSampleEvents);
+ Logger.logger.Log("ThreadPoolWorkerThreadAdjustmentAdjustmentEvents: " + ThreadPoolWorkerThreadAdjustmentAdjustmentEvents);
+ bool ThreadAdjustmentResult = ThreadPoolWorkerThreadAdjustmentSampleEvents >= 1 && ThreadPoolWorkerThreadAdjustmentAdjustmentEvents >= 1;
+ Logger.logger.Log("ThreadAdjustmentResult check: " + ThreadAdjustmentResult);
+
+ return ThreadStartStopResult && ThreadAdjustmentResult ? 100 : -1;
+ };
+ };
+
+ var config = new SessionConfiguration(circularBufferSizeMB: (uint)Math.Pow(2, 10), format: EventPipeSerializationFormat.NetTrace, providers: providers);
+
+ var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, config, _DoesTraceContainEvents);
+ Assert.Equal(100, ret);
+ }, output);
+ }
+ }
+}
\ No newline at end of file