Esempio n. 1
0
        /// <summary>
        /// Dump types by size or by count.
        /// </summary>
        /// <param name="topN">Only print the first N types ordered by size or count.</param>
        /// <param name="orderBySize">If true types are sorted by size. Otherwise by count.</param>
        /// <returns>Allocated memory in KB if VMMap data is available. Otherwise only the allocated managed heap size in KB is returned.</returns>
        /// <remarks>The returned value is returned, if no other error has occurred from the Main method. That allows test automation to trigger e.g. a dump of
        /// a leak was detected or to automatically enable memory profiling if the allocated memory reached a threshold.</remarks>
        public int DumpTypes(int topN, bool orderBySize, int minCount)
        {
            var typeInfosTask       = Task.Factory.StartNew(() => GetTypeStatistics(Heap, LiveOnly));
            int allocatedMemoryInKB = 0;

            if (Heap2 != null)
            {
                var typeInfos2 = GetTypeStatistics(Heap2, LiveOnly);

                VMMapData vmmap  = null;
                VMMapData vmmap2 = null;

                if (this.GetVMMapData)
                {
                    vmmap2 = GetVMMapDataFromProcess(false, TargetInfo, Heap2);
                    typeInfosTask.Wait();

                    vmmap = GetVMMapDataFromProcess(true, TargetInfo, Heap);
                }

                // Get allocated diff
                allocatedMemoryInKB = PrintTypeStatisticsDiff(typeInfosTask.Result, typeInfos2, vmmap, vmmap2, topN, minCount, orderBySize);
            }
            else
            {
                // get allocated memory
                allocatedMemoryInKB = PrintTypeStatistics(topN, minCount, orderBySize, typeInfosTask);
            }

            return(allocatedMemoryInKB);
        }
Esempio n. 2
0
        /// <summary>
        /// For diffs subtraction is useful.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static VMMapData operator -(VMMapData x, VMMapData y)
        {
            var lret = new VMMapData
            {
                Committed_DllBytes         = x.Committed_DllBytes - y.Committed_DllBytes,
                Committed_HeapBytes        = x.Committed_HeapBytes - y.Committed_HeapBytes,
                Committed_ManagedHeapBytes = x.Committed_ManagedHeapBytes - y.Committed_ManagedHeapBytes,
                Committed_MappedFileBytes  = x.Committed_MappedFileBytes - y.Committed_MappedFileBytes,
                Committed_PageTable        = x.Committed_PageTable - y.Committed_PageTable,
                Committed_PrivateBytes     = x.Committed_PrivateBytes - y.Committed_PrivateBytes,
                Committed_ShareableBytes   = x.Committed_ShareableBytes - y.Committed_ShareableBytes,
                Committed_Stack            = x.Committed_Stack - y.Committed_Stack,

                LargestFreeBlockBytes     = x.LargestFreeBlockBytes - y.LargestFreeBlockBytes,
                Reserved_DllBytes         = x.Reserved_DllBytes - y.Reserved_DllBytes,
                Reserved_HeapBytes        = x.Reserved_HeapBytes - y.Reserved_HeapBytes,
                Reserved_ManagedHeapBytes = x.Reserved_ManagedHeapBytes - y.Reserved_ManagedHeapBytes,
                Reserved_MappedFileBytes  = x.Reserved_MappedFileBytes - y.Reserved_MappedFileBytes,
                Reserved_PageTable        = x.Reserved_PageTable - y.Reserved_PageTable,
                Reserved_PrivateBytes     = x.Reserved_PrivateBytes - y.Reserved_PrivateBytes,
                Reserved_ShareableBytes   = x.Reserved_ShareableBytes - y.Reserved_ShareableBytes,
                Reserved_Stack            = x.Reserved_Stack - y.Reserved_Stack
            };

            return(lret);
        }
Esempio n. 3
0
 /// <summary>
 /// Write VMMap data with given formatter function.
 /// </summary>
 /// <param name="formatter"></param>
 /// <param name="vm"></param>
 void WriteVMMapData(Action <string, long> formatter, VMMapData vm)
 {
     // free blocks only play a role in x86
     if (vm.LargestFreeBlockBytes < 4 * 1024 * 1024 * 1024L)
     {
         formatter(VMMapData.Col_Reserved_LargestFreeBlock, vm.LargestFreeBlockBytes);
     }
     formatter(VMMapData.Col_Reserved_Stack, vm.Reserved_Stack);
     formatter(VMMapData.Col_Committed_Dll, vm.Committed_DllBytes);
     formatter(VMMapData.Col_Committed_Heap, vm.Committed_HeapBytes);
     formatter(VMMapData.Col_Committed_MappedFile, vm.Committed_MappedFileBytes);
     formatter(VMMapData.Col_Committed_Private, vm.Committed_PrivateBytes);
     formatter(VMMapData.Col_Committed_Shareable, vm.Committed_ShareableBytes);
     formatter(VMMapData.Col_Committed_Total, vm.TotalCommittedBytes);
 }
Esempio n. 4
0
        /// <summary>
        /// Print type statistics. If output is a CSV file time and process information are appended to allow subsequent writes into one big CSV file for long data series.
        /// </summary>
        /// <param name="topN"></param>
        /// <param name="orderBySize"></param>
        /// <param name="typeInfosTask"></param>
        /// <returns>Allocated memory 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 PrintTypeStatistics(int topN, int minCount, bool orderBySize, Task <List <TypeInfo> > typeInfosTask)
        {
            int allocatedMemoryInKB = 0;
            var typeInfos           = typeInfosTask.Result;

            if (minCount > 0)
            {
                typeInfos = typeInfos.Where(x => x.Count > minCount).ToList();
            }
            typeInfos.Sort((x, y) => orderBySize ? y.AllocatedSizeInBytes.CompareTo(x.AllocatedSizeInBytes) : y.Count.CompareTo(x.Count));

            // can be null if only live objects are considered.
            var free = typeInfos.FirstOrDefault(x => x.Name == FreeTypeName);

            if (topN > 0)
            {
                foreach (var type in typeInfos.Take(topN))
                {
                    if (free != null && type == free)
                    {
                        continue;
                    }
                    WriteTypeStatisticsLine(type.AllocatedSizeInBytes / (long)DisplayUnit, type.Count, type.Name);
                }
            }

            // Total heap size is only possible to calculate if the free objects are included
            if (free != null)
            {
                WriteTypeStatisticsLine(free.AllocatedSizeInBytes / (long)DisplayUnit, free.Count, ManagedHeapFree);
            }

            float managedAllocatedBytes = typeInfos.Where(x => free != null ? x != free : true).Sum(x => (float)x.AllocatedSizeInBytes);

            WriteTypeStatisticsLine((long)(managedAllocatedBytes / (long)DisplayUnit), typeInfos.Where(x => x != free).Sum(x => (long)x.Count), ManagedHeapAllocated);
            WriteTypeStatisticsLine(Heap.GetTotalHeapSize(), 0, ManagedHeapSize);

            allocatedMemoryInKB = (int)(managedAllocatedBytes / (long)DisplayUnit.KB);
            if (GetVMMapData)
            {
                VMMapData data = GetVMMapDataFromProcess(true, TargetInfo, Heap);
                WriteVMMapData(GetSimpleTypeFormatter(DisplayUnit), data);
                WriteTypeStatisticsLine((long)((managedAllocatedBytes + data.AllocatedBytesWithoutManagedHeap) / (long)DisplayUnit), 0, AllocatedTotal);
                allocatedMemoryInKB += (int)(data.AllocatedBytesWithoutManagedHeap / (long)DisplayUnit.KB);
            }

            return(allocatedMemoryInKB);
        }
Esempio n. 5
0
        /// <summary>
        /// Parse VMMap output from an existing process or a previously saved csv file.
        /// </summary>
        /// <returns>Parsed VMMap data. If an error occurs a empty VMMapData instance is returned.</returns>
        public VMMapData GetMappingData()
        {
            if (ExistingVMMapFile != null)
            {
                return(ParseVMMapFile(ExistingVMMapFile, bDelete: false));
            }

            if (NoVMMap)
            {
                return(new VMMapData());
            }

            SaveVMmapDataToFile(Pid, TempFileName);
            VMMapData lret = ParseVMMapFile(TempFileName, bDelete: true);

            return(lret);
        }
Esempio n. 6
0
 internal void MapDataFromLine(VMMapData lret, string line)
 {
     string[] parts = SplitLine(line);
     if (parts.Length >= 11)
     {
         string name = parts[0];
         if (RowMapper.TryGetValue(parts[0], out Action <long, long, long, VMMapData> mapper))
         {
             if (parts[1] == "") // Page table data can sometimes be empty
             {
                 return;
             }
             long reserved = long.Parse(parts[1]);
             long.TryParse(parts[2], out long committed);
             long.TryParse(parts[10], out long largestBlock);
             mapper(reserved, committed, largestBlock, lret);
         }
     }
 }
Esempio n. 7
0
        internal VMMapData ParseVMMapFile(string fileName, bool bDelete)
        {
            VMMapData lret = new VMMapData();

            if (!File.Exists(fileName))
            {
                return(lret);
            }

            using (var reader = new StreamReader(fileName))
            {
                string line         = null;
                bool   bShouldParse = false;
                while ((line = reader.ReadLine()) != null)
                {
                    if (line.StartsWith(SummaryDataStart))
                    {
                        bShouldParse = true;
                        continue;
                    }
                    if (line.StartsWith(SummaryDataStart))
                    {
                        bShouldParse = false;
                        break;
                    }

                    if (!bShouldParse)
                    {
                        continue;
                    }

                    MapDataFromLine(lret, line);
                }
            }

            if (bDelete)
            {
                RemoveTempVMMapFile(fileName);
            }

            return(lret);
        }
Esempio n. 8
0
        /// <summary>
        /// Get VMMap data from process
        /// </summary>
        /// <param name="bFirstProcess"></param>
        /// <param name="targetInfo"></param>
        /// <param name="heap"></param>
        /// <returns></returns>
        private static VMMapData GetVMMapDataFromProcess(bool bFirstProcess, TargetInformation targetInfo, ClrHeap heap)
        {
            int       pid  = bFirstProcess ? targetInfo.Pid1 : targetInfo.Pid2;
            VMMapData data = new VMMapData();

            if (pid != 0)
            {
                // we must first detach CLRMD or VMMAp will block at least in x64 in the target process to get heap information.
                // Play safe and do not try this asynchronously.
                heap?.Runtime?.DataTarget?.Dispose();
                data = StartVMMap(pid, null);
            }
            else
            {
                string existingVMMapFile = bFirstProcess ? targetInfo.DumpVMMapFile1 : targetInfo.DumpVMMapFile2;
                if (existingVMMapFile != null)
                {
                    data = StartVMMap(0, existingVMMapFile);
                }
            }

            return(data);
        }
Esempio n. 9
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);
        }
Esempio n. 10
0
 VMMapData ReturnNullIfNoDataPresent(VMMapData vmmap)
 {
     return(vmmap.IsEmpty ? null : vmmap);
 }