summaryrefslogtreecommitdiff
path: root/src/System.Private.CoreLib/shared/System/Threading/Tasks
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2019-01-22 04:28:13 +0100
committerJan Kotas <jkotas@microsoft.com>2019-01-21 19:28:13 -0800
commit5c9febf6346f90c06e70b3cb9e002300e50fa54b (patch)
tree9f589c28bba076725c51def4d189b7fc814dd4a5 /src/System.Private.CoreLib/shared/System/Threading/Tasks
parentedffbd9c545aa9c1f6cb7ae048efdf5db13d3991 (diff)
downloadcoreclr-5c9febf6346f90c06e70b3cb9e002300e50fa54b.tar.gz
coreclr-5c9febf6346f90c06e70b3cb9e002300e50fa54b.tar.bz2
coreclr-5c9febf6346f90c06e70b3cb9e002300e50fa54b.zip
Move TplEtwProvider to shared partition (#22120)
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Threading/Tasks')
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs584
1 files changed, 584 insertions, 0 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs
new file mode 100644
index 0000000000..311445ec28
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEtwProvider.cs
@@ -0,0 +1,584 @@
+// 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.Runtime.CompilerServices;
+using System.Diagnostics.Tracing;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Threading.Tasks
+{
+ /// <summary>Provides an event source for tracing TPL information.</summary>
+ [EventSource(
+ Name = "System.Threading.Tasks.TplEventSource",
+ Guid = "2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5"
+#if CORECLR
+ ,LocalizationResources = "FxResources.System.Private.CoreLib.SR"
+#endif
+ )]
+ internal sealed class TplEtwProvider : EventSource
+ {
+ /// Used to determine if tasks should generate Activity IDs for themselves
+ internal bool TasksSetActivityIds; // This keyword is set
+ internal bool Debug;
+ private bool DebugActivityId;
+
+ private const int DefaultAppDomainID = 1;
+
+ /// <summary>
+ /// Get callbacks when the ETW sends us commands`
+ /// </summary>
+ protected override void OnEventCommand(EventCommandEventArgs command)
+ {
+ // To get the AsyncCausality events, we need to inform the AsyncCausalityTracer
+ if (command.Command == EventCommand.Enable)
+ AsyncCausalityTracer.EnableToETW(true);
+ else if (command.Command == EventCommand.Disable)
+ AsyncCausalityTracer.EnableToETW(false);
+
+ if (IsEnabled(EventLevel.Informational, Keywords.TasksFlowActivityIds))
+ ActivityTracker.Instance.Enable();
+ else
+ TasksSetActivityIds = IsEnabled(EventLevel.Informational, Keywords.TasksSetActivityIds);
+
+ Debug = IsEnabled(EventLevel.Informational, Keywords.Debug);
+ DebugActivityId = IsEnabled(EventLevel.Informational, Keywords.DebugActivityId);
+ }
+
+ /// <summary>
+ /// Defines the singleton instance for the TPL ETW provider.
+ /// The TPL Event provider GUID is {2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5}.
+ /// </summary>
+ public static readonly TplEtwProvider Log = new TplEtwProvider();
+
+ /// <summary>Prevent external instantiation. All logging should go through the Log instance.</summary>
+ private TplEtwProvider() : base(new Guid(0x2e5dba47, 0xa3d2, 0x4d16, 0x8e, 0xe0, 0x66, 0x71, 0xff, 0xdc, 0xd7, 0xb5), "System.Threading.Tasks.TplEventSource") { }
+
+ /// <summary>Configured behavior of a task wait operation.</summary>
+ public enum TaskWaitBehavior : int
+ {
+ /// <summary>A synchronous wait.</summary>
+ Synchronous = 1,
+ /// <summary>An asynchronous await.</summary>
+ Asynchronous = 2
+ }
+
+ /// <summary>ETW tasks that have start/stop events.</summary>
+ public class Tasks // this name is important for EventSource
+ {
+ /// <summary>A parallel loop.</summary>
+ public const EventTask Loop = (EventTask)1;
+ /// <summary>A parallel invoke.</summary>
+ public const EventTask Invoke = (EventTask)2;
+ /// <summary>Executing a Task.</summary>
+ public const EventTask TaskExecute = (EventTask)3;
+ /// <summary>Waiting on a Task.</summary>
+ public const EventTask TaskWait = (EventTask)4;
+ /// <summary>A fork/join task within a loop or invoke.</summary>
+ public const EventTask ForkJoin = (EventTask)5;
+ /// <summary>A task is scheduled to execute.</summary>
+ public const EventTask TaskScheduled = (EventTask)6;
+ /// <summary>An await task continuation is scheduled to execute.</summary>
+ public const EventTask AwaitTaskContinuationScheduled = (EventTask)7;
+
+ /// <summary>AsyncCausalityFunctionality.</summary>
+ public const EventTask TraceOperation = (EventTask)8;
+ public const EventTask TraceSynchronousWork = (EventTask)9;
+ }
+
+ public class Keywords // thisname is important for EventSource
+ {
+ /// <summary>
+ /// Only the most basic information about the workings of the task library
+ /// This sets activity IDS and logs when tasks are schedules (or waits begin)
+ /// But are otherwise silent
+ /// </summary>
+ public const EventKeywords TaskTransfer = (EventKeywords)1;
+ /// <summary>
+ /// TaskTranser events plus events when tasks start and stop
+ /// </summary>
+ public const EventKeywords Tasks = (EventKeywords)2;
+ /// <summary>
+ /// Events associted with the higher level parallel APIs
+ /// </summary>
+ public const EventKeywords Parallel = (EventKeywords)4;
+ /// <summary>
+ /// These are relatively verbose events that effectively just redirect
+ /// the windows AsyncCausalityTracer to ETW
+ /// </summary>
+ public const EventKeywords AsyncCausalityOperation = (EventKeywords)8;
+ public const EventKeywords AsyncCausalityRelation = (EventKeywords)0x10;
+ public const EventKeywords AsyncCausalitySynchronousWork = (EventKeywords)0x20;
+
+ /// <summary>
+ /// Emit the stops as well as the schedule/start events
+ /// </summary>
+ public const EventKeywords TaskStops = (EventKeywords)0x40;
+
+ /// <summary>
+ /// TasksFlowActivityIds indicate that activity ID flow from one task
+ /// to any task created by it.
+ /// </summary>
+ public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80;
+
+ /// <summary>
+ /// Events related to the happenings of async methods.
+ /// </summary>
+ public const EventKeywords AsyncMethod = (EventKeywords)0x100;
+
+ /// <summary>
+ /// TasksSetActivityIds will cause the task operations to set Activity Ids
+ /// This option is incompatible with TasksFlowActivityIds flow is ignored
+ /// if that keyword is set. This option is likely to be removed in the future
+ /// </summary>
+ public const EventKeywords TasksSetActivityIds = (EventKeywords)0x10000;
+
+ /// <summary>
+ /// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future
+ /// </summary>
+ public const EventKeywords Debug = (EventKeywords)0x20000;
+ /// <summary>
+ /// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future
+ /// </summary>
+ public const EventKeywords DebugActivityId = (EventKeywords)0x40000;
+ }
+
+ /// <summary>Enabled for all keywords.</summary>
+ private const EventKeywords ALL_KEYWORDS = (EventKeywords)(-1);
+
+ //-----------------------------------------------------------------------------------
+ //
+ // TPL Event IDs (must be unique)
+ //
+
+ /// <summary>The beginning of a parallel loop.</summary>
+ private const int PARALLELLOOPBEGIN_ID = 1;
+ /// <summary>The ending of a parallel loop.</summary>
+ private const int PARALLELLOOPEND_ID = 2;
+ /// <summary>The beginning of a parallel invoke.</summary>
+ private const int PARALLELINVOKEBEGIN_ID = 3;
+ /// <summary>The ending of a parallel invoke.</summary>
+ private const int PARALLELINVOKEEND_ID = 4;
+ /// <summary>A task entering a fork/join construct.</summary>
+ private const int PARALLELFORK_ID = 5;
+ /// <summary>A task leaving a fork/join construct.</summary>
+ private const int PARALLELJOIN_ID = 6;
+
+ /// <summary>A task is scheduled to a task scheduler.</summary>
+ private const int TASKSCHEDULED_ID = 7;
+ /// <summary>A task is about to execute.</summary>
+ private const int TASKSTARTED_ID = 8;
+ /// <summary>A task has finished executing.</summary>
+ private const int TASKCOMPLETED_ID = 9;
+ /// <summary>A wait on a task is beginning.</summary>
+ private const int TASKWAITBEGIN_ID = 10;
+ /// <summary>A wait on a task is ending.</summary>
+ private const int TASKWAITEND_ID = 11;
+ /// <summary>A continuation of a task is scheduled.</summary>
+ private const int AWAITTASKCONTINUATIONSCHEDULED_ID = 12;
+ /// <summary>A continuation of a taskWaitEnd is complete </summary>
+ private const int TASKWAITCONTINUATIONCOMPLETE_ID = 13;
+ /// <summary>A continuation of a taskWaitEnd is complete </summary>
+ private const int TASKWAITCONTINUATIONSTARTED_ID = 19;
+
+ private const int TRACEOPERATIONSTART_ID = 14;
+ private const int TRACEOPERATIONSTOP_ID = 15;
+ private const int TRACEOPERATIONRELATION_ID = 16;
+ private const int TRACESYNCHRONOUSWORKSTART_ID = 17;
+ private const int TRACESYNCHRONOUSWORKSTOP_ID = 18;
+
+
+ //-----------------------------------------------------------------------------------
+ //
+ // Task Events
+ //
+
+ // These are all verbose events, so we need to call IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)
+ // call. However since the IsEnabled(l,k) call is more expensive than IsEnabled(), we only want
+ // to incur this cost when instrumentation is enabled. So the Task codepaths that call these
+ // event functions still do the check for IsEnabled()
+
+ #region TaskScheduled
+ /// <summary>
+ /// Fired when a task is queued to a TaskScheduler.
+ /// </summary>
+ /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
+ /// <param name="OriginatingTaskID">The task ID.</param>
+ /// <param name="TaskID">The task ID.</param>
+ /// <param name="CreatingTaskID">The task ID</param>
+ /// <param name="TaskCreationOptions">The options used to create the task.</param>
+ [Event(TASKSCHEDULED_ID, Task = Tasks.TaskScheduled, Version = 1, Opcode = EventOpcode.Send,
+ Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)]
+ public void TaskScheduled(
+ int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
+ int TaskID, int CreatingTaskID, int TaskCreationOptions, int appDomain = DefaultAppDomainID)
+ {
+ // IsEnabled() call is an inlined quick check that makes this very fast when provider is off
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[6];
+ eventPayload[0].Size = sizeof(int);
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
+ eventPayload[0].Reserved = 0;
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
+ eventPayload[1].Reserved = 0;
+ eventPayload[2].Size = sizeof(int);
+ eventPayload[2].DataPointer = ((IntPtr)(&TaskID));
+ eventPayload[2].Reserved = 0;
+ eventPayload[3].Size = sizeof(int);
+ eventPayload[3].DataPointer = ((IntPtr)(&CreatingTaskID));
+ eventPayload[3].Reserved = 0;
+ eventPayload[4].Size = sizeof(int);
+ eventPayload[4].DataPointer = ((IntPtr)(&TaskCreationOptions));
+ eventPayload[4].Reserved = 0;
+ eventPayload[5].Size = sizeof(int);
+ eventPayload[5].DataPointer = ((IntPtr)(&appDomain));
+ eventPayload[5].Reserved = 0;
+ if (TasksSetActivityIds)
+ {
+ Guid childActivityId = CreateGuidForTaskID(TaskID);
+ WriteEventWithRelatedActivityIdCore(TASKSCHEDULED_ID, &childActivityId, 6, eventPayload);
+ }
+ else
+ WriteEventCore(TASKSCHEDULED_ID, 6, eventPayload);
+ }
+ }
+ }
+ #endregion
+
+ #region TaskStarted
+ /// <summary>
+ /// Fired just before a task actually starts executing.
+ /// </summary>
+ /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
+ /// <param name="OriginatingTaskID">The task ID.</param>
+ /// <param name="TaskID">The task ID.</param>
+ [Event(TASKSTARTED_ID,
+ Level = EventLevel.Informational, Keywords = Keywords.Tasks)]
+ public void TaskStarted(
+ int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
+ int TaskID)
+ {
+ if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
+ WriteEvent(TASKSTARTED_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID);
+ }
+ #endregion
+
+ #region TaskCompleted
+ /// <summary>
+ /// Fired right after a task finished executing.
+ /// </summary>
+ /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
+ /// <param name="OriginatingTaskID">The task ID.</param>
+ /// <param name="TaskID">The task ID.</param>
+ /// <param name="IsExceptional">Whether the task completed due to an error.</param>
+ [Event(TASKCOMPLETED_ID, Version = 1,
+ Level = EventLevel.Informational, Keywords = Keywords.TaskStops)]
+ public void TaskCompleted(
+ int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
+ int TaskID, bool IsExceptional)
+ {
+ if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[4];
+ int isExceptionalInt = IsExceptional ? 1 : 0;
+ eventPayload[0].Size = sizeof(int);
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
+ eventPayload[0].Reserved = 0;
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
+ eventPayload[1].Reserved = 0;
+ eventPayload[2].Size = sizeof(int);
+ eventPayload[2].DataPointer = ((IntPtr)(&TaskID));
+ eventPayload[2].Reserved = 0;
+ eventPayload[3].Size = sizeof(int);
+ eventPayload[3].DataPointer = ((IntPtr)(&isExceptionalInt));
+ eventPayload[3].Reserved = 0;
+ WriteEventCore(TASKCOMPLETED_ID, 4, eventPayload);
+ }
+ }
+ }
+ #endregion
+
+ #region TaskWaitBegin
+ /// <summary>
+ /// Fired when starting to wait for a taks's completion explicitly or implicitly.
+ /// </summary>
+ /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
+ /// <param name="OriginatingTaskID">The task ID.</param>
+ /// <param name="TaskID">The task ID.</param>
+ /// <param name="Behavior">Configured behavior for the wait.</param>
+ /// <param name="ContinueWithTaskID">
+ /// If known, if 'TaskID' has a 'continueWith' task, mention give its ID here.
+ /// 0 means unknown. This allows better visualization of the common sequential chaining case.
+ /// </param>
+ [Event(TASKWAITBEGIN_ID, Version = 3, Task = TplEtwProvider.Tasks.TaskWait, Opcode = EventOpcode.Send,
+ Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)]
+ public void TaskWaitBegin(
+ int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
+ int TaskID, TaskWaitBehavior Behavior, int ContinueWithTaskID)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[5];
+ eventPayload[0].Size = sizeof(int);
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
+ eventPayload[0].Reserved = 0;
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
+ eventPayload[1].Reserved = 0;
+ eventPayload[2].Size = sizeof(int);
+ eventPayload[2].DataPointer = ((IntPtr)(&TaskID));
+ eventPayload[2].Reserved = 0;
+ eventPayload[3].Size = sizeof(int);
+ eventPayload[3].DataPointer = ((IntPtr)(&Behavior));
+ eventPayload[3].Reserved = 0;
+ eventPayload[4].Size = sizeof(int);
+ eventPayload[4].DataPointer = ((IntPtr)(&ContinueWithTaskID));
+ eventPayload[4].Reserved = 0;
+ if (TasksSetActivityIds)
+ {
+ Guid childActivityId = CreateGuidForTaskID(TaskID);
+ WriteEventWithRelatedActivityIdCore(TASKWAITBEGIN_ID, &childActivityId, 5, eventPayload);
+ }
+ else
+ {
+ WriteEventCore(TASKWAITBEGIN_ID, 5, eventPayload);
+ }
+ }
+ }
+ }
+ #endregion
+
+ /// <summary>
+ /// Fired when the wait for a tasks completion returns.
+ /// </summary>
+ /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
+ /// <param name="OriginatingTaskID">The task ID.</param>
+ /// <param name="TaskID">The task ID.</param>
+ [Event(TASKWAITEND_ID,
+ Level = EventLevel.Verbose, Keywords = Keywords.Tasks)]
+ public void TaskWaitEnd(
+ int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
+ int TaskID)
+ {
+ // Log an event if indicated.
+ if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks))
+ WriteEvent(TASKWAITEND_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID);
+ }
+
+ /// <summary>
+ /// Fired when the work (method) associated with a TaskWaitEnd completes
+ /// </summary>
+ /// <param name="TaskID">The task ID.</param>
+ [Event(TASKWAITCONTINUATIONCOMPLETE_ID,
+ Level = EventLevel.Verbose, Keywords = Keywords.TaskStops)]
+ public void TaskWaitContinuationComplete(int TaskID)
+ {
+ // Log an event if indicated.
+ if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks))
+ WriteEvent(TASKWAITCONTINUATIONCOMPLETE_ID, TaskID);
+ }
+
+ /// <summary>
+ /// Fired when the work (method) associated with a TaskWaitEnd completes
+ /// </summary>
+ /// <param name="TaskID">The task ID.</param>
+ [Event(TASKWAITCONTINUATIONSTARTED_ID,
+ Level = EventLevel.Verbose, Keywords = Keywords.TaskStops)]
+ public void TaskWaitContinuationStarted(int TaskID)
+ {
+ // Log an event if indicated.
+ if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks))
+ WriteEvent(TASKWAITCONTINUATIONSTARTED_ID, TaskID);
+ }
+
+ /// <summary>
+ /// Fired when the an asynchronous continuation for a task is scheduled
+ /// </summary>
+ /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
+ /// <param name="OriginatingTaskID">The task ID.</param>
+ [Event(AWAITTASKCONTINUATIONSCHEDULED_ID, Task = Tasks.AwaitTaskContinuationScheduled, Opcode = EventOpcode.Send,
+ Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)]
+ public void AwaitTaskContinuationScheduled(
+ int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
+ int ContinuwWithTaskId)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[3];
+ eventPayload[0].Size = sizeof(int);
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
+ eventPayload[0].Reserved = 0;
+ eventPayload[1].Size = sizeof(int);
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
+ eventPayload[1].Reserved = 0;
+ eventPayload[2].Size = sizeof(int);
+ eventPayload[2].DataPointer = ((IntPtr)(&ContinuwWithTaskId));
+ eventPayload[2].Reserved = 0;
+ if (TasksSetActivityIds)
+ {
+ Guid continuationActivityId = CreateGuidForTaskID(ContinuwWithTaskId);
+ WriteEventWithRelatedActivityIdCore(AWAITTASKCONTINUATIONSCHEDULED_ID, &continuationActivityId, 3, eventPayload);
+ }
+ else
+ WriteEventCore(AWAITTASKCONTINUATIONSCHEDULED_ID, 3, eventPayload);
+ }
+ }
+ }
+
+ [Event(TRACEOPERATIONSTART_ID, Version = 1,
+ Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)]
+ public void TraceOperationBegin(int TaskID, string OperationName, long RelatedContext)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
+ {
+ unsafe
+ {
+ fixed (char* operationNamePtr = OperationName)
+ {
+ EventData* eventPayload = stackalloc EventData[3];
+ eventPayload[0].Size = sizeof(int);
+ eventPayload[0].DataPointer = ((IntPtr)(&TaskID));
+ eventPayload[0].Reserved = 0;
+
+ eventPayload[1].Size = ((OperationName.Length + 1) * 2);
+ eventPayload[1].DataPointer = ((IntPtr)operationNamePtr);
+ eventPayload[1].Reserved = 0;
+
+ eventPayload[2].Size = sizeof(long);
+ eventPayload[2].DataPointer = ((IntPtr)(&RelatedContext));
+ eventPayload[2].Reserved = 0;
+ WriteEventCore(TRACEOPERATIONSTART_ID, 3, eventPayload);
+ }
+ }
+ }
+ }
+
+ [Event(TRACEOPERATIONRELATION_ID, Version = 1,
+ Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityRelation)]
+ public void TraceOperationRelation(int TaskID, CausalityRelation Relation)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityRelation))
+ WriteEvent(TRACEOPERATIONRELATION_ID, TaskID, (int)Relation); // optmized overload for this exists
+ }
+
+ [Event(TRACEOPERATIONSTOP_ID, Version = 1,
+ Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)]
+ public void TraceOperationEnd(int TaskID, AsyncCausalityStatus Status)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
+ WriteEvent(TRACEOPERATIONSTOP_ID, TaskID, (int)Status); // optmized overload for this exists
+ }
+
+ [Event(TRACESYNCHRONOUSWORKSTART_ID, Version = 1,
+ Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)]
+ public void TraceSynchronousWorkBegin(int TaskID, CausalitySynchronousWork Work)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
+ WriteEvent(TRACESYNCHRONOUSWORKSTART_ID, TaskID, (int)Work); // optmized overload for this exists
+ }
+
+ [Event(TRACESYNCHRONOUSWORKSTOP_ID, Version = 1,
+ Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)]
+ public void TraceSynchronousWorkEnd(CausalitySynchronousWork Work)
+ {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
+ {
+ unsafe
+ {
+ EventData* eventPayload = stackalloc EventData[1];
+ eventPayload[0].Size = sizeof(int);
+ eventPayload[0].DataPointer = ((IntPtr)(&Work));
+ eventPayload[0].Reserved = 0;
+
+ WriteEventCore(TRACESYNCHRONOUSWORKSTOP_ID, 1, eventPayload);
+ }
+ }
+ }
+
+ [NonEvent]
+ public unsafe void RunningContinuation(int TaskID, object Object) { RunningContinuation(TaskID, (long)*((void**)Unsafe.AsPointer(ref Object))); }
+ [Event(20, Keywords = Keywords.Debug)]
+ private void RunningContinuation(int TaskID, long Object)
+ {
+ if (Debug)
+ WriteEvent(20, TaskID, Object);
+ }
+
+ [NonEvent]
+ public unsafe void RunningContinuationList(int TaskID, int Index, object Object) { RunningContinuationList(TaskID, Index, (long)*((void**)Unsafe.AsPointer(ref Object))); }
+
+ [Event(21, Keywords = Keywords.Debug)]
+ public void RunningContinuationList(int TaskID, int Index, long Object)
+ {
+ if (Debug)
+ WriteEvent(21, TaskID, Index, Object);
+ }
+
+ [Event(23, Keywords = Keywords.Debug)]
+ public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(23, Facility, Message); }
+
+ [Event(24, Keywords = Keywords.Debug)]
+ public void DebugFacilityMessage1(string Facility, string Message, string Value1) { WriteEvent(24, Facility, Message, Value1); }
+
+ [Event(25, Keywords = Keywords.DebugActivityId)]
+ public void SetActivityId(Guid NewId)
+ {
+ if (DebugActivityId)
+ WriteEvent(25, NewId);
+ }
+
+ [Event(26, Keywords = Keywords.Debug)]
+ public void NewID(int TaskID)
+ {
+ if (Debug)
+ WriteEvent(26, TaskID);
+ }
+
+ [NonEvent]
+ public void IncompleteAsyncMethod(IAsyncStateMachineBox stateMachineBox)
+ {
+ System.Diagnostics.Debug.Assert(stateMachineBox != null);
+ if (IsEnabled(EventLevel.Warning, Keywords.AsyncMethod))
+ {
+ IAsyncStateMachine stateMachine = stateMachineBox.GetStateMachineObject();
+ if (stateMachine != null)
+ {
+ string description = AsyncMethodBuilderCore.GetAsyncStateMachineDescription(stateMachine);
+ IncompleteAsyncMethod(description);
+ }
+ }
+ }
+
+ [Event(27, Level = EventLevel.Warning, Keywords = Keywords.AsyncMethod)]
+ private void IncompleteAsyncMethod(string stateMachineDescription) =>
+ WriteEvent(27, stateMachineDescription);
+
+ /// <summary>
+ /// Activity IDs are GUIDS but task IDS are integers (and are not unique across appdomains
+ /// This routine creates a process wide unique GUID given a task ID
+ /// </summary>
+ internal static Guid CreateGuidForTaskID(int taskID)
+ {
+ // The thread pool generated a process wide unique GUID from a task GUID by
+ // using the taskGuid, the appdomain ID, and 8 bytes of 'randomization' chosen by
+ // using the last 8 bytes as the provider GUID for this provider.
+ // These were generated by CreateGuid, and are reasonably random (and thus unlikley to collide
+ uint pid = EventSource.s_currentPid;
+ return new Guid(taskID,
+ (short)DefaultAppDomainID, (short)(DefaultAppDomainID >> 16),
+ (byte)pid, (byte)(pid >> 8), (byte)(pid >> 16), (byte)(pid >> 24),
+ 0xff, 0xdc, 0xd7, 0xb5);
+ }
+ }
+}