1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
7 //
8 // TplEtwProvider.cs
9 //
10 // <OWNER>Microsoft</OWNER>
11 //
12 // EventSource for TPL.
13 //
14 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Text;
19 using System.Security;
20 using System.Security.Permissions;
21 using System.Runtime.CompilerServices;
22 
23 namespace System.Threading.Tasks
24 {
25     using System.Diagnostics.Tracing;
26 
27     /// <summary>Provides an event source for tracing TPL information.</summary>
28     [EventSource(
29         Name = "System.Threading.Tasks.TplEventSource",
30         Guid = "2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5",
31         LocalizationResources = "mscorlib")]
32     internal sealed class TplEtwProvider : EventSource
33     {
34         /// Used to determine if tasks should generate Activity IDs for themselves
35         internal bool TasksSetActivityIds;        // This keyword is set
36         internal bool Debug;
37         private  bool DebugActivityId;
38 
39         /// <summary>
40         /// Get callbacks when the ETW sends us commands`
41         /// </summary>
OnEventCommand(EventCommandEventArgs command)42         protected override void OnEventCommand(EventCommandEventArgs command)
43         {
44             // To get the AsyncCausality events, we need to inform the AsyncCausalityTracer
45             if (command.Command == EventCommand.Enable)
46                 AsyncCausalityTracer.EnableToETW(true);
47             else if (command.Command == EventCommand.Disable)
48                 AsyncCausalityTracer.EnableToETW(false);
49 
50             if (IsEnabled(EventLevel.Informational, Keywords.TasksFlowActivityIds))
51                 ActivityTracker.Instance.Enable();
52             else
53                TasksSetActivityIds = IsEnabled(EventLevel.Informational, Keywords.TasksSetActivityIds);
54 
55             Debug = IsEnabled(EventLevel.Informational, Keywords.Debug);
56             DebugActivityId = IsEnabled(EventLevel.Informational, Keywords.DebugActivityId);
57         }
58 
59         /// <summary>
60         /// Defines the singleton instance for the TPL ETW provider.
61         /// The TPL Event provider GUID is {2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5}.
62         /// </summary>
63         public static TplEtwProvider Log = new TplEtwProvider();
64         /// <summary>Prevent external instantiation.  All logging should go through the Log instance.</summary>
TplEtwProvider()65         private TplEtwProvider() { }
66 
67         /// <summary>Type of a fork/join operation.</summary>
68         public enum ForkJoinOperationType
69         {
70             /// <summary>Parallel.Invoke.</summary>
71             ParallelInvoke=1,
72             /// <summary>Parallel.For.</summary>
73             ParallelFor=2,
74             /// <summary>Parallel.ForEach.</summary>
75             ParallelForEach=3
76         }
77 
78         /// <summary>Configured behavior of a task wait operation.</summary>
79         public enum TaskWaitBehavior : int
80         {
81             /// <summary>A synchronous wait.</summary>
82             Synchronous = 1,
83             /// <summary>An asynchronous await.</summary>
84             Asynchronous = 2
85         }
86 
87         /// <summary>ETW tasks that have start/stop events.</summary>
88         public class Tasks // this name is important for EventSource
89         {
90             /// <summary>A parallel loop.</summary>
91             public const EventTask Loop = (EventTask)1;
92             /// <summary>A parallel invoke.</summary>
93             public const EventTask Invoke = (EventTask)2;
94             /// <summary>Executing a Task.</summary>
95             public const EventTask TaskExecute = (EventTask)3;
96             /// <summary>Waiting on a Task.</summary>
97             public const EventTask TaskWait = (EventTask)4;
98             /// <summary>A fork/join task within a loop or invoke.</summary>
99             public const EventTask ForkJoin = (EventTask)5;
100             /// <summary>A task is scheduled to execute.</summary>
101             public const EventTask TaskScheduled = (EventTask)6;
102             /// <summary>An await task continuation is scheduled to execute.</summary>
103             public const EventTask AwaitTaskContinuationScheduled = (EventTask)7;
104 
105             /// <summary>AsyncCausalityFunctionality.</summary>
106             public const EventTask TraceOperation = (EventTask)8;
107             public const EventTask TraceSynchronousWork = (EventTask)9;
108         }
109 
110         public class Keywords // thisname is important for EventSource
111         {
112             /// <summary>
113             /// Only the most basic information about the workings of the task library
114             /// This sets activity IDS and logs when tasks are schedules (or waits begin)
115             /// But are otherwise silent
116             /// </summary>
117             public const EventKeywords TaskTransfer = (EventKeywords) 1;
118             /// <summary>
119             /// TaskTranser events plus events when tasks start and stop
120             /// </summary>
121             public const EventKeywords Tasks = (EventKeywords) 2;
122             /// <summary>
123             /// Events associted with the higher level parallel APIs
124             /// </summary>
125             public const EventKeywords Parallel = (EventKeywords) 4;
126             /// <summary>
127             /// These are relatively verbose events that effectively just redirect
128             /// the windows AsyncCausalityTracer to ETW
129             /// </summary>
130             public const EventKeywords AsyncCausalityOperation = (EventKeywords) 8;
131             public const EventKeywords AsyncCausalityRelation = (EventKeywords) 0x10;
132             public const EventKeywords AsyncCausalitySynchronousWork = (EventKeywords) 0x20;
133 
134             /// <summary>
135             /// Emit the stops as well as the schedule/start events
136             /// </summary>
137             public const EventKeywords TaskStops = (EventKeywords) 0x40;
138 
139             /// <summary>
140             /// TasksFlowActivityIds indicate that activity ID flow from one task
141             /// to any task created by it.
142             /// </summary>
143             public const EventKeywords TasksFlowActivityIds = (EventKeywords) 0x80;
144 
145             /// <summary>
146             /// TasksSetActivityIds will cause the task operations to set Activity Ids
147             /// This option is incompatible with TasksFlowActivityIds flow is ignored
148             /// if that keyword is set.   This option is likley to be removed in the future
149             /// </summary>
150             public const EventKeywords TasksSetActivityIds = (EventKeywords) 0x10000;
151 
152             /// <summary>
153             /// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future
154             /// </summary>
155             public const EventKeywords Debug = (EventKeywords) 0x20000;
156             /// <summary>
157             /// Relatively Verbose logging meant for debugging the Task library itself.  Will probably be removed in the future
158             /// </summary>
159             public const EventKeywords DebugActivityId = (EventKeywords) 0x40000;
160         }
161 
162         /// <summary>Enabled for all keywords.</summary>
163         private const EventKeywords ALL_KEYWORDS = (EventKeywords)(-1);
164 
165         //-----------------------------------------------------------------------------------
166         //
167         // TPL Event IDs (must be unique)
168         //
169 
170         /// <summary>The beginning of a parallel loop.</summary>
171         private const int PARALLELLOOPBEGIN_ID = 1;
172         /// <summary>The ending of a parallel loop.</summary>
173         private const int PARALLELLOOPEND_ID = 2;
174         /// <summary>The beginning of a parallel invoke.</summary>
175         private const int PARALLELINVOKEBEGIN_ID = 3;
176         /// <summary>The ending of a parallel invoke.</summary>
177         private const int PARALLELINVOKEEND_ID = 4;
178         /// <summary>A task entering a fork/join construct.</summary>
179         private const int PARALLELFORK_ID = 5;
180         /// <summary>A task leaving a fork/join construct.</summary>
181         private const int PARALLELJOIN_ID = 6;
182 
183         /// <summary>A task is scheduled to a task scheduler.</summary>
184         private const int TASKSCHEDULED_ID = 7;
185         /// <summary>A task is about to execute.</summary>
186         private const int TASKSTARTED_ID = 8;
187         /// <summary>A task has finished executing.</summary>
188         private const int TASKCOMPLETED_ID = 9;
189         /// <summary>A wait on a task is beginning.</summary>
190         private const int TASKWAITBEGIN_ID = 10;
191         /// <summary>A wait on a task is ending.</summary>
192         private const int TASKWAITEND_ID = 11;
193         /// <summary>A continuation of a task is scheduled.</summary>
194         private const int AWAITTASKCONTINUATIONSCHEDULED_ID = 12;
195         /// <summary>A continuation of a taskWaitEnd is complete </summary>
196         private const int TASKWAITCONTINUATIONCOMPLETE_ID = 13;
197         /// <summary>A continuation of a taskWaitEnd is complete </summary>
198         private const int TASKWAITCONTINUATIONSTARTED_ID = 19;
199 
200         private const int TRACEOPERATIONSTART_ID       = 14;
201         private const int TRACEOPERATIONSTOP_ID        = 15;
202         private const int TRACEOPERATIONRELATION_ID    = 16;
203         private const int TRACESYNCHRONOUSWORKSTART_ID = 17;
204         private const int TRACESYNCHRONOUSWORKSTOP_ID  = 18;
205 
206 
207         //-----------------------------------------------------------------------------------
208         //
209         // Parallel Events
210         //
211 
212         #region ParallelLoopBegin
213         /// <summary>
214         /// Denotes the entry point for a Parallel.For or Parallel.ForEach loop
215         /// </summary>
216         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
217         /// <param name="OriginatingTaskID">The task ID.</param>
218         /// <param name="ForkJoinContextID">The loop ID.</param>
219         /// <param name="OperationType">The kind of fork/join operation.</param>
220         /// <param name="InclusiveFrom">The lower bound of the loop.</param>
221         /// <param name="ExclusiveTo">The upper bound of the loop.</param>
222         [SecuritySafeCritical]
223         [Event(PARALLELLOOPBEGIN_ID, Level = EventLevel.Informational, ActivityOptions=EventActivityOptions.Recursive,
224          Task = TplEtwProvider.Tasks.Loop, Opcode = EventOpcode.Start)]
ParallelLoopBegin( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ForkJoinContextID, ForkJoinOperationType OperationType, long InclusiveFrom, long ExclusiveTo)225         public void ParallelLoopBegin(
226             int OriginatingTaskSchedulerID, int OriginatingTaskID,      // PFX_COMMON_EVENT_HEADER
227             int ForkJoinContextID, ForkJoinOperationType OperationType, // PFX_FORKJOIN_COMMON_EVENT_HEADER
228             long InclusiveFrom, long ExclusiveTo)
229         {
230             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
231             {
232                 // There is no explicit WriteEvent() overload matching this event's fields. Therefore calling
233                 // WriteEvent() would hit the "params" overload, which leads to an object allocation every time
234                 // this event is fired. To prevent that problem we will call WriteEventCore(), which works with
235                 // a stack based EventData array populated with the event fields.
236                 unsafe
237                 {
238                     EventData* eventPayload = stackalloc EventData[6];
239 
240                     eventPayload[0].Size = sizeof(int);
241                     eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
242                     eventPayload[1].Size = sizeof(int);
243                     eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
244                     eventPayload[2].Size = sizeof(int);
245                     eventPayload[2].DataPointer = ((IntPtr) (&ForkJoinContextID));
246                     eventPayload[3].Size = sizeof(int);
247                     eventPayload[3].DataPointer = ((IntPtr) (&OperationType));
248                     eventPayload[4].Size = sizeof(long);
249                     eventPayload[4].DataPointer = ((IntPtr) (&InclusiveFrom));
250                     eventPayload[5].Size = sizeof(long);
251                     eventPayload[5].DataPointer = ((IntPtr) (&ExclusiveTo));
252 
253                     WriteEventCore(PARALLELLOOPBEGIN_ID, 6, eventPayload);
254                 }
255             }
256         }
257         #endregion
258 
259         #region ParallelLoopEnd
260         /// <summary>
261         /// Denotes the end of a Parallel.For or Parallel.ForEach loop.
262         /// </summary>
263         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
264         /// <param name="OriginatingTaskID">The task ID.</param>
265         /// <param name="ForkJoinContextID">The loop ID.</param>
266         /// <param name="TotalIterations">the total number of iterations processed.</param>
267         [SecuritySafeCritical]
268         [Event(PARALLELLOOPEND_ID, Level = EventLevel.Informational, Task = TplEtwProvider.Tasks.Loop, Opcode = EventOpcode.Stop)]
ParallelLoopEnd( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ForkJoinContextID, long TotalIterations)269         public void ParallelLoopEnd(
270             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
271             int ForkJoinContextID, long TotalIterations)
272         {
273             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
274             {
275                 // There is no explicit WriteEvent() overload matching this event's fields.
276                 // Therefore calling WriteEvent() would hit the "params" overload, which leads to an object allocation every time this event is fired.
277                 // To prevent that problem we will call WriteEventCore(), which works with a stack based EventData array populated with the event fields
278                 unsafe
279                 {
280                     EventData* eventPayload = stackalloc EventData[4];
281 
282                     eventPayload[0].Size = sizeof(int);
283                     eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
284                     eventPayload[1].Size = sizeof(int);
285                     eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
286                     eventPayload[2].Size = sizeof(int);
287                     eventPayload[2].DataPointer = ((IntPtr) (&ForkJoinContextID));
288                     eventPayload[3].Size = sizeof(long);
289                     eventPayload[3].DataPointer = ((IntPtr) (&TotalIterations));
290 
291                     WriteEventCore(PARALLELLOOPEND_ID, 4, eventPayload);
292                 }
293             }
294         }
295         #endregion
296 
297         #region ParallelInvokeBegin
298         /// <summary>Denotes the entry point for a Parallel.Invoke call.</summary>
299         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
300         /// <param name="OriginatingTaskID">The task ID.</param>
301         /// <param name="ForkJoinContextID">The invoke ID.</param>
302         /// <param name="OperationType">The kind of fork/join operation.</param>
303         /// <param name="ActionCount">The number of actions being invoked.</param>
304         [SecuritySafeCritical]
305         [Event(PARALLELINVOKEBEGIN_ID, Level = EventLevel.Informational, ActivityOptions=EventActivityOptions.Recursive,
306          Task = TplEtwProvider.Tasks.Invoke, Opcode = EventOpcode.Start)]
ParallelInvokeBegin( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ForkJoinContextID, ForkJoinOperationType OperationType, int ActionCount)307         public void ParallelInvokeBegin(
308             int OriginatingTaskSchedulerID, int OriginatingTaskID,      // PFX_COMMON_EVENT_HEADER
309             int ForkJoinContextID, ForkJoinOperationType OperationType, // PFX_FORKJOIN_COMMON_EVENT_HEADER
310             int ActionCount)
311         {
312             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
313             {
314                 // There is no explicit WriteEvent() overload matching this event's fields.
315                 // Therefore calling WriteEvent() would hit the "params" overload, which leads to an object allocation every time this event is fired.
316                 // To prevent that problem we will call WriteEventCore(), which works with a stack based EventData array populated with the event fields
317                 unsafe
318                 {
319                     EventData* eventPayload = stackalloc EventData[5];
320 
321                     eventPayload[0].Size = sizeof(int);
322                     eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
323                     eventPayload[1].Size = sizeof(int);
324                     eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
325                     eventPayload[2].Size = sizeof(int);
326                     eventPayload[2].DataPointer = ((IntPtr) (&ForkJoinContextID));
327                     eventPayload[3].Size = sizeof(int);
328                     eventPayload[3].DataPointer = ((IntPtr) (&OperationType));
329                     eventPayload[4].Size = sizeof(int);
330                     eventPayload[4].DataPointer = ((IntPtr) (&ActionCount));
331 
332                     WriteEventCore(PARALLELINVOKEBEGIN_ID, 5, eventPayload);
333                 }
334             }
335         }
336         #endregion
337 
338         #region ParallelInvokeEnd
339         /// <summary>
340         /// Denotes the exit point for a Parallel.Invoke call.
341         /// </summary>
342         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
343         /// <param name="OriginatingTaskID">The task ID.</param>
344         /// <param name="ForkJoinContextID">The invoke ID.</param>
345         [Event(PARALLELINVOKEEND_ID, Level = EventLevel.Informational, Task = TplEtwProvider.Tasks.Invoke, Opcode = EventOpcode.Stop)]
ParallelInvokeEnd( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ForkJoinContextID)346         public void ParallelInvokeEnd(
347             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
348             int ForkJoinContextID)
349         {
350             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
351             {
352                 WriteEvent(PARALLELINVOKEEND_ID, OriginatingTaskSchedulerID, OriginatingTaskID, ForkJoinContextID);
353             }
354         }
355         #endregion
356 
357         #region ParallelFork
358         /// <summary>
359         /// Denotes the start of an individual task that's part of a fork/join context.
360         /// Before this event is fired, the start of the new fork/join context will be marked
361         /// with another event that declares a unique context ID.
362         /// </summary>
363         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
364         /// <param name="OriginatingTaskID">The task ID.</param>
365         /// <param name="ForkJoinContextID">The invoke ID.</param>
366         [Event(PARALLELFORK_ID, Level = EventLevel.Verbose, ActivityOptions=EventActivityOptions.Recursive,
367          Task = TplEtwProvider.Tasks.ForkJoin, Opcode = EventOpcode.Start)]
ParallelFork( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ForkJoinContextID)368         public void ParallelFork(
369             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
370             int ForkJoinContextID)
371         {
372             if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Parallel))
373             {
374                 WriteEvent(PARALLELFORK_ID, OriginatingTaskSchedulerID, OriginatingTaskID, ForkJoinContextID);
375             }
376         }
377         #endregion
378 
379         #region ParallelJoin
380         /// <summary>
381         /// Denotes the end of an individual task that's part of a fork/join context.
382         /// This should match a previous ParallelFork event with a matching "OriginatingTaskID"
383         /// </summary>
384         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
385         /// <param name="OriginatingTaskID">The task ID.</param>
386         /// <param name="ForkJoinContextID">The invoke ID.</param>
387         [Event(PARALLELJOIN_ID, Level = EventLevel.Verbose, Task = TplEtwProvider.Tasks.ForkJoin, Opcode = EventOpcode.Stop)]
ParallelJoin( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ForkJoinContextID)388         public void ParallelJoin(
389             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
390             int ForkJoinContextID)
391         {
392             if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Parallel))
393             {
394                 WriteEvent(PARALLELJOIN_ID, OriginatingTaskSchedulerID, OriginatingTaskID, ForkJoinContextID);
395             }
396         }
397         #endregion
398 
399         //-----------------------------------------------------------------------------------
400         //
401         // Task Events
402         //
403 
404         // These are all verbose events, so we need to call IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)
405         // call. However since the IsEnabled(l,k) call is more expensive than IsEnabled(), we only want
406         // to incur this cost when instrumentation is enabled. So the Task codepaths that call these
407         // event functions still do the check for IsEnabled()
408 
409         #region TaskScheduled
410         /// <summary>
411         /// Fired when a task is queued to a TaskScheduler.
412         /// </summary>
413         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
414         /// <param name="OriginatingTaskID">The task ID.</param>
415         /// <param name="TaskID">The task ID.</param>
416         /// <param name="CreatingTaskID">The task ID</param>
417         /// <param name="TaskCreationOptions">The options used to create the task.</param>
418         [SecuritySafeCritical]
419         [Event(TASKSCHEDULED_ID, Task = Tasks.TaskScheduled, Version=1, Opcode = EventOpcode.Send,
420          Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
TaskScheduled( int OriginatingTaskSchedulerID, int OriginatingTaskID, int TaskID, int CreatingTaskID, int TaskCreationOptions, int appDomain)421         public void TaskScheduled(
422             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
423             int TaskID, int CreatingTaskID, int TaskCreationOptions, int appDomain)
424         {
425             // IsEnabled() call is an inlined quick check that makes this very fast when provider is off
426             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
427             {
428                 unsafe
429                 {
430                     EventData* eventPayload = stackalloc EventData[5];
431                     eventPayload[0].Size = sizeof(int);
432                     eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
433                     eventPayload[1].Size = sizeof(int);
434                     eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
435                     eventPayload[2].Size = sizeof(int);
436                     eventPayload[2].DataPointer = ((IntPtr) (&TaskID));
437                     eventPayload[3].Size = sizeof(int);
438                     eventPayload[3].DataPointer = ((IntPtr) (&CreatingTaskID));
439                     eventPayload[4].Size = sizeof(int);
440                     eventPayload[4].DataPointer = ((IntPtr) (&TaskCreationOptions));
441                     if (TasksSetActivityIds)
442                     {
443                         Guid childActivityId = CreateGuidForTaskID(TaskID);
444                         WriteEventWithRelatedActivityIdCore(TASKSCHEDULED_ID, &childActivityId, 5, eventPayload);
445                     }
446                     else
447                         WriteEventCore(TASKSCHEDULED_ID, 5, eventPayload);
448                 }
449             }
450         }
451         #endregion
452 
453         #region TaskStarted
454         /// <summary>
455         /// Fired just before a task actually starts executing.
456         /// </summary>
457         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
458         /// <param name="OriginatingTaskID">The task ID.</param>
459         /// <param name="TaskID">The task ID.</param>
460         [Event(TASKSTARTED_ID,
461          Level = EventLevel.Informational, Keywords = Keywords.Tasks)]
TaskStarted( int OriginatingTaskSchedulerID, int OriginatingTaskID, int TaskID)462         public void TaskStarted(
463             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
464             int TaskID)
465         {
466             if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
467                 WriteEvent(TASKSTARTED_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID);
468         }
469         #endregion
470 
471         #region TaskCompleted
472         /// <summary>
473         /// Fired right after a task finished executing.
474         /// </summary>
475         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
476         /// <param name="OriginatingTaskID">The task ID.</param>
477         /// <param name="TaskID">The task ID.</param>
478         /// <param name="IsExceptional">Whether the task completed due to an error.</param>
479         [SecuritySafeCritical]
480         [Event(TASKCOMPLETED_ID, Version=1,
481          Level = EventLevel.Informational, Keywords = Keywords.TaskStops)]
TaskCompleted( int OriginatingTaskSchedulerID, int OriginatingTaskID, int TaskID, bool IsExceptional)482         public void TaskCompleted(
483             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
484             int TaskID, bool IsExceptional)
485         {
486             if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
487             {
488                 unsafe
489                 {
490                     EventData* eventPayload = stackalloc EventData[4];
491                     Int32 isExceptionalInt = IsExceptional ? 1 : 0;
492                     eventPayload[0].Size = sizeof(int);
493                     eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
494                     eventPayload[1].Size = sizeof(int);
495                     eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
496                     eventPayload[2].Size = sizeof(int);
497                     eventPayload[2].DataPointer = ((IntPtr) (&TaskID));
498                     eventPayload[3].Size = sizeof(int);
499                     eventPayload[3].DataPointer = ((IntPtr) (&isExceptionalInt));
500                     WriteEventCore(TASKCOMPLETED_ID, 4, eventPayload);
501                 }
502             }
503         }
504         #endregion
505 
506        #region TaskWaitBegin
507         /// <summary>
508         /// Fired when starting to wait for a taks's completion explicitly or implicitly.
509         /// </summary>
510         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
511         /// <param name="OriginatingTaskID">The task ID.</param>
512         /// <param name="TaskID">The task ID.</param>
513         /// <param name="Behavior">Configured behavior for the wait.</param>
514         /// <param name="ContinueWithTaskID">If known, if 'TaskID' has a 'continueWith' task, mention give its ID here.
515         ///      0 means unknown.   This allows better visualization of the common sequential chaining case.</param>
516         /// </summary>
517         [SecuritySafeCritical]
518         [Event(TASKWAITBEGIN_ID, Version=3, Task = TplEtwProvider.Tasks.TaskWait, Opcode = EventOpcode.Send,
519          Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
TaskWaitBegin( int OriginatingTaskSchedulerID, int OriginatingTaskID, int TaskID, TaskWaitBehavior Behavior, int ContinueWithTaskID, int appDomain)520         public void TaskWaitBegin(
521             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
522             int TaskID, TaskWaitBehavior Behavior, int ContinueWithTaskID, int appDomain)
523         {
524             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
525             {
526                 unsafe
527                 {
528                     EventData* eventPayload = stackalloc EventData[5];
529                     eventPayload[0].Size = sizeof(int);
530                     eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
531                     eventPayload[1].Size = sizeof(int);
532                     eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
533                     eventPayload[2].Size = sizeof(int);
534                     eventPayload[2].DataPointer = ((IntPtr)(&TaskID));
535                     eventPayload[3].Size = sizeof(int);
536                     eventPayload[3].DataPointer = ((IntPtr)(&Behavior));
537                     eventPayload[4].Size = sizeof(int);
538                     eventPayload[4].DataPointer = ((IntPtr)(&ContinueWithTaskID));
539                     if (TasksSetActivityIds)
540                     {
541                         Guid childActivityId = CreateGuidForTaskID(TaskID);
542                         WriteEventWithRelatedActivityIdCore(TASKWAITBEGIN_ID, &childActivityId, 5, eventPayload);
543                     }
544                     else
545                         WriteEventCore(TASKWAITBEGIN_ID, 5, eventPayload);
546                 }
547             }
548         }
549         #endregion
550 
551         /// <summary>
552         /// Fired when the wait for a tasks completion returns.
553         /// </summary>
554         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
555         /// <param name="OriginatingTaskID">The task ID.</param>
556         /// <param name="TaskID">The task ID.</param>
557         [Event(TASKWAITEND_ID,
558          Level = EventLevel.Verbose, Keywords = Keywords.Tasks)]
TaskWaitEnd( int OriginatingTaskSchedulerID, int OriginatingTaskID, int TaskID)559         public void TaskWaitEnd(
560             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
561             int TaskID)
562         {
563             // Log an event if indicated.
564             if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks))
565                 WriteEvent(TASKWAITEND_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID);
566         }
567 
568         /// <summary>
569         /// Fired when the the work (method) associated with a TaskWaitEnd completes
570         /// </summary>
571         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
572         /// <param name="OriginatingTaskID">The task ID.</param>
573         /// <param name="TaskID">The task ID.</param>
574         [Event(TASKWAITCONTINUATIONCOMPLETE_ID,
575          Level = EventLevel.Verbose, Keywords = Keywords.TaskStops)]
TaskWaitContinuationComplete(int TaskID)576         public void TaskWaitContinuationComplete(int TaskID)
577         {
578             // Log an event if indicated.
579             if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks))
580                 WriteEvent(TASKWAITCONTINUATIONCOMPLETE_ID, TaskID);
581         }
582 
583         /// <summary>
584         /// Fired when the the work (method) associated with a TaskWaitEnd completes
585         /// </summary>
586         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
587         /// <param name="OriginatingTaskID">The task ID.</param>
588         /// <param name="TaskID">The task ID.</param>
589         [Event(TASKWAITCONTINUATIONSTARTED_ID,
590          Level = EventLevel.Verbose, Keywords = Keywords.TaskStops)]
TaskWaitContinuationStarted(int TaskID)591         public void TaskWaitContinuationStarted(int TaskID)
592         {
593             // Log an event if indicated.
594             if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Tasks))
595                 WriteEvent(TASKWAITCONTINUATIONSTARTED_ID, TaskID);
596         }
597 
598         /// <summary>
599         /// Fired when the an asynchronous continuation for a task is scheduled
600         /// </summary>
601         /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
602         /// <param name="OriginatingTaskID">The task ID.</param>
603         /// <param name="TaskID">The activityId for the continuation.</param>
604         [SecuritySafeCritical]
605         [Event(AWAITTASKCONTINUATIONSCHEDULED_ID, Task = Tasks.AwaitTaskContinuationScheduled, Opcode = EventOpcode.Send,
606          Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
AwaitTaskContinuationScheduled( int OriginatingTaskSchedulerID, int OriginatingTaskID, int ContinuwWithTaskId)607         public void AwaitTaskContinuationScheduled(
608             int OriginatingTaskSchedulerID, int OriginatingTaskID,  // PFX_COMMON_EVENT_HEADER
609             int ContinuwWithTaskId)
610         {
611             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
612             {
613                 unsafe
614                 {
615                     EventData* eventPayload = stackalloc EventData[3];
616                     eventPayload[0].Size = sizeof(int);
617                     eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
618                     eventPayload[1].Size = sizeof(int);
619                     eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
620                     eventPayload[2].Size = sizeof(int);
621                     eventPayload[2].DataPointer = ((IntPtr) (&ContinuwWithTaskId));
622                     if (TasksSetActivityIds)
623                     {
624                         Guid continuationActivityId = CreateGuidForTaskID(ContinuwWithTaskId);
625                         WriteEventWithRelatedActivityIdCore(AWAITTASKCONTINUATIONSCHEDULED_ID, &continuationActivityId, 3, eventPayload);
626                     }
627                     else
628                         WriteEventCore(AWAITTASKCONTINUATIONSCHEDULED_ID, 3, eventPayload);
629                 }
630             }
631         }
632 
633         [SecuritySafeCritical]
634         [Event(TRACEOPERATIONSTART_ID, Version=1,
635          Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)]
TraceOperationBegin(int TaskID, string OperationName, long RelatedContext)636         public void TraceOperationBegin(int TaskID, string OperationName, long RelatedContext)
637         {
638             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
639             {
640                 unsafe
641                 {
642                     fixed(char* operationNamePtr = OperationName)
643                     {
644                         EventData* eventPayload = stackalloc EventData[3];
645                         eventPayload[0].Size = sizeof(int);
646                         eventPayload[0].DataPointer = ((IntPtr) (&TaskID));
647 
648                         eventPayload[1].Size = ((OperationName.Length + 1) * 2);
649                         eventPayload[1].DataPointer = ((IntPtr) operationNamePtr);
650 
651                         eventPayload[2].Size = sizeof(long);
652                         eventPayload[2].DataPointer = ((IntPtr) (&RelatedContext));
653                         WriteEventCore(TRACEOPERATIONSTART_ID, 3, eventPayload);
654                     }
655                 }
656             }
657         }
658 
659         [SecuritySafeCritical]
660         [Event(TRACEOPERATIONRELATION_ID, Version=1,
661          Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityRelation)]
TraceOperationRelation(int TaskID, CausalityRelation Relation)662         public void TraceOperationRelation(int TaskID, CausalityRelation Relation)
663         {
664             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityRelation))
665                 WriteEvent(TRACEOPERATIONRELATION_ID, TaskID,(int) Relation);                // optmized overload for this exists
666         }
667 
668         [SecuritySafeCritical]
669         [Event(TRACEOPERATIONSTOP_ID, Version=1,
670          Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)]
TraceOperationEnd(int TaskID, AsyncCausalityStatus Status)671         public void TraceOperationEnd(int TaskID, AsyncCausalityStatus Status)
672         {
673             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
674                 WriteEvent(TRACEOPERATIONSTOP_ID, TaskID,(int) Status);                     // optmized overload for this exists
675         }
676 
677         [SecuritySafeCritical]
678         [Event(TRACESYNCHRONOUSWORKSTART_ID, Version=1,
679          Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)]
TraceSynchronousWorkBegin(int TaskID, CausalitySynchronousWork Work)680         public void TraceSynchronousWorkBegin(int TaskID, CausalitySynchronousWork Work)
681         {
682             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
683                 WriteEvent(TRACESYNCHRONOUSWORKSTART_ID, TaskID,(int) Work);               // optmized overload for this exists
684         }
685 
686         [SecuritySafeCritical]
687         [Event(TRACESYNCHRONOUSWORKSTOP_ID, Version=1,
688          Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)]
TraceSynchronousWorkEnd(CausalitySynchronousWork Work)689         public void TraceSynchronousWorkEnd(CausalitySynchronousWork Work)
690         {
691             if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
692             {
693                 unsafe
694                 {
695                     EventData* eventPayload = stackalloc EventData[1];
696                     eventPayload[0].Size = sizeof(int);
697                     eventPayload[0].DataPointer = ((IntPtr) (&Work));
698 
699                     WriteEventCore(TRACESYNCHRONOUSWORKSTOP_ID, 1, eventPayload);
700                 }
701             }
702         }
703 
704         [NonEvent, System.Security.SecuritySafeCritical]
RunningContinuation(int TaskID, object Object)705         unsafe public void RunningContinuation(int TaskID, object Object) { RunningContinuation(TaskID, (long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref Object))); }
706         [Event(20, Keywords = Keywords.Debug)]
RunningContinuation(int TaskID, long Object)707         private void RunningContinuation(int TaskID, long Object)
708         {
709             if (Debug)
710                 WriteEvent(20, TaskID, Object);
711         }
712 
713         [NonEvent, System.Security.SecuritySafeCritical]
RunningContinuationList(int TaskID, int Index, object Object)714         unsafe public void RunningContinuationList(int TaskID, int Index, object Object) { RunningContinuationList(TaskID, Index, (long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref Object))); }
715 
716         [Event(21, Keywords = Keywords.Debug)]
RunningContinuationList(int TaskID, int Index, long Object)717         public void RunningContinuationList(int TaskID, int Index, long Object)
718         {
719             if (Debug)
720                 WriteEvent(21, TaskID, Index, Object);
721         }
722 
723         [Event(22, Keywords = Keywords.Debug)]
DebugMessage(string Message)724         public void DebugMessage(string Message) { WriteEvent(22, Message); }
725 
726         [Event(23, Keywords = Keywords.Debug)]
DebugFacilityMessage(string Facility, string Message)727         public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(23, Facility, Message); }
728 
729         [Event(24, Keywords = Keywords.Debug)]
DebugFacilityMessage1(string Facility, string Message, string Value1)730         public void DebugFacilityMessage1(string Facility, string Message, string Value1) { WriteEvent(24, Facility, Message, Value1); }
731 
732         [Event(25, Keywords = Keywords.DebugActivityId)]
SetActivityId(Guid NewId)733         public void SetActivityId(Guid NewId)
734         {
735             if (DebugActivityId)
736                 WriteEvent(25, NewId);
737         }
738 
739         [Event(26, Keywords = Keywords.Debug)]
NewID(int TaskID)740         public void NewID(int TaskID)
741         {
742             if (Debug)
743                 WriteEvent(26, TaskID);
744         }
745 
746         /// <summary>
747         /// Activity IDs are GUIDS but task IDS are integers (and are not unique across appdomains
748         /// This routine creates a process wide unique GUID given a task ID
749         /// </summary>
CreateGuidForTaskID(int taskID)750         internal static Guid CreateGuidForTaskID(int taskID)
751         {
752             // The thread pool generated a process wide unique GUID from a task GUID by
753             // using the taskGuid, the appdomain ID, and 8 bytes of 'randomization' chosen by
754             // using the last 8 bytes  as the provider GUID for this provider.
755             // These were generated by CreateGuid, and are reasonably random (and thus unlikley to collide
756             uint pid = EventSource.s_currentPid;
757             int appDomainID = System.Threading.Thread.GetDomainID();
758             return new Guid(taskID,
759                             (short) appDomainID , (short) (appDomainID >> 16),
760                             (byte)pid, (byte)(pid >> 8), (byte)(pid >> 16), (byte)(pid >> 24),
761                             0xff, 0xdc, 0xd7, 0xb5);
762         }
763     }
764 }
765