From f92dc182d75c60abbfd5a20020462b11ae26e529 Mon Sep 17 00:00:00 2001 From: stephentoub Date: Thu, 11 Feb 2016 16:41:43 -0500 Subject: [PATCH] Fix access to Task.Id while finishing continuations Task.Id is lazily-initialized with an interlocked operation and we strive to avoid accessing it anywhere in Task's internals on hot paths, but apparently when some ETW logging was added around continuations, calls were added that access Task.Id even if logging is disabled. This is accounting for ~30% of the cycles consumed in a TCS Task's lifecycle! This commit fixes it by making sure these accesses to Id are guarded. --- src/mscorlib/src/System/Threading/Tasks/Task.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs index 7501fb2..e852798 100644 --- a/src/mscorlib/src/System/Threading/Tasks/Task.cs +++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs @@ -3585,7 +3585,12 @@ namespace System.Threading.Tasks // Atomically store the fact that this task is completing. From this point on, the adding of continuations will // result in the continuations being run/launched directly rather than being added to the continuation list. object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel); - TplEtwProvider.Log.RunningContinuation(Id, continuationObject); + TplEtwProvider etw = TplEtwProvider.Log; + bool tplEtwProviderLoggingEnabled = etw.IsEnabled(); + if (tplEtwProviderLoggingEnabled) + { + etw.RunningContinuation(Id, continuationObject); + } // If continuationObject == null, then we don't have any continuations to process if (continuationObject != null) @@ -3658,7 +3663,10 @@ namespace System.Threading.Tasks var tc = continuations[i] as StandardTaskContinuation; if (tc != null && (tc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0) { - TplEtwProvider.Log.RunningContinuationList(Id, i, tc); + if (tplEtwProviderLoggingEnabled) + { + etw.RunningContinuationList(Id, i, tc); + } continuations[i] = null; // so that we can skip this later tc.Run(this, bCanInlineContinuations); } @@ -3672,7 +3680,10 @@ namespace System.Threading.Tasks object currentContinuation = continuations[i]; if (currentContinuation == null) continue; continuations[i] = null; // to enable free'ing up memory earlier - TplEtwProvider.Log.RunningContinuationList(Id, i, currentContinuation); + if (tplEtwProviderLoggingEnabled) + { + etw.RunningContinuationList(Id, i, currentContinuation); + } // If the continuation is an Action delegate, it came from an await continuation, // and we should use AwaitTaskContinuation to run it. -- 2.7.4