Example #1
0
        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);
        }
Example #2
0
        public long GetAllocationCount(HeapSnapshotInfo item)
        {
            FilteredHeapSnapshotInfo info = item;

            if (CurrentFilterData != null)
            {
                if (!CurrentFilterData.TryGetValue(item, out info))
                {
                    info = item;
                }
            }

            return((long)(info.AllocationCount));
        }
Example #3
0
        public long GetBytesTotal(HeapSnapshotInfo item)
        {
            FilteredHeapSnapshotInfo info = item;

            if (CurrentFilterData != null)
            {
                if (!CurrentFilterData.TryGetValue(item, out info))
                {
                    info = item;
                }
            }

            return((long)(info.BytesTotal));
        }
Example #4
0
        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);
        }
Example #5
0
        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();
            }
        }
Example #6
0
        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
                );
        }
Example #7
0
 public static long GetLargestOccupiedHeapBlock(HeapSnapshotInfo item)
 {
     return(item.LargestOccupiedHeapBlock);
 }
Example #8
0
 public static long GetAverageFreeHeapBlockSize(HeapSnapshotInfo item)
 {
     return(item.AverageFreeBlockSize);
 }
Example #9
0
 public static long GetWorkingSet(HeapSnapshotInfo item)
 {
     return(item.Memory.WorkingSet);
 }
Example #10
0
 public static long GetVirtualMemory(HeapSnapshotInfo item)
 {
     return(item.Memory.Virtual);
 }
Example #11
0
 public static long GetPagedMemory(HeapSnapshotInfo item)
 {
     return(item.Memory.Paged);
 }
Example #12
0
        public static IEnumerator <object> LoadFromDatabase(DatabaseFile db, HeapSnapshotInfo info)
        {
            var fResult = db.Snapshots.Get(info.Index);

            yield return(fResult);
        }
Example #13
0
 internal HeapSnapshot(HeapSnapshotInfo info)
 {
     Info = info;
     info.SetSnapshot(this);
 }
Example #14
0
        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
                                        )));
        }
Example #15
0
 public static long GetAverageOccupiedHeapBlockSize(HeapSnapshotInfo item)
 {
     return(item.AverageOccupiedBlockSize);
 }
Example #16
0
 public static long GetHeapFragmentation(HeapSnapshotInfo item)
 {
     return((long)(item.HeapFragmentation * 10000));
 }
Example #17
0
        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);
        }
Example #18
0
 public long GetBytesTotal(HeapSnapshotInfo item)
 {
     return((long)(item.BytesTotal));
 }
Example #19
0
        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));
        }