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);
                    }
                }
            }
        }
Beispiel #5
0
        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);
        }
Beispiel #9
0
        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);
        }