protected IEnumerator <object> FinishShowingTooltip( Point mouseLocation, HeapSnapshot.Heap heap, HeapSnapshot.Allocation allocation, HeapSnapshot.Traceback rawTraceback ) { var uniqueRawFrames = rawTraceback.Frames.AsEnumerable().Distinct(); var fSymbols = Instance.Database.SymbolCache.Select(uniqueRawFrames); using (fSymbols) yield return(fSymbols); var symbolDict = SequenceUtils.ToDictionary( uniqueRawFrames, fSymbols.Result ); var tracebackInfo = HeapRecording.ConstructTracebackInfo( rawTraceback.ID, rawTraceback.Frames, symbolDict ); var renderParams = new DeltaInfo.RenderParams { BackgroundBrush = new SolidBrush(SystemColors.Info), BackgroundColor = SystemColors.Info, TextBrush = new SolidBrush(SystemColors.InfoText), IsExpanded = true, IsSelected = false, Font = Font, ShadeBrush = new SolidBrush(Color.FromArgb(31, 0, 0, 0)), StringFormat = CustomTooltip.GetDefaultStringFormat() }; var content = new HeapSnapshot.AllocationTooltipContent( ref allocation, ref tracebackInfo, ref renderParams ) { Location = mouseLocation, Font = Font }; using (var g = CreateGraphics()) CustomTooltip.FitContentOnScreen( g, content, ref content.RenderParams.Font, ref content.Location, ref content.Size ); Tooltip.SetContent(content); }
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 ))); }
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)); }