private static List <Tuple <XElement, XElement> > CreateNodeLabels(Dictionary <JoinableTask, XElement> tasksAndElements) { Requires.NotNull(tasksAndElements, nameof(tasksAndElements)); var result = new List <Tuple <XElement, XElement> >(); foreach (KeyValuePair <JoinableTask, XElement> tasksAndElement in tasksAndElements) { JoinableTask?pendingTask = tasksAndElement.Key; XElement? node = tasksAndElement.Value; int queueIndex = 0; foreach (JoinableTaskFactory.SingleExecuteProtector?pendingTasksElement in pendingTask.MainThreadQueueContents) { queueIndex++; XElement?callstackNode = Dgml.Node(node.Attribute("Id").Value + "MTQueue#" + queueIndex, GetAsyncReturnStack(pendingTasksElement)); XElement?callstackLink = Dgml.Link(callstackNode, node); result.Add(Tuple.Create(callstackNode, callstackLink)); } foreach (JoinableTaskFactory.SingleExecuteProtector?pendingTasksElement in pendingTask.ThreadPoolQueueContents) { queueIndex++; XElement?callstackNode = Dgml.Node(node.Attribute("Id").Value + "TPQueue#" + queueIndex, GetAsyncReturnStack(pendingTasksElement)); XElement?callstackLink = Dgml.Link(callstackNode, node); result.Add(Tuple.Create(callstackNode, callstackLink)); } } return(result); }
private static XDocument CreateTemplateDgml(out XElement nodes, out XElement links) { return(Dgml.Create(out nodes, out links) .WithCategories( Dgml.Category("MainThreadBlocking", "Blocking main thread", background: "#FFF9FF7F", isTag: true), Dgml.Category("NonEmptyQueue", "Non-empty queue", background: "#FFFF0000", isTag: true))); }
private static XDocument CreateDgml(out XElement nodes, out XElement links) { return(Dgml.Create(out nodes, out links, layout: "ForceDirected", direction: "BottomToTop") .WithCategories( Dgml.Category("Waiting", icon: "pack://application:,,,/Microsoft.VisualStudio.Progression.GraphControl;component/Icons/kpi_yellow_cat1_large.png"), Dgml.Category("Issued", icon: "pack://application:,,,/Microsoft.VisualStudio.Progression.GraphControl;component/Icons/kpi_green_sym2_large.png"), Dgml.Category("Released", icon: "pack://application:,,,/Microsoft.VisualStudio.Progression.GraphControl;component/Icons/kpi_red_sym2_large.png"), Dgml.Category("ReadLock", background: "#FF7476AF"), Dgml.Category("UpgradeableReadLock", background: "#FFFFBF00"), Dgml.Category("WriteLock", background: "#FFC79393"))); }
protected virtual HangReportContribution GetHangReport() { using (this.NoMessagePumpSynchronizationContext.Apply()) { // It's possible that the hang is due to a deadlock on our own private lock, // so while we're reporting the hang, don't accidentally deadlock ourselves // while trying to do the right thing by taking the lock. bool lockAcquired = false; try { Monitor.TryEnter(this.syncObject, 1000, ref lockAcquired); XElement nodes, links; var dgml = CreateDgml(out nodes, out links); if (!lockAcquired) { nodes.Add(Dgml.Comment("WARNING: failed to acquire our own lock in formulating this report.")); } var liveAwaiterMetadata = new HashSet <AwaiterMetadata>(); liveAwaiterMetadata.UnionWith(this.waitingReaders.Select(a => new AwaiterMetadata(a, AwaiterCollection.Waiting | AwaiterCollection.ReadLock))); liveAwaiterMetadata.UnionWith(this.waitingUpgradeableReaders.Select(a => new AwaiterMetadata(a, AwaiterCollection.Waiting | AwaiterCollection.UpgradeableReadLock))); liveAwaiterMetadata.UnionWith(this.waitingWriters.Select(a => new AwaiterMetadata(a, AwaiterCollection.Waiting | AwaiterCollection.WriteLock))); liveAwaiterMetadata.UnionWith(this.issuedReadLocks.Select(a => new AwaiterMetadata(a, AwaiterCollection.Issued | AwaiterCollection.ReadLock))); liveAwaiterMetadata.UnionWith(this.issuedUpgradeableReadLocks.Select(a => new AwaiterMetadata(a, AwaiterCollection.Issued | AwaiterCollection.UpgradeableReadLock))); liveAwaiterMetadata.UnionWith(this.issuedWriteLocks.Select(a => new AwaiterMetadata(a, AwaiterCollection.Issued | AwaiterCollection.WriteLock))); var liveAwaiters = liveAwaiterMetadata.Select(am => am.Awaiter); var releasedAwaiterMetadata = new HashSet <AwaiterMetadata>(liveAwaiters.SelectMany(GetLockStack).Distinct().Except(liveAwaiters).Select(AwaiterMetadata.Released)); var allAwaiterMetadata = new HashSet <AwaiterMetadata>(liveAwaiterMetadata.Concat(releasedAwaiterMetadata)); // Build the lock stack containers. dgml.WithContainers(allAwaiterMetadata.Select(am => am.GroupId).Distinct().Select(id => Dgml.Container(id, "Lock stack"))); // Add each lock awaiter. nodes.Add(allAwaiterMetadata.Select(am => CreateAwaiterNode(am.Awaiter).WithCategories(am.Categories.ToArray()).ContainedBy(am.GroupId, dgml))); // Link the lock stacks among themselves. links.Add(allAwaiterMetadata.Where(a => a.Awaiter.NestingLock != null).Select(a => Dgml.Link(GetAwaiterId(a.Awaiter.NestingLock), GetAwaiterId(a.Awaiter)))); return(new HangReportContribution( dgml.ToString(), "application/xml", this.GetType().Name + ".dgml")); } finally { if (lockAcquired) { Monitor.Exit(this.syncObject); } } } }
private static XElement CreateAwaiterNode(Awaiter awaiter) { Requires.NotNull(awaiter, nameof(awaiter)); var label = new StringBuilder(); label.AppendLine(awaiter.Kind.ToString()); if (awaiter.Options != LockFlags.None) { label.AppendLine("Options: " + awaiter.Options); } Delegate lockWaitingContinuation; #if DESKTOP if (awaiter.RequestingStackTrace != null) { label.AppendLine(awaiter.RequestingStackTrace.ToString()); } #endif if ((lockWaitingContinuation = awaiter.LockRequestingContinuation) != null) { try { foreach (var frame in lockWaitingContinuation.GetAsyncReturnStackFrames()) { label.AppendLine(frame); } } catch (Exception ex) { // Just eat the exception so we don't crash during a hang report. Report.Fail("GetAsyncReturnStackFrames threw exception: ", ex); } } if (label.Length >= Environment.NewLine.Length) { label.Length -= Environment.NewLine.Length; } XElement element = Dgml.Node(GetAwaiterId(awaiter), label.ToString()); return(element); }
private static ICollection <XElement> CreateCollectionContainingTaskLinks(Dictionary <JoinableTask, XElement> tasks, Dictionary <JoinableTaskCollection, XElement> collections) { Requires.NotNull(tasks, nameof(tasks)); Requires.NotNull(collections, nameof(collections)); var result = new List <XElement>(); foreach (KeyValuePair <JoinableTask, XElement> task in tasks) { foreach (JoinableTaskCollection?collection in task.Key.ContainingCollections) { XElement?collectionElement = collections[collection]; result.Add(Dgml.Link(collectionElement, task.Value).WithCategories("Contains")); } } return(result); }
private static ICollection <XElement> CreatesLinksBetweenNodes(Dictionary <JoinableTask, XElement> pendingTasksElements) { Requires.NotNull(pendingTasksElements, nameof(pendingTasksElements)); var links = new List <XElement>(); foreach (KeyValuePair <JoinableTask, XElement> joinableTaskAndElement in pendingTasksElements) { foreach (JoinableTask?joinedTask in JoinableTaskDependencyGraph.GetAllDirectlyDependentJoinableTasks(joinableTaskAndElement.Key)) { if (pendingTasksElements.TryGetValue(joinedTask, out XElement? joinedTaskElement)) { links.Add(Dgml.Link(joinableTaskAndElement.Value, joinedTaskElement)); } } } return(links); }
private static Dictionary <JoinableTaskCollection, XElement> CreateNodesForJoinableTaskCollections(IEnumerable <JoinableTask> tasks) { Requires.NotNull(tasks, nameof(tasks)); var collectionsSet = new HashSet <JoinableTaskCollection>(tasks.SelectMany(t => t.ContainingCollections)); var result = new Dictionary <JoinableTaskCollection, XElement>(collectionsSet.Count); int collectionId = 0; foreach (JoinableTaskCollection?collection in collectionsSet) { collectionId++; var label = string.IsNullOrEmpty(collection.DisplayName) ? "Collection #" + collectionId : collection.DisplayName; XElement?element = Dgml.Node("Collection#" + collectionId, label, group: "Expanded") .WithCategories("Collection"); result.Add(collection, element); } return(result); }
private static ICollection <XElement> CreatesLinksBetweenNodes(Dictionary <JoinableTask, XElement> pendingTasksElements) { Requires.NotNull(pendingTasksElements, nameof(pendingTasksElements)); var links = new List <XElement>(); foreach (var joinableTaskAndElement in pendingTasksElements) { foreach (var joinedTask in joinableTaskAndElement.Key.ChildOrJoinedJobs) { if (pendingTasksElements.TryGetValue(joinedTask, out XElement joinedTaskElement)) { links.Add(Dgml.Link(joinableTaskAndElement.Value, joinedTaskElement)); } } } return(links); }
private Dictionary <JoinableTask, XElement> CreateNodesForPendingTasks() { var pendingTasksElements = new Dictionary <JoinableTask, XElement>(); lock (this.pendingTasks) { int taskId = 0; foreach (JoinableTask?pendingTask in this.pendingTasks) { taskId++; string methodName = string.Empty; System.Reflection.MethodInfo?entryMethodInfo = pendingTask.EntryMethodInfo; if (entryMethodInfo is object) { methodName = string.Format( CultureInfo.InvariantCulture, " ({0}.{1})", entryMethodInfo.DeclaringType?.FullName, entryMethodInfo.Name); } XElement?node = Dgml.Node("Task#" + taskId, "Task #" + taskId + methodName) .WithCategories("Task"); if (pendingTask.HasNonEmptyQueue) { node.WithCategories("NonEmptyQueue"); } if (pendingTask.State.HasFlag(JoinableTask.JoinableTaskFlags.SynchronouslyBlockingMainThread)) { node.WithCategories("MainThreadBlocking"); } pendingTasksElements.Add(pendingTask, node); } } return(pendingTasksElements); }