예제 #1
0
        private void SetCurrentSnapshot(HeapSnapshot snapshot)
        {
            // sanity checks
            if (snapshot == null)
            {
                return;
            }

            // remove current "Current item"
            SnapshotListViewItem currentItem = GetSnapshotItem(SnapshotListViewItemState.Current);

            if (currentItem != null)
            {
                currentItem.State = SnapshotListViewItemState.None;

                currentItem.ImageIndex = -1;
                // Note: the item must be redrawn when the image is reset to -1
                lvSnapshots.RedrawItems(currentItem.Index, currentItem.Index, "force redraw" == null);
            }

            // update the new "current" item
            SnapshotListViewItem item = GetSnapshotItem(snapshot);

            item.State      = SnapshotListViewItemState.Current;
            item.ImageIndex = CurrentImageIndex;

            _current = snapshot;
        }
예제 #2
0
        private void _listener_Changed(object sender, ClipboardChangedEventArgs e)
        {
            // Note: in WinDBG, the same content is copied to the clipboard TWICE.
            //       so we need to skip the notifications that occurs too close from
            //       the previous one.
            var now = DateTime.UtcNow;

            if (now.Subtract(_lastClipboardNotificationTime) < MIN_ELAPSE_SINCE_CLIPBOARD_NOTIFICATION)
            {
                return;
            }
            _lastClipboardNotificationTime = now;

            // TODO: make this "maybe long" treatment asynchronous if needed
            //
            // Check if this is a supported format
            HeapSnapshot snapshot = GetSnapshotFromClipboard();

            if (snapshot == null)
            {
                return;
            }

            AddOneSnapshot(snapshot);
        }
예제 #3
0
        private void SetReferenceSnapshot(HeapSnapshot snapshot)
        {
            // sanity checks
            if (snapshot == null)
            {
                return;
            }

            // remove current "reference" item
            SnapshotListViewItem referenceItem = GetSnapshotItem(SnapshotListViewItemState.Reference);

            if (referenceItem != null)
            {
                referenceItem.State = SnapshotListViewItemState.None;

                referenceItem.ImageIndex = -1;
                // Note: the item must be redrawn when the image is reset to -1
                lvSnapshots.RedrawItems(referenceItem.Index, referenceItem.Index, "force redraw" == null);
            }

            // update the new "reference" item
            SnapshotListViewItem item = GetSnapshotItem(snapshot);

            item.State      = SnapshotListViewItemState.Reference;
            item.ImageIndex = ReferenceImageIndex;

            _reference = snapshot;
        }
예제 #4
0
        private bool IsFilteredType(TypeEntry typeEntry)
        {
            string key = HeapSnapshot.GetKey(typeEntry);

            return
                (_filteredEntries.Any(e => (string.Compare(HeapSnapshot.GetKey(e), key) == 0)));
        }
        public static HeapSnapshot CreateFromHeapStat(string dumpheap)
        {
            // sanity checks
            if (string.IsNullOrEmpty(dumpheap))
            {
                throw InvalidFormatException;
            }

            if (!dumpheap.Contains(Header))
            {
                throw InvalidFormatException;
            }

            DumpHeapParsingState state = DumpHeapParsingState.Init;

            using (TextReader reader = new StringReader(dumpheap))
            {
                HeapSnapshot snapshot = new HeapSnapshot();
                while (true)
                {
                    string line = reader.ReadLine();
                    if (string.IsNullOrEmpty(line))
                    {
                        if (state == DumpHeapParsingState.End)
                        {
                            return(snapshot);
                        }

                        throw InvalidFormatException;
                    }

                    switch (state)
                    {
                    case DumpHeapParsingState.Init:
                        if (line.Contains(Header))
                        {
                            state = DumpHeapParsingState.TypeEntries;
                        }
                        break;

                    case DumpHeapParsingState.TypeEntries:
                        state = ParseAndAddTypeEntry(line, snapshot);
                        break;

                    case DumpHeapParsingState.End:
                        return(snapshot);

                    case DumpHeapParsingState.Error:
                        return(null);

                    default:
                        throw new InvalidOperationException($"Invalid parsing state {(int)state}.");
                    }
                }
            }
        }
예제 #6
0
 private SnapshotListViewItem GetSnapshotItem(HeapSnapshot snapshot)
 {
     foreach (SnapshotListViewItem item in lvSnapshots.Items)
     {
         if (item.Tag == snapshot)
         {
             return(item);
         }
     }
     return(null);
 }
예제 #7
0
 private TypeEntryListViewItem GetItemFromEntry(ListView listview, TypeEntry entry)
 {
     foreach (TypeEntryListViewItem item in listview.Items)
     {
         TypeEntry tagEntry = (TypeEntry)item.Tag;
         if (string.Compare(HeapSnapshot.GetKey(tagEntry), HeapSnapshot.GetKey(entry)) == 0)
         {
             return(item);
         }
     }
     return(null);
 }
        public static void DumpSnapshot(HeapSnapshot snapshot)
        {
            Debug.WriteLine("HeapSnapshot at {0}", snapshot.TimeStamp);
            Debug.WriteLine("  {0} objects for {1} Mb", snapshot.ObjectCount, snapshot.Size / 1024 / 1024);
            var entries =
                from e in snapshot.TypeStats.AsParallel()
                orderby e.Value.Name
                select e.Value
            ;

            foreach (var entry in entries)
            {
                Debug.WriteLine("    {0}", entry);
            }
        }
예제 #9
0
        private void AddSnapshot(HeapSnapshot snapshot)
        {
            // update the list
            SnapshotListViewItem lvSnapshot = new SnapshotListViewItem();

            lvSnapshot.Tag = snapshot;
            lvSnapshot.SubItems.Add(snapshot.ObjectCount.ToString("#,#"));
            lvSnapshot.SubItems.Add(snapshot.Size.ToString("#,#"));

            lvSnapshots.Items.Add(lvSnapshot);

            // update the chart
            chartCount.Series["Series2"].Points.AddY(snapshot.ObjectCount);
            chartSize.Series["Series1"].Points.AddY(snapshot.Size);
        }
예제 #10
0
        private void Clear()
        {
            // empty UI
            lvSnapshots.Items.Clear();
            lvCompare.Items.Clear();
            lvFiltered.Items.Clear();
            tbResult.Text = "";
            chartCount.Series["Series2"].Points.Clear();
            chartSize.Series["Series1"].Points.Clear();

            // same for data
            _reference = null;
            _current   = null;
            _filteredEntries.Clear();
        }
예제 #11
0
        private void AddOneSnapshot(HeapSnapshot snapshot)
        {
            // add the snapshot into the list
            AddSnapshot(snapshot);

            // set the reference if not already set
            if (_reference == null)
            {
                SetReferenceSnapshot(snapshot);
            }
            else
            {
                SetCurrentSnapshot(snapshot);
                CompareSnapshots();
            }
        }
        public static HeapSnapshot Compare(HeapSnapshot reference, HeapSnapshot current)
        {
            HeapSnapshot compare = new HeapSnapshot();

            // loop on each entry in the current snapshot and compare with the reference
            foreach (var item in current.TypeStats)
            {
                // look for this class in the reference
                if (reference.TypeStats.ContainsKey(item.Key))
                {
                    TypeEntry referenceEntry = reference.TypeStats[item.Key];
                    if (referenceEntry.Count < item.Value.Count)
                    {
                        var entry = new TypeEntry();
                        entry.Name        = string.Intern(referenceEntry.Name);
                        entry.MethodTable = referenceEntry.MethodTable;
                        entry.Count       = item.Value.Count - referenceEntry.Count;
                        entry.TotalSize   = item.Value.TotalSize - referenceEntry.TotalSize;

                        compare.TypeStats.Add(HeapSnapshot.GetKey(entry), entry);

                        compare.ObjectCount += entry.Count;
                        compare.Size        += entry.TotalSize;
                    }
                }
                else  // don't forget the case where brand new type instances appear in current snapshot
                {
                    var entry = new TypeEntry();
                    entry.Name        = string.Intern(item.Value.Name);
                    entry.MethodTable = item.Value.MethodTable;
                    entry.Count       = item.Value.Count;
                    entry.TotalSize   = item.Value.TotalSize;

                    compare.TypeStats.Add(HeapSnapshot.GetKey(entry), entry);

                    compare.ObjectCount += entry.Count;
                    compare.Size        += entry.TotalSize;
                }
            }

            return(compare);
        }
예제 #13
0
        private static HeapSnapshot Compute(ClrHeap heap)
        {
            var snapshot = new HeapSnapshot();

            foreach (ulong objAddress in heap.EnumerateObjectAddresses())
            {
                ClrType type = heap.GetObjectType(objAddress);
                if (type == null)
                {
                    continue;
                }

                var mt   = type.MethodTable.ToString();
                var name = type.Name;
                var key  = HeapSnapshot.GetKey(name, mt);

                if (!snapshot.TypeStats.TryGetValue(key, out var entry))
                {
                    entry = new TypeEntry()
                    {
                        Name        = name,
                        MethodTable = mt
                    };

                    snapshot.TypeStats[key] = entry;
                }
                entry.Count          = entry.Count + 1;
                snapshot.ObjectCount = snapshot.ObjectCount + 1;

                var size = type.GetSize(objAddress);
                entry.TotalSize = entry.TotalSize + (long)size;
                snapshot.Size   = snapshot.Size + (long)size;
            }

            return(snapshot);
        }
        private static DumpHeapParsingState ParseAndAddTypeEntry(string line, HeapSnapshot snapshot)
        {
            if (line.StartsWith("Total"))
            {
                return(DumpHeapParsingState.End);
            }

            //       MT    Count    TotalSize Class Name
            // 651d7ffc        1           12 System.Configuration.Internal.ConfigurationManagerInternal
            //
            // or in x64
            //
            // 0x000007ff01221408    1,448       57,920 System.Xml.XmlQualifiedName
            //
            TypeEntry entry = new TypeEntry();
            var       pos   = 0;
            var       end   = 0;
            string    field;

            // 1. look for the MT
            end = line.IndexOf(SPACE);
            if (end == -1)
            {
                Debug.WriteLine("impossible to find the end of the MT field");
                return(DumpHeapParsingState.Error);
            }
            field             = line.Substring(pos, end - pos);
            entry.MethodTable = field;

            if (!SkipSpaces(line, ref end))
            {
                Debug.WriteLine("impossible to find the start of the Count field");
                return(DumpHeapParsingState.Error);
            }
            pos = end;

            // 2. look for the count
            end = line.IndexOf(SPACE, pos);
            if (end == -1)
            {
                Debug.WriteLine("impossible to find the end of the Count field");
                return(DumpHeapParsingState.Error);
            }
            field = line.Substring(pos, end - pos);

            if (!long.TryParse(GetNumberFromString(field), out var count))
            {
                Debug.WriteLine("invalid decimal value for the Count field");
                return(DumpHeapParsingState.Error);
            }
            entry.Count = count;

            if (!SkipSpaces(line, ref end))
            {
                Debug.WriteLine("impossible to find the start of the TotalSize field");
                return(DumpHeapParsingState.Error);
            }
            pos = end;


            // 3. look for the total size
            end = line.IndexOf(SPACE, pos);
            if (end == -1)
            {
                Debug.WriteLine("impossible to find the end of the MT field");
                return(DumpHeapParsingState.Error);
            }
            field = line.Substring(pos, end - pos);
            if (!long.TryParse(GetNumberFromString(field), out var totalSize))
            {
                Debug.WriteLine("invalid decimal value for the TotalSize field");
                return(DumpHeapParsingState.Error);
            }
            entry.TotalSize = totalSize;

            if (!SkipSpaces(line, ref end))
            {
                Debug.WriteLine("impossible to find the start of the TotalSize field");
                return(DumpHeapParsingState.Error);
            }
            pos = end;


            // 4. look for the class name
            field      = line.Substring(pos);
            entry.Name = string.Intern(field);

            snapshot.ObjectCount += entry.Count;
            snapshot.Size        += entry.TotalSize;

            string key = HeapSnapshot.GetKey(entry);

            if (!snapshot.TypeStats.ContainsKey(key))
            {
                snapshot.TypeStats.Add(key, entry);
            }
            else
            {
                Debug.Fail("This should never happen");
                throw new InvalidOperationException($"Impossible to find {key} for the entry");
            }

            return(DumpHeapParsingState.TypeEntries);
        }
예제 #15
0
        private void CompareSnapshots()
        {
            HeapSnapshot compare = HeapSnapshotFactory.Compare(_reference, _current);

            HeapSnapshotFactory.DumpSnapshot(compare);

            // if the check box is checked, don't show the System.* types
            bool dontShowBCLType = cbDontShowBCLTypes.Checked;

            // update the Raw UI
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("HeapSnapshot at {0}\r\n", compare.TimeStamp);
            sb.AppendFormat("  {0} objects for {1} bytes\r\n", compare.ObjectCount, compare.Size);
            var entries =
                from item in compare.TypeStats.AsParallel()
                where !dontShowBCLType || !IsBclType(item.Value.Name)
                orderby item.Value.Name
                select item.Value
            ;

            foreach (var entry in entries)
            {
                sb.AppendFormat("    {0}\r\n", entry);
            }
            tbResult.Text = sb.ToString();

            // update the List UI
            lvCompare.BeginUpdate();
            lvFiltered.BeginUpdate();
            lvCompare.Items.Clear();
            lvFiltered.Items.Clear();

            foreach (var entry in compare.TypeStats)
            {
                TypeEntryListViewItem item;

                // Create a wrapping ListViewItem for the filtered list if needed
                // Note: always present even though DontShowBCLType is checked
                if (IsFilteredType(entry.Value))
                {
                    AddFilteredEntry(entry.Value);
                }

                // skip BCL when needed
                if (dontShowBCLType)
                {
                    if (IsBclType(entry.Value.Name))
                    {
                        continue;
                    }
                }

                // Create a wrapping ListViewItem for the compare list
                item     = new TypeEntryListViewItem("");
                item.Tag = entry.Value;
                item.SubItems.Add(entry.Value.Count.ToString("#,#"));
                item.SubItems.Add(entry.Value.TotalSize.ToString("#,#"));
                item.SubItems.Add(entry.Value.Name);
                lvCompare.Items.Add(item);

                // Create a wrapping ListViewItem for the filtered list if needed
                if (IsFilteredType(entry.Value))
                {
                    item.Filtered   = true;
                    item.ImageIndex = 0;
                }
            }
            lvCompare.Sort();
            lvFiltered.Sort();
            lvFiltered.EndUpdate();
            lvCompare.EndUpdate();
        }