未验证 提交 ae401454 编写于 作者: S Sung Yoon Whang 提交者: GitHub

Fix AV in NativeRuntimeEventSource QCalls (#48414)

* Fix AV in NativeRuntimeEventSource QCalls

* Add test

* Use WriteEventCore APIs to emit events on Mono

* Separate out Mono/CoreCLR implementations to different files

* Fix wasm build
上级 481628fd
......@@ -126,6 +126,7 @@
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Debugger.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\EditAndContinueHelper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipe.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\NativeRuntimeEventSource.PortableThreadPool.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\ICustomDebuggerNotification.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrame.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrameHelper.cs" />
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Threading;
using System.Diagnostics.Tracing;
using System.Runtime.CompilerServices;
using Internal.Runtime.CompilerServices;
namespace System.Diagnostics.Tracing
{
// This is part of the NativeRuntimeEventsource, which is the managed version of the Microsoft-Windows-DotNETRuntime provider.
// It contains the handwritten implementation of the ThreadPool events.
// The events here do not call into the typical WriteEvent* APIs unlike most EventSources because that results in the
// events to be forwarded to EventListeners twice, once directly from the managed WriteEvent API, and another time
// from the mechanism in NativeRuntimeEventSource.ProcessEvents that forwards native runtime events to EventListeners.
// To prevent this, these events call directly into QCalls provided by the runtime (refer to NativeRuntimeEventSource.cs) which call
// FireEtw* methods auto-generated from ClrEtwAll.man. This ensures that corresponding event sinks are being used
// for the native platform. Refer to src/coreclr/vm/nativeruntimesource.cpp.
// For Mono implementation of these events, refer to NativeRuntimeEventSource.PortableThreadPool.cs.
internal sealed partial class NativeRuntimeEventSource : EventSource
{
// This value does not seem to be used, leaving it as zero for now. It may be useful for a scenario that may involve
// multiple instances of the runtime within the same process, but then it seems unlikely that both instances' thread
// pools would be in moderate use.
private const ushort DefaultClrInstanceId = 0;
private static class Messages
{
public const string WorkerThread = "ActiveWorkerThreadCount={0};\nRetiredWorkerThreadCount={1};\nClrInstanceID={2}";
public const string WorkerThreadAdjustmentSample = "Throughput={0};\nClrInstanceID={1}";
public const string WorkerThreadAdjustmentAdjustment = "AverageThroughput={0};\nNewWorkerThreadCount={1};\nReason={2};\nClrInstanceID={3}";
public const string WorkerThreadAdjustmentStats = "Duration={0};\nThroughput={1};\nThreadWave={2};\nThroughputWave={3};\nThroughputErrorEstimate={4};\nAverageThroughputErrorEstimate={5};\nThroughputRatio={6};\nConfidence={7};\nNewControlSetting={8};\nNewThreadWaveMagnitude={9};\nClrInstanceID={10}";
public const string IOEnqueue = "NativeOverlapped={0};\nOverlapped={1};\nMultiDequeues={2};\nClrInstanceID={3}";
public const string IO = "NativeOverlapped={0};\nOverlapped={1};\nClrInstanceID={2}";
public const string WorkingThreadCount = "Count={0};\nClrInstanceID={1}";
}
// The task definitions for the ETW manifest
public static class Tasks // this name and visibility is important for EventSource
{
public const EventTask ThreadPoolWorkerThread = (EventTask)16;
public const EventTask ThreadPoolWorkerThreadAdjustment = (EventTask)18;
public const EventTask ThreadPool = (EventTask)23;
public const EventTask ThreadPoolWorkingThreadCount = (EventTask)22;
}
public static class Opcodes // this name and visibility is important for EventSource
{
public const EventOpcode IOEnqueue = (EventOpcode)13;
public const EventOpcode IODequeue = (EventOpcode)14;
public const EventOpcode Wait = (EventOpcode)90;
public const EventOpcode Sample = (EventOpcode)100;
public const EventOpcode Adjustment = (EventOpcode)101;
public const EventOpcode Stats = (EventOpcode)102;
}
public enum ThreadAdjustmentReasonMap : uint
{
Warmup,
Initializing,
RandomMove,
ClimbingMove,
ChangePoint,
Stabilizing,
Starvation,
ThreadTimedOut
}
[Event(50, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = EventOpcode.Start, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadStart(
uint ActiveWorkerThreadCount,
uint RetiredWorkerThreadCount = 0,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadStart(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
}
}
[Event(51, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = EventOpcode.Stop, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public void ThreadPoolWorkerThreadStop(
uint ActiveWorkerThreadCount,
uint RetiredWorkerThreadCount = 0,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadStop(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
}
}
[Event(57, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = Opcodes.Wait, Version = 0, Keywords = Keywords.ThreadingKeyword)]
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThreadPoolWorkerThreadWait(
uint ActiveWorkerThreadCount,
uint RetiredWorkerThreadCount = 0,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadWait(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
}
}
[Event(54, Level = EventLevel.Informational, Message = Messages.WorkerThreadAdjustmentSample, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Sample, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadAdjustmentSample(
double Throughput,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkerThreadAdjustmentSample(Throughput, ClrInstanceID);
}
[Event(55, Level = EventLevel.Informational, Message = Messages.WorkerThreadAdjustmentAdjustment, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Adjustment, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadAdjustmentAdjustment(
double AverageThroughput,
uint NewWorkerThreadCount,
ThreadAdjustmentReasonMap Reason,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkerThreadAdjustmentAdjustment(AverageThroughput, NewWorkerThreadCount, Reason, ClrInstanceID);
}
[Event(56, Level = EventLevel.Verbose, Message = Messages.WorkerThreadAdjustmentStats, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Stats, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadAdjustmentStats(
double Duration,
double Throughput,
double ThreadWave,
double ThroughputWave,
double ThroughputErrorEstimate,
double AverageThroughputErrorEstimate,
double ThroughputRatio,
double Confidence,
double NewControlSetting,
ushort NewThreadWaveMagnitude,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkerThreadAdjustmentStats(Duration, Throughput, ThreadWave, ThroughputWave, ThroughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, Confidence, NewControlSetting, NewThreadWaveMagnitude, ClrInstanceID);
}
[Event(63, Level = EventLevel.Verbose, Message = Messages.IOEnqueue, Task = Tasks.ThreadPool, Opcode = Opcodes.IOEnqueue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)]
private unsafe void ThreadPoolIOEnqueue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
bool MultiDequeues,
ushort ClrInstanceID = DefaultClrInstanceId)
{
int multiDequeuesInt = Convert.ToInt32(MultiDequeues); // bool maps to "win:Boolean", a 4-byte boolean
LogThreadPoolIOEnqueue(NativeOverlapped, Overlapped, MultiDequeues, ClrInstanceID);
}
// TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use
// FrameworkEventSource's thread transfer send/receive events instead at callers.
[NonEvent]
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThreadPoolIOEnqueue(RegisteredWaitHandle registeredWaitHandle)
{
if (IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword))
{
ThreadPoolIOEnqueue((IntPtr)registeredWaitHandle.GetHashCode(), IntPtr.Zero, registeredWaitHandle.Repeating);
}
}
[Event(64, Level = EventLevel.Verbose, Message = Messages.IO, Task = Tasks.ThreadPool, Opcode = Opcodes.IODequeue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)]
private unsafe void ThreadPoolIODequeue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
ushort ClrInstanceID = DefaultClrInstanceId)
{
LogThreadPoolIODequeue(NativeOverlapped, Overlapped, ClrInstanceID);
}
// TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use
// FrameworkEventSource's thread transfer send/receive events instead at callers.
[NonEvent]
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThreadPoolIODequeue(RegisteredWaitHandle registeredWaitHandle)
{
if (IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword))
{
ThreadPoolIODequeue((IntPtr)registeredWaitHandle.GetHashCode(), IntPtr.Zero);
}
}
[Event(60, Level = EventLevel.Verbose, Message = Messages.WorkingThreadCount, Task = Tasks.ThreadPoolWorkingThreadCount, Opcode = EventOpcode.Start, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkingThreadCount(uint Count, ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkingThreadCount(Count, ClrInstanceID);
}
}
}
......@@ -989,13 +989,15 @@ FCFuncStart(gStreamFuncs)
FCFuncEnd()
#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
FCFuncStart(gEventLogger)
#if defined(FEATURE_EVENTSOURCE_XPLAT)
FCFuncStart(gEventLogger)
QCFuncElement("IsEventSourceLoggingEnabled", XplatEventSourceLogger::IsEventSourceLoggingEnabled)
QCFuncElement("LogEventSource", XplatEventSourceLogger::LogEventSource)
FCFuncEnd()
#endif // defined(FEATURE_EVENTSOURCE_XPLAT)
#if defined(FEATURE_PERFTRACING)
FCFuncStart(gNativeEventLogger)
QCFuncElement("LogThreadPoolWorkerThreadStart", NativeEventLogger::LogThreadPoolWorkerThreadStart)
QCFuncElement("LogThreadPoolWorkerThreadStop", NativeEventLogger::LogThreadPoolWorkerThreadStop)
QCFuncElement("LogThreadPoolWorkerThreadWait", NativeEventLogger::LogThreadPoolWorkerThreadWait)
......@@ -1005,9 +1007,8 @@ FCFuncStart(gEventLogger)
QCFuncElement("LogThreadPoolIOEnqueue", NativeEventLogger::LogThreadPoolIOEnqueue)
QCFuncElement("LogThreadPoolIODequeue", NativeEventLogger::LogThreadPoolIODequeue)
QCFuncElement("LogThreadPoolWorkingThreadCount", NativeEventLogger::LogThreadPoolWorkingThreadCount)
#endif // defined(FEATURE_PERFTRACING)
FCFuncEnd()
#endif // defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
#endif // defined(FEATURE_PERFTRACING)
#ifdef FEATURE_PERFTRACING
FCFuncStart(gEventPipeInternalFuncs)
......@@ -1165,6 +1166,9 @@ FCClassElement("ModuleBuilder", "System.Reflection.Emit", gCOMModuleBuilderFuncs
FCClassElement("ModuleHandle", "System", gCOMModuleHandleFuncs)
FCClassElement("Monitor", "System.Threading", gMonitorFuncs)
FCClassElement("NativeLibrary", "System.Runtime.InteropServices", gInteropNativeLibraryFuncs)
#if defined(FEATURE_PERFTRACING)
FCClassElement("NativeRuntimeEventSource", "System.Diagnostics.Tracing", gNativeEventLogger)
#endif //defined(FEATURE_PERFTRACING)
#ifdef FEATURE_COMINTEROP
FCClassElement("OAVariantLib", "Microsoft.Win32", gOAVariantFuncs)
#endif
......@@ -1213,7 +1217,7 @@ FCClassElement("WeakReference`1", "System", gWeakReferenceOfTFuncs)
FCClassElement("X86Base", "System.Runtime.Intrinsics.X86", gX86BaseFuncs)
#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
#if defined(FEATURE_EVENTSOURCE_XPLAT)
FCClassElement("XplatEventLogger", "System.Diagnostics.Tracing", gEventLogger)
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)
......
......@@ -1960,7 +1960,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPool.Portable.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPoolBoundHandle.PlatformNotSupported.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.GateThread.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.HillClimbing.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.HillClimbing.Complex.cs" />
......
......@@ -1283,7 +1283,15 @@ protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* rel
#endif // FEATURE_MANAGED_ETW
if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data);
{
#if MONO && !TARGET_BROWSER
// On Mono, managed events from NativeRuntimeEventSource are written using WriteEventCore which can be
// written doubly because EventPipe tries to pump it back up to EventListener via NativeRuntimeEventSource.ProcessEvents.
// So we need to prevent this from getting written directly to the Listeners.
if (this.GetType() != typeof(NativeRuntimeEventSource))
#endif // MONO && !TARGET_BROWSER
WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data);
}
}
catch (Exception ex)
{
......
......@@ -8,14 +8,9 @@
namespace System.Diagnostics.Tracing
{
// This is part of the NativeRuntimeEventsource, which is the managed version of the Microsoft-Windows-DotNETRuntime provider.
// It contains the handwritten implementation of the ThreadPool events.
// The events here do not call into the typical WriteEvent* APIs unlike most EventSources because that results in the
// events to be forwarded to EventListeners twice, once directly from the managed WriteEvent API, and another time
// from the mechanism in NativeRuntimeEventSource.ProcessEvents that forwards native runtime events to EventListeners.
// To prevent this, these events call directly into QCalls provided by the runtime (refer to NativeRuntimeEventSource.cs) which call
// FireEtw* methods auto-generated from ClrEtwAll.man. This ensures that corresponding event sinks are being used
// for the native platform. Refer to src/coreclr/vm/nativeruntimesource.cpp.
// This is part of the NativeRuntimeEventsource for Mono, which is the managed version of the Microsoft-Windows-DotNETRuntime provider.
// and contains the implementation of ThreadPool events.
// To look at CoreCLR implementation of these events, refer to NativeRuntimeEventSource.PortableThreadPool.CoreCLR.cs.
internal sealed partial class NativeRuntimeEventSource : EventSource
{
// This value does not seem to be used, leaving it as zero for now. It may be useful for a scenario that may involve
......@@ -65,6 +60,25 @@ public enum ThreadAdjustmentReasonMap : uint
ThreadTimedOut
}
[NonEvent]
private unsafe void WriteThreadEvent(int eventId, uint numExistingThreads)
{
uint retiredWorkerThreadCount = 0;
ushort clrInstanceId = DefaultClrInstanceId;
EventData* data = stackalloc EventData[3];
data[0].DataPointer = (IntPtr)(&numExistingThreads);
data[0].Size = sizeof(uint);
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&retiredWorkerThreadCount);
data[1].Size = sizeof(uint);
data[1].Reserved = 0;
data[2].DataPointer = (IntPtr)(&clrInstanceId);
data[2].Size = sizeof(ushort);
data[2].Reserved = 0;
WriteEventCore(eventId, 3, data);
}
[Event(50, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = EventOpcode.Start, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadStart(
uint ActiveWorkerThreadCount,
......@@ -73,7 +87,7 @@ public enum ThreadAdjustmentReasonMap : uint
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadStart(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
WriteThreadEvent(50, ActiveWorkerThreadCount);
}
}
......@@ -85,7 +99,7 @@ public enum ThreadAdjustmentReasonMap : uint
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadStop(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
WriteThreadEvent(51, ActiveWorkerThreadCount);
}
}
......@@ -98,7 +112,7 @@ public enum ThreadAdjustmentReasonMap : uint
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadWait(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
WriteThreadEvent(57, ActiveWorkerThreadCount);
}
}
......@@ -111,7 +125,14 @@ public enum ThreadAdjustmentReasonMap : uint
{
return;
}
LogThreadPoolWorkerThreadAdjustmentSample(Throughput, ClrInstanceID);
EventData* data = stackalloc EventData[2];
data[0].DataPointer = (IntPtr)(&Throughput);
data[0].Size = sizeof(double);
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&ClrInstanceID);
data[1].Size = sizeof(ushort);
data[1].Reserved = 0;
WriteEventCore(54, 2, data);
}
[Event(55, Level = EventLevel.Informational, Message = Messages.WorkerThreadAdjustmentAdjustment, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Adjustment, Version = 0, Keywords = Keywords.ThreadingKeyword)]
......@@ -125,7 +146,20 @@ public enum ThreadAdjustmentReasonMap : uint
{
return;
}
LogThreadPoolWorkerThreadAdjustmentAdjustment(AverageThroughput, NewWorkerThreadCount, Reason, ClrInstanceID);
EventData* data = stackalloc EventData[4];
data[0].DataPointer = (IntPtr)(&AverageThroughput);
data[0].Size = sizeof(double);
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&NewWorkerThreadCount);
data[1].Size = sizeof(uint);
data[1].Reserved = 0;
data[2].DataPointer = (IntPtr)(&Reason);
data[2].Size = sizeof(ThreadAdjustmentReasonMap);
data[2].Reserved = 0;
data[3].DataPointer = (IntPtr)(&ClrInstanceID);
data[3].Size = sizeof(ushort);
data[3].Reserved = 0;
WriteEventCore(55, 4, data);
}
[Event(56, Level = EventLevel.Verbose, Message = Messages.WorkerThreadAdjustmentStats, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Stats, Version = 0, Keywords = Keywords.ThreadingKeyword)]
......@@ -146,7 +180,41 @@ public enum ThreadAdjustmentReasonMap : uint
{
return;
}
LogThreadPoolWorkerThreadAdjustmentStats(Duration, Throughput, ThreadWave, ThroughputWave, ThroughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, Confidence, NewControlSetting, NewThreadWaveMagnitude, ClrInstanceID);
EventData* data = stackalloc EventData[11];
data[0].DataPointer = (IntPtr)(&Duration);
data[0].Size = sizeof(double);
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&Throughput);
data[1].Size = sizeof(double);
data[1].Reserved = 0;
data[2].DataPointer = (IntPtr)(&ThreadWave);
data[2].Size = sizeof(double);
data[2].Reserved = 0;
data[3].DataPointer = (IntPtr)(&ThroughputWave);
data[3].Size = sizeof(double);
data[3].Reserved = 0;
data[4].DataPointer = (IntPtr)(&ThroughputErrorEstimate);
data[4].Size = sizeof(double);
data[4].Reserved = 0;
data[5].DataPointer = (IntPtr)(&AverageThroughputErrorEstimate);
data[5].Size = sizeof(double);
data[5].Reserved = 0;
data[6].DataPointer = (IntPtr)(&ThroughputRatio);
data[6].Size = sizeof(double);
data[6].Reserved = 0;
data[7].DataPointer = (IntPtr)(&Confidence);
data[7].Size = sizeof(double);
data[7].Reserved = 0;
data[8].DataPointer = (IntPtr)(&NewControlSetting);
data[8].Size = sizeof(double);
data[8].Reserved = 0;
data[9].DataPointer = (IntPtr)(&NewThreadWaveMagnitude);
data[9].Size = sizeof(ushort);
data[9].Reserved = 0;
data[10].DataPointer = (IntPtr)(&ClrInstanceID);
data[10].Size = sizeof(ushort);
data[10].Reserved = 0;
WriteEventCore(56, 11, data);
}
[Event(63, Level = EventLevel.Verbose, Message = Messages.IOEnqueue, Task = Tasks.ThreadPool, Opcode = Opcodes.IOEnqueue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)]
......@@ -157,7 +225,20 @@ public enum ThreadAdjustmentReasonMap : uint
ushort ClrInstanceID = DefaultClrInstanceId)
{
int multiDequeuesInt = Convert.ToInt32(MultiDequeues); // bool maps to "win:Boolean", a 4-byte boolean
LogThreadPoolIOEnqueue(NativeOverlapped, Overlapped, MultiDequeues, ClrInstanceID);
EventData* data = stackalloc EventData[4];
data[0].DataPointer = (IntPtr)(&NativeOverlapped);
data[0].Size = IntPtr.Size;
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&Overlapped);
data[1].Size = IntPtr.Size;
data[1].Reserved = 0;
data[2].DataPointer = (IntPtr)(&multiDequeuesInt);
data[2].Size = sizeof(int);
data[2].Reserved = 0;
data[3].DataPointer = (IntPtr)(&ClrInstanceID);
data[3].Size = sizeof(ushort);
data[3].Reserved = 0;
WriteEventCore(63, 4, data);
}
// TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use
......@@ -178,7 +259,17 @@ public void ThreadPoolIOEnqueue(RegisteredWaitHandle registeredWaitHandle)
IntPtr Overlapped,
ushort ClrInstanceID = DefaultClrInstanceId)
{
LogThreadPoolIODequeue(NativeOverlapped, Overlapped, ClrInstanceID);
EventData* data = stackalloc EventData[3];
data[0].DataPointer = (IntPtr)(&NativeOverlapped);
data[0].Size = IntPtr.Size;
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&Overlapped);
data[1].Size = IntPtr.Size;
data[1].Reserved = 0;
data[2].DataPointer = (IntPtr)(&ClrInstanceID);
data[2].Size = sizeof(ushort);
data[2].Reserved = 0;
WriteEventCore(64, 3, data);
}
// TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use
......@@ -200,7 +291,14 @@ public unsafe void ThreadPoolWorkingThreadCount(uint Count, ushort ClrInstanceID
{
return;
}
LogThreadPoolWorkingThreadCount(Count, ClrInstanceID);
EventData* data = stackalloc EventData[2];
data[0].DataPointer = (IntPtr)(&Count);
data[0].Size = sizeof(uint);
data[0].Reserved = 0;
data[1].DataPointer = (IntPtr)(&ClrInstanceID);
data[1].Size = sizeof(ushort);
data[1].Reserved = 0;
WriteEventCore(60, 2, data);
}
}
}
// 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.Tracing;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tools.RuntimeClient;
using Microsoft.Diagnostics.Tracing;
using Tracing.Tests.Common;
namespace Tracing.Tests.GCFinalizers
{
public class ProviderValidation
{
public static int Main(string[] args)
{
var providers = new List<Provider>()
{
new Provider("Microsoft-DotNETCore-SampleProfiler"),
//ThreadingKeyword (0x10000)
new Provider("Microsoft-Windows-DotNETRuntime", 0x10000, EventLevel.Verbose)
};
var configuration = new SessionConfiguration(circularBufferSizeMB: 1024, format: EventPipeSerializationFormat.NetTrace, providers: providers);
return IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, configuration, _DoesTraceContainEvents);
}
private static Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
{
{ "Microsoft-Windows-DotNETRuntime", -1 },
{ "Microsoft-Windows-DotNETRuntimeRundown", -1 },
{ "Microsoft-DotNETCore-SampleProfiler", -1 }
};
private static Action _eventGeneratingAction = () =>
{
Task[] tasks = new Task[50];
for (int i = 0; i < 50; i++)
{
tasks[i] = Task.Run(async () => {
long total = 0;
await Task.Delay(10);
var rnd = new Random();
for (int n = 1; n <= 100; n++)
total += rnd.Next(0, 100);
return total;
});
}
};
private static Func<EventPipeEventSource, Func<int>> _DoesTraceContainEvents = (source) =>
{
int threadPoolEventsCount = 0;
source.Clr.ThreadPoolWorkerThreadStart += (_) => threadPoolEventsCount += 1;
source.Clr.ThreadPoolWorkerThreadWait += (_) => threadPoolEventsCount += 1;
source.Clr.ThreadPoolWorkerThreadStop += (_) => threadPoolEventsCount += 1;
source.Clr.ThreadPoolWorkerThreadAdjustmentSample += (_) => threadPoolEventsCount += 1;
source.Clr.ThreadPoolWorkerThreadAdjustmentAdjustment += (_) => threadPoolEventsCount += 1;
return () => {
Logger.logger.Log("Event counts validation");
return threadPoolEventsCount >= 50 ? 100 : -1;
};
};
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
<OutputType>exe</OutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CLRTestPriority>1</CLRTestPriority>
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
<JitOptimizationSensitive>true</JitOptimizationSensitive>
<GCStressIncompatible>true</GCStressIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="ThreadPool.cs" />
<ProjectReference Include="../common/common.csproj" />
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册