diff --git a/src/Microsoft.Diagnostics.Runtime.Tests/src/HeapTests.cs b/src/Microsoft.Diagnostics.Runtime.Tests/src/HeapTests.cs index 20ad93493..fe2a0b264 100644 --- a/src/Microsoft.Diagnostics.Runtime.Tests/src/HeapTests.cs +++ b/src/Microsoft.Diagnostics.Runtime.Tests/src/HeapTests.cs @@ -105,6 +105,10 @@ public void NextObject() foreach (ClrSegment seg in heap.Segments) { + if (seg.Length == 0) + { + continue; + } ulong nextObj = seg.GetNextObjectAddress(seg.FirstObjectAddress); foreach (ClrObject obj in seg.EnumerateObjects().Skip(1)) { @@ -123,6 +127,10 @@ public void PrevObject() foreach (ClrSegment seg in heap.Segments) { + if (seg.Length == 0) + { + continue; + } ClrObject prev = heap.GetObject(seg.FirstObjectAddress); Assert.Equal(0ul, seg.GetPreviousObjectAddress(prev)); @@ -181,22 +189,9 @@ public void WorkstationSegmentTests() Assert.True(heap.Segments.Length > 0); - CheckSorted(heap.Segments); CheckSegments(heap); } - private void CheckSorted(ImmutableArray segments) - { - ClrSegment last = null; - foreach (ClrSegment seg in segments) - { - if (last != null) - Assert.True(last.Start < seg.Start); - - last = seg; - } - } - private static void CheckSegments(ClrHeap heap) { foreach (ClrSegment seg in heap.Segments) @@ -208,7 +203,7 @@ private static void CheckSegments(ClrHeap heap) Assert.True(seg.Start < seg.CommittedMemory.End); Assert.True(seg.CommittedMemory.End < seg.ReservedMemory.End); Assert.False(seg.CommittedMemory.Overlaps(seg.ReservedMemory)); - Assert.True(seg.CommittedMemory.Contains(seg.ObjectRange)); + Assert.True(seg.Length == 0 || seg.CommittedMemory.Contains(seg.ObjectRange)); if (seg.Generation0.Length > 0) Assert.True(seg.ObjectRange.Contains(seg.Generation0)); @@ -219,12 +214,10 @@ private static void CheckSegments(ClrHeap heap) if (seg.Generation2.Length > 0) Assert.True(seg.ObjectRange.Contains(seg.Generation2)); - if (!seg.IsEphemeralSegment) + if (seg.Length == 0) { - Assert.Equal(0ul, seg.Generation0.Length); - Assert.Equal(0ul, seg.Generation1.Length); + continue; } - int count = 0; foreach (ulong obj in seg.EnumerateObjects()) { diff --git a/src/Microsoft.Diagnostics.Runtime/src/Builders/RuntimeBuilder.cs b/src/Microsoft.Diagnostics.Runtime/src/Builders/RuntimeBuilder.cs index 76e3450e5..b4641747d 100644 --- a/src/Microsoft.Diagnostics.Runtime/src/Builders/RuntimeBuilder.cs +++ b/src/Microsoft.Diagnostics.Runtime/src/Builders/RuntimeBuilder.cs @@ -167,7 +167,7 @@ bool IHeapHelpers.CreateSegments(ClrHeap clrHeap, out ImmutableArray } bool result = false; - SegmentBuilder segBuilder = new SegmentBuilder(_sos); + SegmentBuilder segBuilder = new SegmentBuilder(_sos, DataReader.PointerSize); if (clrHeap.IsServer) { ClrDataAddress[] heapList = _sos.GetHeapList(clrHeap.LogicalHeapCount); @@ -207,14 +207,21 @@ private void ProcessHeap( ImmutableArray.Builder fqRoots, ImmutableArray.Builder fqObjects) { + bool regions = heap.SavedSweepEphemeralSeg.Value == -1; + if (heap.EphemeralAllocContextPtr != 0 && heap.EphemeralAllocContextPtr != heap.EphemeralAllocContextLimit) allocationContexts.Add(new MemoryRange(heap.EphemeralAllocContextPtr, heap.EphemeralAllocContextLimit)); fqRoots.Add(new FinalizerQueueSegment(heap.FQRootsStart, heap.FQRootsStop)); fqObjects.Add(new FinalizerQueueSegment(heap.FQAllObjectsStart, heap.FQAllObjectsStop)); - AddSegments(segBuilder, clrHeap, large: true, pinned: false, heap, segments, heap.GenerationTable[3].StartSegment); - AddSegments(segBuilder, clrHeap, large: false, pinned: false, heap, segments, heap.GenerationTable[2].StartSegment); + AddSegments(segBuilder, clrHeap, 3, heap, segments, heap.GenerationTable[3].StartSegment); + AddSegments(segBuilder, clrHeap, 2, heap, segments, heap.GenerationTable[2].StartSegment); + if (regions) + { + AddSegments(segBuilder, clrHeap, 1, heap, segments, heap.GenerationTable[1].StartSegment); + AddSegments(segBuilder, clrHeap, 0, heap, segments, heap.GenerationTable[0].StartSegment); + } if (_sos8 != null) { @@ -227,18 +234,18 @@ private void ProcessHeap( genData = _sos8.GetGenerationTable(); if (genData != null && genData.Length > 3) - AddSegments(segBuilder, clrHeap, large: false, pinned: true, heap, segments, genData[4].StartSegment); + AddSegments(segBuilder, clrHeap, 4, heap, segments, genData[4].StartSegment); } } } - private void AddSegments(SegmentBuilder segBuilder, ClrHeap clrHeap, bool large, bool pinned, in HeapDetails heap, ImmutableArray.Builder segments, ulong address) + private void AddSegments(SegmentBuilder segBuilder, ClrHeap clrHeap, int generation, in HeapDetails heap, ImmutableArray.Builder segments, ulong address) { HashSet seenSegments = new HashSet { 0 }; - segBuilder.IsLargeObjectSegment = large; - segBuilder.IsPinnedObjectSegment = pinned; + segBuilder.IsLargeObjectSegment = (generation == 3); + segBuilder.IsPinnedObjectSegment = (generation == 4); - while (seenSegments.Add(address) && segBuilder.Initialize(address, heap)) + while (seenSegments.Add(address) && segBuilder.Initialize(address, generation, heap)) { // Unfortunately ClrmdSegment is tightly coupled to ClrmdHeap to make implementation vastly simpler and it can't // be used with any generic ClrHeap. There should be no way that this runtime builder ever mismatches the two diff --git a/src/Microsoft.Diagnostics.Runtime/src/Builders/SegmentBuilder.cs b/src/Microsoft.Diagnostics.Runtime/src/Builders/SegmentBuilder.cs index 867f63ad3..e2858d6c6 100644 --- a/src/Microsoft.Diagnostics.Runtime/src/Builders/SegmentBuilder.cs +++ b/src/Microsoft.Diagnostics.Runtime/src/Builders/SegmentBuilder.cs @@ -10,22 +10,39 @@ namespace Microsoft.Diagnostics.Runtime.Builders internal sealed class SegmentBuilder : ISegmentData { private SegmentData _segment; + private bool _regions; private ulong _heapAllocated; - private ulong _ephemGen0Start; - private ulong _ephemGen1Start; private ulong _ephemAddress; private readonly SOSDac _sos; - public SegmentBuilder(SOSDac sos) + // Segments only + private ulong _ephemGen0Start; + private ulong _ephemGen1Start; + + // Regions only + private int _generation; + private ulong _sizeofPlugAndGap; + + public SegmentBuilder(SOSDac sos, int pointerSize) { _sos = sos; + _sizeofPlugAndGap = (ulong)pointerSize * 4; } - public bool Initialize(ulong address, in HeapDetails heap) + public bool Initialize(ulong address, int generation, in HeapDetails heap) { + _regions = heap.SavedSweepEphemeralSeg.Value == -1; + _heapAllocated = heap.Allocated; - _ephemGen0Start = heap.GenerationTable[0].AllocationStart; - _ephemGen1Start = heap.GenerationTable[1].AllocationStart; + if (_regions) + { + _generation = generation; + } + else + { + _ephemGen0Start = heap.GenerationTable[0].AllocationStart; + _ephemGen1Start = heap.GenerationTable[1].AllocationStart; + } _ephemAddress = heap.EphemeralHeapSegment; return _sos.GetSegmentData(address, out _segment); @@ -34,7 +51,7 @@ public bool Initialize(ulong address, in HeapDetails heap) #region ISegmentData public int LogicalHeap { get; set; } - public ulong BaseAddress => _segment.Address; + public ulong BaseAddress => _regions ? (_segment.Start - _sizeofPlugAndGap) : _segment.Address; public ulong Start => _segment.Start; @@ -44,17 +61,82 @@ public bool Initialize(ulong address, in HeapDetails heap) public ulong CommittedEnd => _segment.Committed; - public ulong Gen0Start => IsEphemeralSegment ? _ephemGen0Start : End; + public ulong Gen0Start + { + get + { + if (_regions) + { + return (_generation == 0) ? Start : End; + } + else + { + return IsEphemeralSegment ? _ephemGen0Start : End; + } + } + } public ulong Gen0Length => End - Gen0Start; - public ulong Gen1Start => IsEphemeralSegment ? _ephemGen1Start : End; + public ulong Gen1Start + { + get + { + if (_regions) + { + return (_generation == 1) ? Start : End; + } + else + { + return IsEphemeralSegment ? _ephemGen1Start : End; + } + } + } - public ulong Gen1Length => Gen0Start - Gen1Start; + public ulong Gen1Length + { + get + { + if (_regions) + { + return End - Gen1Start; + } + else + { + return Gen0Start - Gen1Start; + } + } + } - public ulong Gen2Start => Start; + public ulong Gen2Start + { + get + { + if (_regions) + { + return (_generation >= 2) ? Start : End; + } + else + { + return Start; + } + } + } - public ulong Gen2Length => Gen1Start - Start; + public ulong Gen2Length + { + get + { + if (_regions) + { + return End - Gen2Start; + } + else + { + return Gen1Start - Start; + } + } + } public bool IsLargeObjectSegment { get; set; }