Example #1
0
        public async Task <Heapshot> TakeHeapshotAndMakeReport()
        {
            var newHeapshot = await TakeHeapshot();

            if (Options.PrintReportTypes.HasFlag(ProfilerOptions.PrintReport.ObjectsTotal))
            {
                Console.WriteLine($"Total objects per type({newHeapshot.Types.Count}):");
                foreach (var heapTypeInfo in newHeapshot.Types.Values.OrderByDescending(p => p.Objects.Count))
                {
                    var name = heapTypeInfo.TypeInfo.Name;
                    if (ShouldReportItem(name))
                    {
                        Console.WriteLine($"{name}:{heapTypeInfo.Objects.Count}");
                    }
                }
            }

            if (Options.PrintReportTypes.HasFlag(ProfilerOptions.PrintReport.ObjectsDiff))
            {
                Heapshot oldHeapshot = lastHeapshot;
                lastHeapshot = newHeapshot;

                if (oldHeapshot == null)
                {
                    Console.WriteLine("No objects diff report on 1st Heapshot.");
                    return(newHeapshot);
                }

                var diffCounter = new List <Tuple <string, int> > ();
                foreach (var kvp in newHeapshot.Types)                //ClassInfos is not Heapshot specific, all heapshot has same
                {
                    var typeId = kvp.Key;
                    var name   = kvp.Value.TypeInfo.Name;

                    int oldCount = oldHeapshot.GetObjectCount(typeId);
                    int newCount = newHeapshot.GetObjectCount(typeId);

                    if (newCount - oldCount != 0)
                    {
                        diffCounter.Add(Tuple.Create(name, newCount - oldCount));
                    }
                }

                Console.WriteLine($"Heapshot diff has {diffCounter.Count} entries:");
                foreach (var diff in diffCounter.OrderByDescending(d => d.Item2))
                {
                    var name = diff.Item1;
                    if (ShouldReportItem(name))
                    {
                        Console.WriteLine($"{name}:{diff.Item2}");
                    }
                }
            }

            return(newHeapshot);

            bool ShouldReportItem(string name) => Options.PrintReportObjectNames.Count == 0 || Options.PrintReportObjectNames.Contains(name);
        }
Example #2
0
        Dictionary <string, LeakItem> DetectLeakedObjects(Heapshot heapshot, bool isCleanup, ResultIterationData previousData, string iterationName)
        {
            if (heapshot == null || ProfilerOptions.Type == ProfilerOptions.ProfilerType.Disabled)
            {
                return(new Dictionary <string, LeakItem> ());
            }

            var trackedLeaks = scenario.GetLeakAttributes(isCleanup);

            if (trackedLeaks.Count == 0)
            {
                return(new Dictionary <string, LeakItem> ());
            }

            Directory.CreateDirectory(graphsDirectory);

            Console.WriteLine("Live objects count per type:");
            var leakedObjects = new Dictionary <string, LeakItem> (trackedLeaks.Count);

            foreach (var kvp in trackedLeaks)
            {
                var name = kvp.Key;

                if (!heapshot.TryGetHeapshotTypeInfo(name, out var heapshotTypeInfo))
                {
                    continue;
                }

                var resultFile = ReportPathsToRoots(heapshot, heapshotTypeInfo, iterationName, out int objectCount);
                if (resultFile == null)
                {
                    // We have determined the leak is not an actual leak.
                    continue;
                }

                // We need to check if the root is finalizer or ephemeron, and not report the value.
                leakedObjects.Add(name, new LeakItem(name, objectCount, resultFile));
            }

            foreach (var kvp in leakedObjects)
            {
                var leak  = kvp.Value;
                int delta = 0;
                if (previousData != null && previousData.Leaks.TryGetValue(kvp.Key, out var previousLeak))
                {
                    int previousCount = previousLeak.Count;
                    delta = leak.Count - previousCount;
                }

                Console.WriteLine("{0}: {1} {2:+0;-#}", leak.ClassName, leak.Count, delta);
            }
            return(leakedObjects);
        }
Example #3
0
        string ReportPathsToRoots(Heapshot heapshot, HeapshotTypeInfo typeInfo, string iterationName, out int objectCount)
        {
            var    visitedRoots = new HashSet <HeapObject> ();
            string outputPath   = null;

            var rootTypeName = typeInfo.TypeInfo.Name;
            var objects      = typeInfo.Objects;

            objectCount = objects.Count;

            // Look for the first object that is definitely leaked.
            foreach (var obj in objects)
            {
                visitedRoots.Clear();
                bool isLeak = false;

                var paths = heapshot.Graph.GetPredecessors(obj, vertex => {
                    if (heapshot.Roots.TryGetValue(vertex.Address, out var heapRootRegisterEvent))
                    {
                        visitedRoots.Add(vertex);
                        isLeak |= IsActualLeakSource(heapRootRegisterEvent.Source);
                    }
                });

                if (outputPath == null && isLeak)
                {
                    var objectRetentionGraph = new AdjacencyGraph <HeapObject, SReversedEdge <HeapObject, Edge <HeapObject> > > ();

                    foreach (var root in visitedRoots)
                    {
                        if (paths.TryGetPath(root, out var edges))
                        {
                            objectRetentionGraph.AddVerticesAndEdgeRange(edges);
                        }
                    }
                    var graphviz = objectRetentionGraph.ToLeakGraphviz(heapshot);

                    var dotPath = Path.Combine(graphsDirectory, iterationName + "_" + rootTypeName + ".dot");
                    outputPath = graphviz.Generate(DotEngine.Instance, dotPath);
                }
                else
                {
                    objectCount--;
                }
            }

            // We have not found a definite leak if outputPath is null.
            return(outputPath);
        }
Example #4
0
        public void Process(Heapshot heapshot, bool isCleanup, string iterationName, Components.AutoTest.AutoTestSession.MemoryStats memoryStats)
        {
            if (heapshot == null)
            {
                return;
            }

            // TODO: Make this async.

            var previousData  = result.Iterations.LastOrDefault();
            var leakedObjects = DetectLeakedObjects(heapshot, isCleanup, previousData, iterationName);
            var leakResult    = new ResultIterationData(iterationName, leakedObjects, memoryStats);

            result.Iterations.Add(leakResult);
        }
Example #5
0
        void ReportMemoryUsage(int iteration)
        {
            //Make sure IDE stops doing what it was doing
            UserInterfaceTests.Ide.WaitForIdeIdle();

            // This is to prevent leaking of AppQuery instances.
            TestService.Session.DisconnectQueries();
            Heapshot heapshot = null;

            if (profilerProcessor != null)
            {
                heapshot = profilerProcessor.TakeHeapshotAndMakeReport().Result;
            }

            var memoryStats = TestService.Session.MemoryStats;

            string iterationName;

            if (iteration == cleanupIteration)
            {
                iterationName = "Cleanup";
            }
            else if (iteration == setupIteration)
            {
                iterationName = "Setup";
            }
            else
            {
                iterationName = string.Format("Run_{0}", iteration + 1);
            }

            Console.WriteLine(iterationName);

            Console.WriteLine("  NonPagedSystemMemory: " + memoryStats.NonPagedSystemMemory);
            Console.WriteLine("  PagedMemory: " + memoryStats.PagedMemory);
            Console.WriteLine("  PagedSystemMemory: " + memoryStats.PagedSystemMemory);
            Console.WriteLine("  PeakVirtualMemory: " + memoryStats.PeakVirtualMemory);
            Console.WriteLine("  PrivateMemory: " + memoryStats.PrivateMemory);
            Console.WriteLine("  VirtualMemory: " + memoryStats.VirtualMemory);
            Console.WriteLine("  WorkingSet: " + memoryStats.WorkingSet);

            Console.WriteLine();

            leakProcessor.Process(heapshot, iteration == cleanupIteration, iterationName, memoryStats);
        }
Example #6
0
 public override void Visit(HeapBeginEvent ev)
 {
     currentHeapshot = new Heapshot();
 }
Example #7
0
        public static GraphvizAlgorithm <HeapObject, TEdge> ToLeakGraphviz <TEdge> (this IEdgeListGraph <HeapObject, TEdge> graph, Heapshot heapshot) where TEdge : IEdge <HeapObject>
        {
            var graphviz = new GraphvizAlgorithm <HeapObject, TEdge> (graph);

            graphviz.FormatVertex += (sender, e) => {
                var currentObj = e.Vertex;

                // Look up the object and set its type name.
                var typeName = currentObj.TypeInfo.Name;

                var formatter = e.VertexFormatter;

                e.VertexFormatter.Label = typeName;
                // Append root information.
                if (heapshot.Roots.TryGetValue(currentObj.Address, out var rootRegisterEvent))
                {
                    e.VertexFormatter.Label = $"{typeName}\\nRoot Kind: {rootRegisterEvent.Source.ToString ()}";
                    e.VertexFormatter.Shape = QuickGraph.Graphviz.Dot.GraphvizVertexShape.Box;
                }
                else
                {
                    e.VertexFormatter.Label = typeName;
                }
            };

            return(graphviz);
        }