static void Serialize(ref SerializationContext context, ref HeapSnapshotInfo input) { var bw = new BinaryWriter(context.Stream, Encoding.UTF8); bw.Write(input.Index); bw.Write(input.Timestamp.ToString("O")); bw.Write(input.Filename); bw.Write(input.HeapFragmentation); bw.Write(input.LargestFreeHeapBlock); bw.Write(input.LargestOccupiedHeapBlock); bw.Write(input.AverageFreeBlockSize); bw.Write(input.AverageOccupiedBlockSize); bw.Write(input.BytesAllocated); bw.Write(input.BytesOverhead); bw.Write(input.BytesTotal); bw.Write(input.AllocationCount); bw.Flush(); uint offset = (uint)context.Stream.Length; bw.Write(offset + 4); bw.Flush(); context.SerializeValue(input.Memory); }
public long GetAllocationCount(HeapSnapshotInfo item) { FilteredHeapSnapshotInfo info = item; if (CurrentFilterData != null) { if (!CurrentFilterData.TryGetValue(item, out info)) { info = item; } } return((long)(info.AllocationCount)); }
public long GetBytesTotal(HeapSnapshotInfo item) { FilteredHeapSnapshotInfo info = item; if (CurrentFilterData != null) { if (!CurrentFilterData.TryGetValue(item, out info)) { info = item; } } return((long)(info.BytesTotal)); }
public Future <HeapSnapshot> GetSnapshot(HeapSnapshotInfo info) { var snapshot = info.Snapshot; if (snapshot != null) { return(new Future <HeapSnapshot>(snapshot)); } var f = new Future <HeapSnapshot>(); Scheduler.Start( f, new SchedulableGeneratorThunk(LoadSnapshotFromDatabase(info)), TaskExecutionPolicy.RunAsBackgroundTask ); return(f); }
private IEnumerator <object> SetCurrentSnapshot(HeapSnapshotInfo info) { var oldSnapshot = Snapshot; if (oldSnapshot != null) { oldSnapshot.Info.ReleaseStrongReference(); } using (Finally.Do(() => { UseWaitCursor = false; })) { var fSnapshot = Instance.GetSnapshot(info); yield return(fSnapshot); Snapshot = fSnapshot.Result; RefreshHeap(); } }
static void Deserialize(ref DeserializationContext context, out HeapSnapshotInfo output) { var br = new BinaryReader(context.Stream, Encoding.UTF8); var index = br.ReadInt32(); var timestamp = DateTime.Parse(br.ReadString()); var filename = br.ReadString(); var heapFragmentation = br.ReadSingle(); var largestFree = br.ReadInt64(); var largestOccupied = br.ReadInt64(); var averageFree = br.ReadInt64(); var averageOccupied = br.ReadInt64(); var bytesAllocated = br.ReadInt64(); var bytesOverhead = br.ReadInt64(); var bytesTotal = br.ReadInt64(); var allocationCount = br.ReadInt32(); var memoryOffset = br.ReadUInt32(); MemoryStatistics memory; context.DeserializeValue(memoryOffset, out memory); output = new HeapSnapshotInfo( index, timestamp, filename, memory, heapFragmentation, largestFree, largestOccupied, averageFree, averageOccupied, bytesAllocated, bytesOverhead, bytesTotal, allocationCount ); }
public static long GetLargestOccupiedHeapBlock(HeapSnapshotInfo item) { return(item.LargestOccupiedHeapBlock); }
public static long GetAverageFreeHeapBlockSize(HeapSnapshotInfo item) { return(item.AverageFreeBlockSize); }
public static long GetWorkingSet(HeapSnapshotInfo item) { return(item.Memory.WorkingSet); }
public static long GetVirtualMemory(HeapSnapshotInfo item) { return(item.Memory.Virtual); }
public static long GetPagedMemory(HeapSnapshotInfo item) { return(item.Memory.Paged); }
public static IEnumerator <object> LoadFromDatabase(DatabaseFile db, HeapSnapshotInfo info) { var fResult = db.Snapshots.Get(info.Index); yield return(fResult); }
internal HeapSnapshot(HeapSnapshotInfo info) { Info = info; info.SetSnapshot(this); }
public IEnumerator <object> DiffSnapshots(HeapSnapshotInfo first, HeapSnapshotInfo last) { var moduleNames = new NameTable(StringComparer.Ordinal); var heapIds = new HashSet <UInt32>(); var functionNames = new NameTable(); var deltas = new List <DeltaInfo>(); var tracebacks = new Dictionary <UInt32, TracebackInfo>(); { var fModulesFirst = Database.SnapshotModules.Get(first.Index); var fModulesLast = Database.SnapshotModules.Get(last.Index); var fHeapsFirst = Database.SnapshotHeaps.Get(first.Index); var fHeapsLast = Database.SnapshotHeaps.Get(last.Index); yield return(fModulesFirst); foreach (var moduleName in fModulesFirst.Result) { moduleNames.Add(Path.GetFileNameWithoutExtension(moduleName)); } yield return(fHeapsFirst); heapIds.UnionWith(from heap in fHeapsFirst.Result select heap.HeapID); yield return(fModulesLast); foreach (var moduleName in fModulesLast.Result) { moduleNames.Add(Path.GetFileNameWithoutExtension(moduleName)); } yield return(fHeapsLast); heapIds.UnionWith(from heap in fHeapsLast.Result select heap.HeapID); } var allocationIds = new HashSet <UInt32>(); { var fAllocations = Database.HeapAllocations.Select(heapIds); using (fAllocations) yield return(fAllocations); yield return(Future.RunInThread(() => { foreach (var ids in fAllocations.Result) { allocationIds.UnionWith(ids); } })); } { var tracebackIds = new HashSet <UInt32>(); var deallocs = new Dictionary <UInt32, DeltaInfo>(); var allocs = new Dictionary <UInt32, DeltaInfo>(); var fAllocationRanges = Database.Allocations.Select(allocationIds); using (fAllocationRanges) yield return(fAllocationRanges); yield return(Future.RunInThread(() => { DeltaInfo delta; foreach (var item in fAllocationRanges.Result) { var ranges = item.Ranges.Array; for (int i = 0, c = item.Ranges.Count, o = item.Ranges.Offset; i < c; i++) { var range = ranges[i + o]; if ((range.First <= first.Index) && (range.Last >= first.Index) && (range.Last < last.Index) ) { // deallocation if (deallocs.TryGetValue(range.TracebackID, out delta)) { delta.CountDelta += 1; delta.BytesDelta += (int)(range.Size + range.Overhead); delta.OldCount += 1; delta.OldBytes += (int)(range.Size + range.Overhead); } else { deallocs.Add(range.TracebackID, new DeltaInfo { Added = false, BytesDelta = (int)(range.Size + range.Overhead), CountDelta = 1, NewBytes = 0, NewCount = 0, OldBytes = (int)(range.Size + range.Overhead), OldCount = 1, TracebackID = range.TracebackID, Traceback = null }); } tracebackIds.Add(range.TracebackID); } else if ( (range.First <= last.Index) && (range.First > first.Index) && (range.Last >= last.Index) ) { // allocation if (allocs.TryGetValue(range.TracebackID, out delta)) { delta.CountDelta += 1; delta.BytesDelta += (int)(range.Size + range.Overhead); delta.NewCount += 1; delta.NewBytes += (int)(range.Size + range.Overhead); } else { allocs.Add(range.TracebackID, new DeltaInfo { Added = true, BytesDelta = (int)(range.Size + range.Overhead), CountDelta = 1, NewBytes = (int)(range.Size + range.Overhead), NewCount = 1, OldBytes = 0, OldCount = 0, TracebackID = range.TracebackID, Traceback = null }); } tracebackIds.Add(range.TracebackID); } } } foreach (var tracebackId in tracebackIds) { if (allocs.TryGetValue(tracebackId, out delta)) { DeltaInfo dealloc; if (deallocs.TryGetValue(tracebackId, out dealloc)) { delta.OldBytes = dealloc.OldBytes; delta.OldCount = dealloc.OldCount; delta.BytesDelta = Math.Abs(delta.NewBytes - delta.OldBytes); delta.CountDelta = Math.Abs(delta.NewCount - delta.OldCount.Value); if (delta.NewBytes < delta.OldBytes) { delta.Added = false; } } if (delta.BytesDelta != 0) { deltas.Add(delta); } } else if (deallocs.TryGetValue(tracebackId, out delta)) { if (delta.BytesDelta != 0) { deltas.Add(delta); } } } })); var fTracebacks = Database.Tracebacks.Select(tracebackIds); using (fTracebacks) yield return(fTracebacks); Dictionary <UInt32, TracebackFrame> frameSymbols; { var rawFrames = new HashSet <UInt32>(); yield return(Future.RunInThread(() => { foreach (var traceback in fTracebacks.Result) { foreach (var rawFrame in traceback) { rawFrames.Add(rawFrame); } } })); var fSymbols = Database.SymbolCache.Select(rawFrames); using (fSymbols) yield return(fSymbols); var fSymbolDict = Future.RunInThread(() => SequenceUtils.ToDictionary(rawFrames, fSymbols.Result) ); yield return(fSymbolDict); frameSymbols = fSymbolDict.Result; } yield return(Future.RunInThread(() => { foreach (var tf in frameSymbols.Values) { if (tf.Function != null) { functionNames.Add(tf.Function); } } foreach (var traceback in fTracebacks.Result) { tracebacks[traceback.ID] = ConstructTracebackInfo( traceback.ID, traceback.Frames, frameSymbols ); } foreach (var d in deltas) { d.Traceback = tracebacks[d.TracebackID]; } })); } yield return(Future.RunInThread(() => deltas.Sort((lhs, rhs) => { var lhsBytes = (lhs.Added ? 1 : -1) * lhs.BytesDelta; var rhsBytes = (rhs.Added ? 1 : -1) * rhs.BytesDelta; return rhsBytes.CompareTo(lhsBytes); }) )); yield return(Result.New(new HeapDiff( null, moduleNames, functionNames, deltas, tracebacks ))); }
public static long GetAverageOccupiedHeapBlockSize(HeapSnapshotInfo item) { return(item.AverageOccupiedBlockSize); }
public static long GetHeapFragmentation(HeapSnapshotInfo item) { return((long)(item.HeapFragmentation * 10000)); }
public HeapSnapshot(int index, DateTime when, string filename, string text) { MemoryStatistics memory = new MemoryStatistics(); bool scanningForStart = true, scanningForMemory = false; Heap scanningHeap = null; var regexes = new Regexes(); int groupModule = regexes.SnapshotModule.GroupNumberFromName("module"); int groupModuleOffset = regexes.SnapshotModule.GroupNumberFromName("offset"); int groupModuleSize = regexes.SnapshotModule.GroupNumberFromName("size"); int groupHeaderId = regexes.HeapHeader.GroupNumberFromName("id"); int groupAllocOffset = regexes.Allocation.GroupNumberFromName("offset"); int groupAllocSize = regexes.Allocation.GroupNumberFromName("size"); int groupAllocOverhead = regexes.Allocation.GroupNumberFromName("overhead"); int groupAllocId = regexes.Allocation.GroupNumberFromName("id"); Match m; // Instead of allocating a tiny new UInt32[] for every traceback we read in, // we store groups of tracebacks into fixed-size buffers so that the GC has // less work to do when performing collections. Tracebacks are read-only after // being constructed, and all the tracebacks from a snapshot have the same // lifetime, so this works out well. var frameBuffer = new UInt32[FrameBufferSize]; int frameBufferCount = 0; var lr = new LineReader(text); LineReader.Line line; while (lr.ReadLine(out line)) { if (scanningHeap != null) { if (line.StartsWith("*-") && line.Contains("End of data for heap")) { scanningHeap.Allocations.TrimExcess(); scanningHeap = null; } else if (regexes.Allocation.TryMatch(ref line, out m)) { var tracebackId = UInt32.Parse(m.Groups[groupAllocId].Value, NumberStyles.HexNumber); Traceback traceback; if (!Tracebacks.TryGetValue(tracebackId, out traceback)) { // If the frame buffer could fill up while we're building our traceback, // let's allocate a new one. if (frameBufferCount >= frameBuffer.Length - MaxTracebackLength) { frameBuffer = new UInt32[frameBuffer.Length]; frameBufferCount = 0; } int firstFrame = frameBufferCount; // This is only valid if every allocation is followed by an empty line while (lr.ReadLine(out line)) { if (line.StartsWith("\t")) { frameBuffer[frameBufferCount++] = UInt32.Parse( line.ToString(), NumberStyles.HexNumber | NumberStyles.AllowLeadingWhite ); } else { lr.Rewind(ref line); break; } } Tracebacks.Add(traceback = new Traceback( tracebackId, new ArraySegment <UInt32>(frameBuffer, firstFrame, frameBufferCount - firstFrame) )); } scanningHeap.Allocations.Add(new Allocation( UInt32.Parse(m.Groups[groupAllocOffset].Value, NumberStyles.HexNumber), UInt32.Parse(m.Groups[groupAllocSize].Value, NumberStyles.HexNumber), UInt32.Parse(m.Groups[groupAllocOverhead].Value, NumberStyles.HexNumber), traceback.ID )); } } else if (scanningForMemory) { if (regexes.HeapHeader.TryMatch(ref line, out m)) { scanningHeap = new Heap(index, UInt32.Parse(m.Groups[groupHeaderId].Value, NumberStyles.HexNumber)); Heaps.Add(scanningHeap); } else if (line.StartsWith("// Memory=")) { memory = new MemoryStatistics(line.ToString()); scanningForMemory = false; break; } else { continue; } } else if (scanningForStart) { if (line.Contains("Loaded modules")) { scanningForStart = false; } else if (line.Contains("Start of data for heap")) { break; } else { continue; } } else { if (!regexes.SnapshotModule.TryMatch(ref line, out m)) { if (line.Contains("Process modules enumerated")) { scanningForMemory = true; } else { continue; } } else { var modulePath = Path.GetFullPath(m.Groups[groupModule].Value).ToLowerInvariant(); Modules.Add(new Module( modulePath, UInt32.Parse(m.Groups[groupModuleOffset].Value, System.Globalization.NumberStyles.HexNumber), UInt32.Parse(m.Groups[groupModuleSize].Value, System.Globalization.NumberStyles.HexNumber) )); } } } foreach (var heap in Heaps) { heap.Allocations.Sort( (lhs, rhs) => lhs.Address.CompareTo(rhs.Address) ); heap.ComputeStatistics(); } Info = new HeapSnapshotInfo(index, when, filename, memory, this); }
public long GetBytesTotal(HeapSnapshotInfo item) { return((long)(item.BytesTotal)); }
protected IEnumerator <object> LoadSnapshotFromDatabase(HeapSnapshotInfo info) { var result = new HeapSnapshot(info); var fModules = Database.SnapshotModules.Get(info.Index); var fHeaps = Database.SnapshotHeaps.Get(info.Index); using (fModules) yield return(fModules); var fModuleInfos = Database.Modules.Select( from moduleName in fModules.Result select moduleName ); using (fModuleInfos) yield return(fModuleInfos); foreach (var module in fModuleInfos.Result) { result.Modules.Add(module); } using (fHeaps) yield return(fHeaps); var heapIDs = from heap in fHeaps.Result select heap.HeapID; var fAllocations = Database.HeapAllocations.Select(heapIDs); using (fAllocations) yield return(fAllocations); var allocations = SequenceUtils.ToDictionary(heapIDs, fAllocations.Result); var tracebackIDs = new HashSet <UInt32>(); foreach (var heapInfo in fHeaps.Result) { var theHeap = new HeapSnapshot.Heap(heapInfo); var allocationIds = allocations[heapInfo.HeapID]; theHeap.Allocations.Capacity = allocationIds.Length; var fRanges = Database.Allocations.Select(allocationIds); using (fRanges) yield return(fRanges); yield return(Future.RunInThread(() => SequenceUtils.Zip( allocationIds, fRanges.Result, (id, ranges) => { HeapSnapshot.AllocationRanges.Range range; if (ranges.Get(info.Index, out range)) { theHeap.Allocations.Add(new HeapSnapshot.Allocation( id, range.Size, range.Overhead, range.TracebackID )); tracebackIDs.Add(range.TracebackID); } } ) )); result.Heaps.Add(theHeap); } var fTracebacks = Database.Tracebacks.Select(tracebackIDs); using (fTracebacks) yield return(fTracebacks); yield return(Future.RunInThread(() => { foreach (var traceback in fTracebacks.Result) { result.Tracebacks.Add(traceback); } })); yield return(Result.New(result)); }