Skip to content

Commit 3b98e80

Browse files
author
Lifeng Lu
committed
Retain the empty potentialUnreachable collection to reduce potential allocation
1 parent d75c448 commit 3b98e80

File tree

2 files changed

+18
-23
lines changed

2 files changed

+18
-23
lines changed

src/Microsoft.VisualStudio.Threading/JoinableTask.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,12 @@ internal WeakReference<JoinableTask> WeakSelf
389389
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
390390
internal HashSet<IJoinableTaskDependent>? PotentialUnreachableDependents { get; set; }
391391

392+
/// <summary>
393+
/// Gets a value indicating whether PotentialUnreachableDependents is empty.
394+
/// </summary>
395+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
396+
internal bool HasPotentialUnreachableDependents => this.PotentialUnreachableDependents is object && this.PotentialUnreachableDependents.Count != 0;
397+
392398
/// <summary>
393399
/// Gets the flags set on this task.
394400
/// </summary>
@@ -711,7 +717,7 @@ internal void Post(SendOrPostCallback d, object? state, bool mainThreadAffinitiz
711717
eventsNeedNotify = new List<AsyncManualResetEvent>(tasksNeedNotify.Count);
712718
foreach (JoinableTask? taskToNotify in tasksNeedNotify)
713719
{
714-
if (mainThreadQueueUpdated && taskToNotify != this && taskToNotify.pendingEventCount == 0 && taskToNotify.PotentialUnreachableDependents != null)
720+
if (mainThreadQueueUpdated && taskToNotify != this && taskToNotify.pendingEventCount == 0 && taskToNotify.HasPotentialUnreachableDependents)
715721
{
716722
// It is not essential to clean up potential unreachable dependent items before triggering the UI thread,
717723
// because dependencies may change, and invalidate this work. However, we try to do this work in the background thread to make it less likely
@@ -1101,7 +1107,7 @@ private bool TryDequeueSelfOrDependencies(bool onMainThread, ref HashSet<IJoinab
11011107
{
11021108
if (this.pendingEventSource.TryGetTarget(out JoinableTask? pendingSource) &&
11031109
(pendingSource == this ||
1104-
(this.PotentialUnreachableDependents == null && JoinableTaskDependencyGraph.IsDependingSynchronousTask(pendingSource, this))))
1110+
(!this.HasPotentialUnreachableDependents && JoinableTaskDependencyGraph.IsDependingSynchronousTask(pendingSource, this))))
11051111
{
11061112
ExecutionQueue? queue = onMainThread ? pendingSource.mainThreadQueue : pendingSource.threadPoolQueue;
11071113
if (queue is object && !queue.IsCompleted && queue.TryDequeue(out work))
@@ -1131,19 +1137,15 @@ private bool TryDequeueSelfOrDependencies(bool onMainThread, ref HashSet<IJoinab
11311137
bool foundWork = TryDequeueSelfOrDependencies(this, onMainThread, visited, out work);
11321138

11331139
HashSet<IJoinableTaskDependent>? visitedNodes = visited;
1134-
if (visitedNodes != null && this.PotentialUnreachableDependents != null)
1140+
if (visitedNodes != null && this.HasPotentialUnreachableDependents)
11351141
{
11361142
// We walked the dependencies tree and use this information to update the PotentialUnreachableDependents list.
1137-
this.PotentialUnreachableDependents.RemoveWhere(n => visitedNodes.Contains(n));
1138-
if (this.PotentialUnreachableDependents.Count == 0)
1139-
{
1140-
this.PotentialUnreachableDependents = null;
1141-
}
1143+
this.PotentialUnreachableDependents!.RemoveWhere(n => visitedNodes.Contains(n));
11421144

1143-
if (!foundWork && this.PotentialUnreachableDependents != null)
1145+
if (!foundWork && this.PotentialUnreachableDependents.Count > 0)
11441146
{
11451147
JoinableTaskDependencyGraph.RemoveUnreachableDependentItems(this, this.PotentialUnreachableDependents, visitedNodes);
1146-
this.PotentialUnreachableDependents = null;
1148+
this.PotentialUnreachableDependents.Clear();
11471149
}
11481150
}
11491151

src/Microsoft.VisualStudio.Threading/JoinableTaskDependencyGraph.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -236,20 +236,20 @@ internal static bool CleanUpPotentialUnreachableDependentItems(JoinableTask sync
236236
// the reference count, we will calculate the entire reachable tree from the root. That will
237237
// tell us the exactly tasks which need track the synchronous task, and we will clean up the rest.
238238
HashSet<IJoinableTaskDependent>? possibleUnreachableItems = syncTask.PotentialUnreachableDependents;
239-
if (possibleUnreachableItems is object)
239+
if (possibleUnreachableItems is object && possibleUnreachableItems.Count > 0)
240240
{
241241
var reachableNodes = new HashSet<IJoinableTaskDependent>();
242242
var syncTaskItem = (IJoinableTaskDependent)syncTask;
243243

244244
JoinableTaskDependentData.ComputeSelfAndDescendentOrJoinedJobsAndRemainTasks(syncTaskItem, reachableNodes, possibleUnreachableItems);
245245

246-
syncTask.PotentialUnreachableDependents = null;
247246
allReachableNodes = reachableNodes;
248247

249248
// force to remove all invalid items
250249
if (possibleUnreachableItems.Count > 0)
251250
{
252251
JoinableTaskDependentData.RemoveUnreachableDependentItems(syncTask, possibleUnreachableItems, reachableNodes);
252+
possibleUnreachableItems.Clear();
253253

254254
return true;
255255
}
@@ -600,7 +600,7 @@ internal bool HasMainThreadSynchronousTaskWaiting(IJoinableTaskDependent taskIte
600600
DependentSynchronousTask? nextTrackingTask = existingTaskTracking.Next;
601601
if ((existingTaskTracking.SynchronousTask.State & JoinableTask.JoinableTaskFlags.SynchronouslyBlockingMainThread) == JoinableTask.JoinableTaskFlags.SynchronouslyBlockingMainThread)
602602
{
603-
if (existingTaskTracking.SynchronousTask.PotentialUnreachableDependents != null)
603+
if (existingTaskTracking.SynchronousTask.HasPotentialUnreachableDependents)
604604
{
605605
// This might remove the current tracking item from the linked list, so we capture next node first.
606606
if (!CleanUpPotentialUnreachableDependentItems(existingTaskTracking.SynchronousTask, out HashSet<IJoinableTaskDependent>? allReachableNodes) ||
@@ -642,12 +642,9 @@ internal void OnTaskCompleted(IJoinableTaskDependent thisDependentNode)
642642
RemoveDependingSynchronousTaskFrom(childrenTasks, existingTaskTracking.SynchronousTask, false);
643643

644644
HashSet<IJoinableTaskDependent>? potentialUnreachableDependents = existingTaskTracking.SynchronousTask.PotentialUnreachableDependents;
645-
if (potentialUnreachableDependents != null)
645+
if (potentialUnreachableDependents is object && potentialUnreachableDependents.Count > 0)
646646
{
647-
if (potentialUnreachableDependents.Remove(thisDependentNode) && potentialUnreachableDependents.Count == 0)
648-
{
649-
existingTaskTracking.SynchronousTask.PotentialUnreachableDependents = null;
650-
}
647+
potentialUnreachableDependents.Remove(thisDependentNode);
651648
}
652649

653650
existingTaskTracking = existingTaskTracking.Next;
@@ -879,7 +876,7 @@ private static void RemoveDependingSynchronousTaskFrom(IReadOnlyList<IJoinableTa
879876

880877
RemoveUnreachableDependentItems(syncTask, remainNodes, reachableNodes);
881878

882-
syncTask.PotentialUnreachableDependents = null;
879+
syncTask.PotentialUnreachableDependents?.Clear();
883880
}
884881
else if (syncTask.PotentialUnreachableDependents != remainNodes)
885882
{
@@ -890,10 +887,6 @@ private static void RemoveDependingSynchronousTaskFrom(IReadOnlyList<IJoinableTa
890887
syncTask.PotentialUnreachableDependents = remainNodes;
891888
}
892889
}
893-
else
894-
{
895-
syncTask.PotentialUnreachableDependents = null;
896-
}
897890
}
898891

899892
/// <summary>

0 commit comments

Comments
 (0)