예제 #1
0
        /// <summary>
        /// Write one line of type statistics metric. This method adds extra columns for CSV output to see which process, cmd line and time
        /// the data was generated to make it possible to record data in append mode.
        /// </summary>
        /// <param name="allocated">Allocated bytes</param>
        /// <param name="instances">Allocates Intances</param>
        /// <param name="type">Type name</param>
        void WriteTypeStatisticsLine(long allocated, long instances, string type)
        {
            // Default format string for console output.
            // fmt is ignored for CSV output where all columns are simply \t separated.
            string fmt = "{0,-17:N0}\t{1,-17:N0}\t{2}";

            if (IsFirstLine)
            {
                string[] header = new string[] { AllocatedColumnBase + DisplayUnit, InstancesColumn, TypeColumn };

                if (OutputStringWriter.CsvOutput)
                {
                    header = header.Concat(new string[] { ProcessIdColumn, TimeColumn, CommandeLineColumn, AgeColumn, NameColumn, ContextColumn }).ToArray();
                }

                // write header
                OutputStringWriter.FormatAndWriteHeader(fmt, header);
                IsFirstLine = false;
            }

            if (OutputStringWriter.CsvOutput)
            {
                OutputStringWriter.FormatAndWrite(fmt, allocated, instances, type, TargetInfo.IsLiveProcess ? TargetInfo.Pid1.ToString() : "", TimeAndOrDate, CmdLine, TargetInfo.ProcessAgeInSeconds, TargetInfo.ProcessName, Context);
            }
            else
            {
                OutputStringWriter.FormatAndWrite(fmt, allocated, instances == 0 ? "" : (object)instances, type);
            }
        }
예제 #2
0
        public void Execute(int topN, bool bShowAddress)
        {
            Task <StringAnalysisResult> res = Task.Factory.StartNew <StringAnalysisResult>(() => Analyze(Heap, LiveOnly));

            if (Heap2 != null)
            {
                StringAnalysisResult res2 = Analyze(Heap2, LiveOnly);
                PrintDiff(topN, res.Result, res2);
            }
            else
            {
                if (topN > 0)
                {
                    var sorted = res.Result.StringCounts.OrderByDescending(kvp => kvp.Value.InstanceCount).Take(topN);
                    OutputStringWriter.FormatAndWrite("{0}\t{1}\t{2}", "Strings(Count)", $"Waste({DisplayUnit})", "String");
                    string fmt = "{0,-12}\t{1,-11:N0}\t{2}";
                    foreach (var kvp in sorted)
                    {
                        string addressString = bShowAddress ? " 0x" + kvp.Value.SampleAddress.ToString("X") : "";
                        OutputStringWriter.FormatAndWrite(fmt, kvp.Value.InstanceCount, ((kvp.Value.InstanceCount - 1L) * kvp.Value.SizePerInstance) / (long)DisplayUnit, GetShortString(kvp.Key) + addressString);
                    }
                }

                if (!OutputStringWriter.CsvOutput)
                {
                    Console.WriteLine();
                    Console.WriteLine("Summary");
                    Console.WriteLine("==========================================");
                    Console.WriteLine($"Strings                 {res.Result.StringObjectCount,12:N0} count");
                    Console.WriteLine($"Allocated Size          {res.Result.StringsAllocatedInBytes/(long)DisplayUnit,12:N0} {DisplayUnit}");
                    Console.WriteLine($"Waste Duplicate Strings {res.Result.StringWasteInBytes/(long)DisplayUnit,12:N0} {DisplayUnit}");
                }
            }
        }
예제 #3
0
 /// <summary>
 /// Format a type diff format string where only diff, size, size2 and type name are printed to the output.
 /// </summary>
 /// <param name="fmt">Type diff format string.</param>
 /// <param name="unit">Unit in which bytes are printed.</param>
 /// <returns>Delegate which accepts sizeDiff, size1, size2 as long values.</returns>
 Action <string, long, long, long> GetSimpleDiffFormatter(string fmt, DisplayUnit unit)
 {
     return((typeName, sizeInBytesDiff, sizeInBytes1, sizeInBytes2) =>
     {
         long unitDivisor = (long)unit;
         OutputStringWriter.FormatAndWrite(fmt, (long)(sizeInBytesDiff / unitDivisor), "", "", "", (long)(sizeInBytes1 / unitDivisor), (long)(sizeInBytes2 / unitDivisor), "", "", typeName + unit);
     });
 }
예제 #4
0
        /// <summary>
        /// Print type statistics diff.
        /// </summary>
        /// <param name="typeInfos"></param>
        /// <param name="typeInfos2"></param>
        /// <param name="vmmap"></param>
        /// <param name="vmmap2"></param>
        /// <param name="topN"></param>
        /// <param name="orderBySize"></param>
        /// <param name="minCount"></param>
        /// <returns>Allocated memory diff in KB. If VMmap data is present the total allocated memory diff for allocated managed heap, heap, private, file mappings and sharable memory is returned.</returns>
        private int PrintTypeStatisticsDiff(List <TypeInfo> typeInfos, List <TypeInfo> typeInfos2, VMMapData vmmap, VMMapData vmmap2, int topN, int minCount, bool orderBySize)
        {
            int allocatedMemoryInKB = 0;

            TypeDiffStatistics delta = GetDiffStatistics(typeInfos, typeInfos2, orderBySize);

            if (minCount > 0)
            {
                delta.TypeDiffs = delta.TypeDiffs.Where(x => Math.Abs(orderBySize ?  x.InstanceCountDiff : x.AllocatedBytesDiff) > minCount).ToList();
            }

            string fmt = "{0,-12:N0}\t{1,-17:N0}\t{2,-11:N0}\t{3,-11:N0}\t{4,-17:N0}\t{5,-18:N0}" +
                         "\t{6,-14}\t{7,-15}\t{8}";

            OutputStringWriter.FormatAndWriteHeader(fmt, $"Delta({DisplayUnit})", "Delta(Instances)", "Instances", "Instances2", $"Allocated({DisplayUnit})", $"Allocated2({DisplayUnit})",
                                                    "AvgSize(Bytes)", "AvgSize2(Bytes)", "Type");

            long unitDivisor = (long)DisplayUnit;

            if (topN > 0)
            {
                foreach (var diff in delta.TypeDiffs.Take(topN))
                {
                    if (diff.Name == FreeTypeName)
                    {
                        continue;
                    }


                    OutputStringWriter.FormatAndWrite(fmt, diff.AllocatedBytesDiff / unitDivisor, diff.InstanceCountDiff, diff?.Info.SafeCount(), diff?.Info2.SafeCount(), diff?.Info.TotalSize() / unitDivisor,
                                                      diff?.Info2.TotalSize() / unitDivisor, diff?.Info?.AverageSizePerInstance, diff?.Info2?.AverageSizePerInstance, diff.Name);
                }
            }

            allocatedMemoryInKB = (int)(delta.DeltaBytes / (long)DisplayUnit.KB);
            OutputStringWriter.FormatAndWrite(fmt, delta.DeltaBytes / unitDivisor, delta.DeltaInstances, delta.Count, delta.Count2, delta.SizeInBytes / unitDivisor,
                                              delta.SizeInBytes2 / unitDivisor, "", "", ManagedHeapAllocated);
            long heap1Size = Heap.GetTotalHeapSize();
            long heap2Size = Heap2.GetTotalHeapSize();

            OutputStringWriter.FormatAndWrite(fmt, (heap2Size - heap1Size) / unitDivisor, 0, 0, 0, heap1Size / unitDivisor, heap2Size / unitDivisor, "", "", ManagedHeapSize);

            if (vmmap != null && vmmap2 != null && vmmap.HasValues && vmmap2.HasValues)
            {
                var diff = vmmap2 - vmmap;
                WriteVMMapDataDiff(GetSimpleDiffFormatter(fmt, DisplayUnit), vmmap, vmmap2, diff);
                OutputStringWriter.FormatAndWrite(fmt, (diff.AllocatedBytesWithoutManagedHeap + delta.DeltaBytes) / unitDivisor, "", "", "",
                                                  (delta.SizeInBytes + vmmap.AllocatedBytesWithoutManagedHeap) / unitDivisor, (vmmap2.AllocatedBytesWithoutManagedHeap + delta.SizeInBytes2) / unitDivisor, ""
                                                  , "", AllocatedTotal);

                // When VMMap data is present add the other memory types which usually leak as well also to the allocation number.
                allocatedMemoryInKB += (int)(diff.AllocatedBytesWithoutManagedHeap / (long)DisplayUnit.KB);
            }

            return(allocatedMemoryInKB);
        }
예제 #5
0
        private void PrintDiff(int topN, StringAnalysisResult res, StringAnalysisResult res2)
        {
            var top  = res.StringCounts.OrderByDescending(kvp => kvp.Value.InstanceCount).Take(topN).ToDictionary(x => x.Key, x => x.Value);
            var top2 = res2.StringCounts.OrderByDescending(kvp => kvp.Value.InstanceCount).Take(topN).ToDictionary(x => x.Key, x => x.Value);

            HashSet <string>  uniqueStringValues = new HashSet <string>(top.Select(x => x.Key).Concat(top2.Select(x => x.Key)).ToArray());
            List <StringDiff> diffs = new List <StringDiff>();

            foreach (var stringValue in uniqueStringValues)
            {
                ObjectStatistics stat  = null;
                ObjectStatistics stat2 = null;
                top.TryGetValue(stringValue, out stat);
                top2.TryGetValue(stringValue, out stat2);
                diffs.Add(new StringDiff
                {
                    DiffInBytes       = (stat2 != null ? stat2.AllocatedInBytes : 0) - (stat != null ? stat.AllocatedInBytes : 0),
                    InstanceDiffCount = (stat2 != null ? stat2.InstanceCount : 0) - (stat != null ? stat.InstanceCount : 0),
                    Stat  = stat,
                    Stat2 = stat2,
                    Value = stringValue
                });
            }

            var sortedDiffs = diffs.OrderByDescending(x => Math.Abs(x.DiffInBytes)).ToArray();

            Console.WriteLine("String Allocation Diff Statistics");
            string fmtString = "{0,-12:N0}\t{1,17:N0}\t{2,-11:N0}\t{3,-11:N0}\t{4,-17:N0}\t{5,-18:N0}\t{6}";

            OutputStringWriter.FormatAndWrite(fmtString, $"Delta({DisplayUnit})", "Delta(Instances)", "Instances", "Instances2", $"Allocated({DisplayUnit})", $"Allocated2({DisplayUnit})", "Value");

            long displayUnitDiv = (long)DisplayUnit;

            foreach (var diff in sortedDiffs)
            {
                OutputStringWriter.FormatAndWrite(fmtString, diff.DiffInBytes / displayUnitDiv, diff.InstanceDiffCount, diff?.Stat?.InstanceCount, diff?.Stat2?.InstanceCount, diff?.Stat?.AllocatedInBytes / displayUnitDiv, diff?.Stat2?.AllocatedInBytes / displayUnitDiv, GetShortString(diff.Value));
            }

            var deltaCount = res2.StringObjectCount - res.StringObjectCount;
            var deltaWaste = res2.StringWasteInBytes - res.StringWasteInBytes;
            var deltaBytes = res2.StringsAllocatedInBytes - res.StringsAllocatedInBytes;

            OutputStringWriter.FormatAndWrite(fmtString, deltaBytes / displayUnitDiv, deltaCount, res.StringObjectCount, res2.StringObjectCount,
                                              res.StringsAllocatedInBytes / displayUnitDiv, res2.StringsAllocatedInBytes / displayUnitDiv, "Strings(Total)");
        }
예제 #6
0
        private void Run()
        {
            AddProcessStartDirectoryToPath();

            MemAnalyzerBase analyzer = null;

            ShowHelpMessage = false; // When we now throw exceptions it is not due to wrong command line arguments.
            try
            {
                TargetInformation.LoadProcessRenameFile(ProcessRenameFile);


                if (!String.IsNullOrEmpty(OutFile))
                {
                    OutputStringWriter.CsvOutput          = true;
                    OutputStringWriter.DisableExcelCSVSep = DisableExcelCSVSep;
                    var info = new FileInfo(OutFile);

                    // skip header if file has already content
                    if (info.Exists && info.Length > 0)
                    {
                        OutputStringWriter.SuppressHeader = true;
                    }

                    // when child process is spawned do not print the same message twice
                    if (!IsChild && !IsSilent)
                    {
                        Console.WriteLine($"Writing output to csv file {OutFile}. {(OverWriteOutFile || !info.Exists ? "" : "File contents are appended.")}");
                    }

                    FileStream file = new FileStream(OutFile, (OverWriteOutFile || TargetInformation.IsProcessCompare) ? FileMode.Create : FileMode.Append);
                    OutputStringWriter.Output = new StreamWriter(file);
                }
                analyzer = CreateAnalyzer(Action);

                switch (Action)
                {
                case Actions.None:
                    Help("No command specified.");
                    break;

                case Actions.DumpTypesByCount:
                    int?allocatedKB = (analyzer as MemAnalyzer)?.DumpTypes(TopN, false, MinCount);
                    if (allocatedKB != null)
                    {
                        ReturnCode = allocatedKB.Value;
                    }
                    break;

                case Actions.DumpTypesBySize:
                    allocatedKB = (analyzer as MemAnalyzer)?.DumpTypes(TopN, true, MinCount);
                    if (allocatedKB != null)
                    {
                        ReturnCode = allocatedKB.Value;
                    }
                    break;

                case Actions.DumpStrings:
                    (analyzer as StringStatisticsCommand)?.Execute(TopN, ShowAddress);
                    break;

                case Actions.ProcDump:
                    DumpCreator dumper = new DumpCreator(IsDebug, VerifyDump);
                    dumper.Dump(ProcDumpArgs);
                    break;

                default:
                    throw new NotSupportedException(String.Format("Command {0} is not recognized as a valid command", this.Action));
                }
            }
            finally
            {
                OutputStringWriter.Flush();

                if (analyzer != null)
                {
                    analyzer.Dispose();
                }
                if (Target != null)
                {
                    Target.Dispose();
                }
                if (Target2 != null)
                {
                    Target2.Dispose();
                }
            }
        }