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