internal void RecordGc(int tickIndex, int gen, SampleObjectTable sampleObjectTable, bool simpleForm) { lastTickIndex = tickIndex; sampleObjectTable?.AddGcTick(tickIndex, gen); intervalTable.RecordGc(tickIndex, sampleObjectTable, simpleForm); if (gen >= 1) { gen2LimitTickIndex = gen1LimitTickIndex; } gen1LimitTickIndex = tickIndex; lastGcGen0Count++; if (gen > 0) { lastGcGen1Count++; if (gen > 1) { lastGcGen2Count++; } } }
private void RemoveRange(ulong loAddr, ulong hiAddr, int tickIndex, SampleObjectTable sampleObjectTable) { Interval next; for (Interval i = liveRoot; i != null; i = next) { next = i.next; ulong lo = Math.Max(loAddr, i.loAddr); ulong hi = Math.Min(hiAddr, i.hiAddr); if (lo >= hi) { continue; } liveObjectTable.RemoveObjectRange(lo, hi - lo, tickIndex, sampleObjectTable); if (i.hiAddr == hi) { if (i.loAddr == lo) { DeleteInterval(i); } else { i.hiAddr = lo; } } } }
internal void RecordGc(int tickIndex, SampleObjectTable sampleObjectTable, bool simpleForm) { if (simpleForm && nullRelocationsSeen || newLiveRoot != null) { // in this case assume anything not reported is dead updateRoot = SortIntervals(updateRoot); ulong prevHiAddr = 0; for (Interval i = updateRoot; i != null; i = i.next) { if (prevHiAddr < i.loAddr) { RemoveRange(prevHiAddr, i.loAddr, tickIndex, sampleObjectTable); } if (prevHiAddr < i.hiAddr) { prevHiAddr = i.hiAddr; } } RemoveRange(prevHiAddr, ulong.MaxValue, tickIndex, sampleObjectTable); updateRoot = null; if (newLiveRoot != null) { liveRoot = newLiveRoot; newLiveRoot = null; } } else { for (Interval i = liveRoot; i != null; i = i.next) { i.justHadGc = true; } } nullRelocationsSeen = false; }
internal bool AddObject(ulong id, uint size, int allocTickIndex, SampleObjectTable sampleObjectTable) { size = (size + 3) & (uint.MaxValue - 3); Interval prevInterval = null; Interval bestInterval = null; Interval prevI = null; bool emptySpace = false; // look for the best interval to put this object in. for (Interval i = liveRoot; i != null; i = i.next) { if (i.loAddr < id + size && id <= i.hiAddr + allowableGap) { if (bestInterval == null || bestInterval.loAddr < i.loAddr) { bestInterval = i; prevInterval = prevI; } } prevI = i; } if (bestInterval != null) { if (bestInterval.loAddr > id) { bestInterval.loAddr = id; } if (id < bestInterval.hiAddr) { if (bestInterval.hadRelocations && bestInterval.justHadGc) { // Interval gets shortened liveObjectTable.RemoveObjectRange(id, bestInterval.hiAddr - id, allocTickIndex, sampleObjectTable); bestInterval.hiAddr = id + size; bestInterval.justHadGc = false; } } else { bestInterval.hiAddr = id + size; emptySpace = true; } if (prevInterval != null) { // Move to front to speed up future searches. prevInterval.next = bestInterval.next; bestInterval.next = liveRoot; liveRoot = bestInterval; } if (OverlappingInterval(bestInterval) != null) { MergeInterval(bestInterval); } return(emptySpace); } liveRoot = new Interval(id, id + size, -1, liveRoot); Debug.Assert(OverlappingInterval(liveRoot) == null); return(false); }
private void RemoveObjectRange(ulong firstId, ulong length, int tickIndex, SampleObjectTable sampleObjectTable) { ulong lastId = firstId + length; sampleObjectTable?.Delete(firstId, lastId, tickIndex); Zero(firstId, length); }
private int NextLabelX(Graphics g, SampleObjectTable.SampleObject gc, int gen, int[] pgcCount) { int[] gcCount = new int[3]; gcCount[0] = pgcCount[0]; gcCount[1] = pgcCount[1]; gcCount[2] = pgcCount[2]; if (gen < 2) { for (gc = gc.prev; gc != null; gc = gc.prev) { gcCount[0]--; if (gc.typeIndex >= 1) gcCount[1]--; if (gc.typeIndex >= 2) gcCount[2]--; if (gc.typeIndex > gen) { int x = TimeToX(lastLog.TickIndexToTime(gc.changeTickIndex)); string s = string.Format("gc #{0} (gen {1}#{2})", gcCount[0], gc.typeIndex, gcCount[gen]); int minLabelPitch = (int)g.MeasureString(s, font).Width + 10; return x + minLabelPitch; } } } return int.MinValue; }
private void RemoveRange(ulong loAddr, ulong hiAddr, int tickIndex, SampleObjectTable sampleObjectTable) { Interval next; for (Interval i = liveRoot; i != null; i = next) { next = i.next; ulong lo = Math.Max(loAddr, i.loAddr); ulong hi = Math.Min(hiAddr, i.hiAddr); if (lo >= hi) continue; liveObjectTable.RemoveObjectRange(lo, hi - lo, tickIndex, sampleObjectTable); if (i.hiAddr == hi) { if (i.loAddr == lo) DeleteInterval(i); else i.hiAddr = lo; } } }
internal void RecordGc(int tickIndex, int gcGen0Count, int gcGen1Count, int gcGen2Count, SampleObjectTable sampleObjectTable) { int gen = 0; if (gcGen2Count != lastGcGen2Count) gen = 2; else if (gcGen1Count != lastGcGen1Count) gen = 1; RecordGc(tickIndex, gen, sampleObjectTable, false); lastGcGen0Count = gcGen0Count; lastGcGen1Count = gcGen1Count; lastGcGen2Count = gcGen2Count; }
internal void UpdateObjects(Histogram relocatedHistogram, ulong oldId, ulong newId, uint length, int tickIndex, SampleObjectTable sampleObjectTable) { if (lastPos >= readNewLog.pos) return; lastPos = readNewLog.pos; lastTickIndex = tickIndex; intervalTable.Relocate(oldId, newId, length); if (oldId == newId) return; ulong nextId; ulong lastId = oldId + length; LiveObject o; for (GetNextObject(oldId, lastId, out o); o.id < lastId; GetNextObject(nextId, lastId, out o)) { nextId = o.id + o.size; ulong offset = o.id - oldId; if (sampleObjectTable != null) sampleObjectTable.Delete(o.id, o.id + o.size, tickIndex); Zero(o.id, o.size); InsertObject(newId + offset, o.typeSizeStacktraceIndex, o.allocTickIndex, tickIndex, false, sampleObjectTable); if (relocatedHistogram != null) relocatedHistogram.AddObject(o.typeSizeStacktraceIndex, 1); } }
internal void InsertObject(ulong id, int typeSizeStacktraceIndex, int allocTickIndex, int nowTickIndex, bool newAlloc, SampleObjectTable sampleObjectTable) { if (lastPos >= readNewLog.pos && newAlloc) return; lastPos = readNewLog.pos; lastTickIndex = nowTickIndex; int[] stacktrace = readNewLog.stacktraceTable.IndexToStacktrace(typeSizeStacktraceIndex); int typeIndex = stacktrace[0]; uint size = (uint)stacktrace[1]; bool emptySpace = false; if (newAlloc) { emptySpace = intervalTable.AddObject(id, size, allocTickIndex, sampleObjectTable); } if (!emptySpace) { ulong prevId = FindObjectBackward(id - 4); LiveObject o; GetNextObject(prevId, id, out o); if (o.id < id && (o.id + o.size > id || o.id + 12 > id)) { Zero(o.id, id - o.id); } } Debug.Assert(FindObjectBackward(id-4)+12 <= id); if (size >= 12) { ushort u1 = (ushort)(typeSizeStacktraceIndex | 0x8000); ushort u2 = (ushort)((typeSizeStacktraceIndex >> 15) | ((allocTickIndex & 0xff) << 7)); ushort u3 = (ushort)(allocTickIndex >> 8); Write3WordsAt(id, u1, u2, u3); if (!emptySpace) Zero(id + 12, size - 12); Debug.Assert(CanReadObjectBackCorrectly(id, size, typeSizeStacktraceIndex, allocTickIndex)); } if (sampleObjectTable != null) sampleObjectTable.Insert(id, id + size, nowTickIndex, allocTickIndex, typeIndex); }
private void DrawChangeList(Graphics g, SampleObjectTable.SampleObject so, ulong addr, int tickIndex) { int nextTickIndex = sampleObjectTable.lastTickIndex; for ( ; so != null; so = so.prev) { if (so.changeTickIndex <= tickIndex && tickIndex < nextTickIndex) { TypeDesc t; if (firstAllocTickIndex <= so.origAllocTickIndex && so.origAllocTickIndex < lastAllocTickIndex) t = typeIndexToTypeDesc[so.typeIndex]; else t = typeIndexToTypeDesc[0]; int x = TimeToX(lastLog.TickIndexToTime(tickIndex)); int y = AddrToY(addr); g.DrawLine(t.pen, x-1, y, x, y); break; } nextTickIndex = so.changeTickIndex; } }
private void versionTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (font != MainForm.instance.font) { font = MainForm.instance.font; graphPanel.Invalidate(); typeLegendPanel.Invalidate(); } ReadLogResult lastLogResult = MainForm.instance.lastLogResult; if (lastLogResult != null && lastLogResult.sampleObjectTable != sampleObjectTable) { sampleObjectTable = lastLogResult.sampleObjectTable; lastLog = sampleObjectTable.readNewLog; typeName = lastLog.typeName; lastTickIndex = sampleObjectTable.lastTickIndex; rangeList = null; rangeCount = 0; graphPanel.Invalidate(); typeLegendPanel.Invalidate(); } }
private void DrawGcTicks(Graphics g, SampleObjectTable.SampleObject gcTickList) { RectangleF clipRect = g.VisibleClipBounds; Brush[] brushes = new Brush[3]; Pen[] pens = new Pen[3]; brushes[0] = new SolidBrush(Color.Red); brushes[1] = new SolidBrush(Color.Green); brushes[2] = new SolidBrush(Color.Blue); for (int i = 0; i < 3; i++) pens[i] = new Pen(brushes[i]); int[] totalGcCount = new int[3]; for (SampleObjectTable.SampleObject gc = gcTickList; gc != null; gc = gc.prev) { totalGcCount[0]++; if (gc.typeIndex >= 1) totalGcCount[1]++; if (gc.typeIndex >= 2) totalGcCount[2]++; } int y = topMargin; for (AddressRange r = rangeList; r != null; r = r.next) { y += (int)((r.hiAddr - r.loAddr)/(uint)verticalScale); if (y <= clipRect.Bottom && clipRect.Top <= y + timeLabelHeight) { for (int gen = 2; gen >= 0; gen--) { int[] gcCount = new int[3]; gcCount[0] = totalGcCount[0]; gcCount[1] = totalGcCount[1]; gcCount[2] = totalGcCount[2]; int lastLabelX = Int32.MaxValue; for (SampleObjectTable.SampleObject gc = gcTickList; gc != null; gc = gc.prev) { int x = TimeToX(lastLog.TickIndexToTime(gc.changeTickIndex)); if (gc.typeIndex != gen) { if (gc.typeIndex > gen) lastLabelX = x; } else { string s; if (gen == 0) s = string.Format("gc #{0}", gcCount[0]); else s = string.Format("gc #{0} (gen {1}#{2})", gcCount[0], gen, gcCount[gen]); int minLabelPitch = (int)g.MeasureString(s, font).Width + 10; if (lastLabelX - x >= minLabelPitch && x > NextLabelX(g, gc, gen, gcCount)) { int x1 = x; int x2 = x1 + minLabelPitch; IntersectIntervals((int)clipRect.Left, (int)clipRect.Right, ref x1, ref x2); if (x1 < x2) { g.DrawLine(pens[gen], x, y, x, y+6); g.DrawString(s, font, brushes[gen], x, y); } lastLabelX = x; } else if (clipRect.Left <= x && x <= clipRect.Right) { g.DrawLine(pens[gen], x, y, x, y+3); } } gcCount[0]--; if (gc.typeIndex >= 1) gcCount[1]--; if (gc.typeIndex >= 2) gcCount[2]--; } } } y += timeLabelHeight + gap; } }
internal void RecordGc(int tickIndex, int gcGen0Count, int gcGen1Count, int gcGen2Count, SampleObjectTable sampleObjectTable) { int gen = 0; if (gcGen2Count != lastGcGen2Count) { gen = 2; } else if (gcGen1Count != lastGcGen1Count) { gen = 1; } RecordGc(tickIndex, gen, sampleObjectTable, false); lastGcGen0Count = gcGen0Count; lastGcGen1Count = gcGen1Count; lastGcGen2Count = gcGen2Count; }
internal void UpdateObjects(Histogram relocatedHistogram, ulong oldId, ulong newId, uint length, int tickIndex, SampleObjectTable sampleObjectTable) { if (lastPos >= readNewLog.pos) { return; } lastPos = readNewLog.pos; lastTickIndex = tickIndex; intervalTable.Relocate(oldId, newId, length); if (oldId == newId) { return; } ulong nextId; ulong lastId = oldId + length; LiveObject o; for (GetNextObject(oldId, lastId, out o); o.id < lastId; GetNextObject(nextId, lastId, out o)) { nextId = o.id + o.size; ulong offset = o.id - oldId; sampleObjectTable?.Delete(o.id, o.id + o.size, tickIndex); Zero(o.id, o.size); InsertObject(newId + offset, o.typeSizeStacktraceIndex, o.allocTickIndex, tickIndex, false, sampleObjectTable); relocatedHistogram?.AddObject(o.typeSizeStacktraceIndex, 1); } }
private void DrawSamples(Graphics g, SampleObjectTable.SampleObject[][] masterTable, int tick) { for (uint i = 0; i < masterTable.Length; i++) { SampleObjectTable.SampleObject[] soa = masterTable[i]; if (soa != null) { for (uint j = 0; j < soa.Length; j++) { SampleObjectTable.SampleObject so = soa[j]; if (so != null) { ulong addr = ((ulong)i<<SampleObjectTable.firstLevelShift) + (j<<SampleObjectTable.secondLevelShift); if ((addr % (uint)verticalScale) == 0) DrawChangeList(g, so, addr, tick); } } } } }
private void ProcessChangeList(SampleObjectTable.SampleObject so) { int lastTickIndex = sampleObjectTable.lastTickIndex; for ( ; so != null; so = so.prev) { AddToTypeTable(so.typeIndex, lastTickIndex - so.changeTickIndex); lastTickIndex = so.changeTickIndex; } }
void RemoveObjectRange(ulong firstId, ulong length, int tickIndex, SampleObjectTable sampleObjectTable) { ulong lastId = firstId + length; if (sampleObjectTable != null) sampleObjectTable.Delete(firstId, lastId, tickIndex); Zero(firstId, length); }
private void BuildAddressRangesTypeTable(SampleObjectTable.SampleObject[][] masterTable) { rangeList = null; rangeCount = 0; if (typeIndexToTypeDesc == null || typeIndexToTypeDesc.Length < typeName.Length) typeIndexToTypeDesc = new TypeDesc[typeName.Length]; else { foreach (TypeDesc t in typeIndexToTypeDesc) { if (t != null) t.totalSize = 0; } } for (uint i = 0; i < masterTable.Length; i++) { SampleObjectTable.SampleObject[] soa = masterTable[i]; if (soa != null) { for (uint j = 0; j < soa.Length; j++) { SampleObjectTable.SampleObject so = soa[j]; if (so != null) { AddAddress(((ulong)i<<SampleObjectTable.firstLevelShift) + (j<<SampleObjectTable.secondLevelShift)); ProcessChangeList(so); } } } } sortedTypeTable = new ArrayList(); foreach (TypeDesc t in typeIndexToTypeDesc) if (t != null) sortedTypeTable.Add(t); sortedTypeTable.Sort(); }
internal void RecordGc(int tickIndex, int gen, SampleObjectTable sampleObjectTable, bool simpleForm) { lastTickIndex = tickIndex; if (sampleObjectTable != null) sampleObjectTable.AddGcTick(tickIndex, gen); intervalTable.RecordGc(tickIndex, sampleObjectTable, simpleForm); if (gen >= 1) gen2LimitTickIndex = gen1LimitTickIndex; gen1LimitTickIndex = tickIndex; lastGcGen0Count++; if (gen > 0) { lastGcGen1Count++; if (gen > 1) lastGcGen2Count++; } }
private void DrawChangeList(Graphics g, SampleObjectTable.SampleObject so, ulong addr) { double lastTime = lastLog.TickIndexToTime(sampleObjectTable.lastTickIndex); int y = AddrToY(addr); RectangleF clipRect = g.VisibleClipBounds; for ( ; so != null; so = so.prev) { TypeDesc t; if (firstAllocTickIndex <= so.origAllocTickIndex && so.origAllocTickIndex < lastAllocTickIndex) t = typeIndexToTypeDesc[so.typeIndex]; else t = typeIndexToTypeDesc[0]; double changeTime = lastLog.TickIndexToTime(so.changeTickIndex); int x1 = TimeToX(changeTime); int x2 = TimeToX(lastTime); IntersectIntervals((int)clipRect.Left, (int)clipRect.Right, ref x1, ref x2); if (x1 < x2) g.DrawLine(t.pen, x1, y, x2, y); lastTime = changeTime; } }
internal bool AddObject(ulong id, uint size, int allocTickIndex, SampleObjectTable sampleObjectTable) { size = (size + 3) & (uint.MaxValue - 3); Interval prevInterval = null; Interval bestInterval = null; Interval prevI = null; bool emptySpace = false; // look for the best interval to put this object in. for (Interval i = liveRoot; i != null; i = i.next) { if (i.loAddr < id + size && id <= i.hiAddr + allowableGap) { if (bestInterval == null || bestInterval.loAddr < i.loAddr) { bestInterval = i; prevInterval = prevI; } } prevI = i; } if (bestInterval != null) { if (bestInterval.loAddr > id) { bestInterval.loAddr = id; } if (id < bestInterval.hiAddr) { if (bestInterval.hadRelocations && bestInterval.justHadGc) { // Interval gets shortened liveObjectTable.RemoveObjectRange(id, bestInterval.hiAddr - id, allocTickIndex, sampleObjectTable); bestInterval.hiAddr = id + size; bestInterval.justHadGc = false; } } else { bestInterval.hiAddr = id + size; emptySpace = true; } if (prevInterval != null) { // Move to front to speed up future searches. prevInterval.next = bestInterval.next; bestInterval.next = liveRoot; liveRoot = bestInterval; } if (OverlappingInterval(bestInterval) != null) MergeInterval(bestInterval); return emptySpace; } liveRoot = new Interval(id, id + size, -1, liveRoot); Debug.Assert(OverlappingInterval(liveRoot) == null); return emptySpace; }
private void DrawSamples(Graphics g, SampleObjectTable.SampleObject[][] masterTable) { RectangleF clipRect = g.VisibleClipBounds; for (AddressRange r = rangeList; r != null; r = r.next) { int rangeTop = AddrToY(r.hiAddr); int rangeBottom = AddrToY(r.loAddr); IntersectIntervals((int)clipRect.Top, (int)clipRect.Bottom, ref rangeTop, ref rangeBottom); if (rangeTop < rangeBottom) { ulong hiAddr = YToAddr(rangeTop); for (ulong addr = (ulong)(YToAddr(rangeBottom) / (uint)verticalScale * (uint)verticalScale); addr <= hiAddr; addr += (ulong)verticalScale) { uint i = (uint)(addr >> SampleObjectTable.firstLevelShift); SampleObjectTable.SampleObject[] soa = masterTable[i]; if (soa != null) { uint j = (uint)((addr >> SampleObjectTable.secondLevelShift) & (SampleObjectTable.secondLevelLength-1)); SampleObjectTable.SampleObject so = soa[j]; if (so != null) { int y = AddrToY(addr); Debug.Assert(addr == ((ulong)i<<SampleObjectTable.firstLevelShift) + (j<<SampleObjectTable.secondLevelShift)); if (clipRect.Top <= y && y <= clipRect.Bottom) { DrawChangeList(g, so, addr); } } } } } } }
internal void RecordGc(int tickIndex, SampleObjectTable sampleObjectTable, bool simpleForm) { if (simpleForm && nullRelocationsSeen || newLiveRoot != null) { // in this case assume anything not reported is dead updateRoot = SortIntervals(updateRoot); ulong prevHiAddr = 0; for (Interval i = updateRoot; i != null; i = i.next) { if (prevHiAddr < i.loAddr) { RemoveRange(prevHiAddr, i.loAddr, tickIndex, sampleObjectTable); } if (prevHiAddr < i.hiAddr) prevHiAddr = i.hiAddr; } RemoveRange(prevHiAddr, ulong.MaxValue, tickIndex, sampleObjectTable); updateRoot = null; if (newLiveRoot != null) { liveRoot = newLiveRoot; newLiveRoot = null; } } else { for (Interval i = liveRoot; i != null; i = i.next) i.justHadGc = true; } nullRelocationsSeen = false; }
internal void InsertObject(ulong id, int typeSizeStacktraceIndex, int allocTickIndex, int nowTickIndex, bool newAlloc, SampleObjectTable sampleObjectTable) { if (lastPos >= readNewLog.pos && newAlloc) { return; } lastPos = readNewLog.pos; lastTickIndex = nowTickIndex; int[] stacktrace = readNewLog.stacktraceTable.IndexToStacktrace(typeSizeStacktraceIndex); int typeIndex = stacktrace[0]; uint size = (uint)stacktrace[1]; bool emptySpace = false; if (newAlloc) { emptySpace = intervalTable.AddObject(id, size, allocTickIndex, sampleObjectTable); } if (!emptySpace) { ulong prevId = FindObjectBackward(id - 4); LiveObject o; GetNextObject(prevId, id, out o); if (o.id < id && (o.id + o.size > id || o.id + 12 > id)) { Zero(o.id, id - o.id); } } Debug.Assert(FindObjectBackward(id - 4) + 12 <= id); if (size >= 12) { ushort u1 = (ushort)(typeSizeStacktraceIndex | 0x8000); ushort u2 = (ushort)((typeSizeStacktraceIndex >> 15) | ((allocTickIndex & 0xff) << 7)); ushort u3 = (ushort)(allocTickIndex >> 8); Write3WordsAt(id, u1, u2, u3); if (!emptySpace) { Zero(id + 12, size - 12); } Debug.Assert(CanReadObjectBackCorrectly(id, size, typeSizeStacktraceIndex, allocTickIndex)); } sampleObjectTable?.Insert(id, id + size, nowTickIndex, allocTickIndex, typeIndex); }