コード例 #1
0
ファイル: StackGraph.cs プロジェクト: konlil/HeapProfiler
        public void Visit(DeltaInfo delta)
        {
            lock (this) {
                if (VisitedTracebacks.Contains(delta.TracebackID))
                {
                    return;
                }
                else
                {
                    VisitedTracebacks.Add(delta.TracebackID);
                }

                Allocations    += delta.CountDelta.GetValueOrDefault(0);
                BytesRequested += delta.BytesDelta;
            }
        }
コード例 #2
0
ファイル: HeapDiff.cs プロジェクト: konlil/HeapProfiler
        public static IEnumerator <object> FromFile(string filename, IProgressListener progress)
        {
            progress.Status = "Loading diff...";

            Future <string> fText;

            // We could stream the lines in from the IO thread while we parse them, but this
            //  part of the load is usually pretty quick even on a regular hard disk, and
            //  loading the whole diff at once eliminates some context switches
            using (var fda = new FileDataAdapter(
                       filename, FileMode.Open,
                       FileAccess.Read, FileShare.Read, 1024 * 128
                       )) {
                var fBytes = fda.ReadToEnd();
                yield return(fBytes);

                fText = Future.RunInThread(
                    () => Encoding.ASCII.GetString(fBytes.Result)
                    );
                yield return(fText);
            }

            yield return(fText);

            var lr = new LineReader(fText.Result);

            LineReader.Line line;

            progress.Status = "Parsing diff...";

            var frames        = new List <TracebackFrame>();
            var moduleNames   = new NameTable(StringComparer.Ordinal);
            var symbolTypes   = new NameTable(StringComparer.Ordinal);
            var functionNames = new NameTable(StringComparer.Ordinal);
            var deltas        = new List <DeltaInfo>();
            var tracebacks    = new Dictionary <UInt32, TracebackInfo>();

            var regexes = new Regexes();

            // Regex.Groups[string] does an inefficient lookup, so we do that lookup once here
            int groupModule            = regexes.DiffModule.GroupNumberFromName("module");
            int groupSymbolType        = regexes.DiffModule.GroupNumberFromName("symbol_type");
            int groupTraceId           = regexes.BytesDelta.GroupNumberFromName("trace_id");
            int groupType              = regexes.BytesDelta.GroupNumberFromName("type");
            int groupDeltaBytes        = regexes.BytesDelta.GroupNumberFromName("delta_bytes");
            int groupNewBytes          = regexes.BytesDelta.GroupNumberFromName("new_bytes");
            int groupOldBytes          = regexes.BytesDelta.GroupNumberFromName("old_bytes");
            int groupNewCount          = regexes.BytesDelta.GroupNumberFromName("new_count");
            int groupOldCount          = regexes.CountDelta.GroupNumberFromName("old_count");
            int groupCountDelta        = regexes.CountDelta.GroupNumberFromName("delta_count");
            int groupTracebackModule   = regexes.TracebackFrame.GroupNumberFromName("module");
            int groupTracebackFunction = regexes.TracebackFrame.GroupNumberFromName("function");
            int groupTracebackOffset   = regexes.TracebackFrame.GroupNumberFromName("offset");
            int groupTracebackOffset2  = regexes.TracebackFrame.GroupNumberFromName("offset2");
            int groupTracebackPath     = regexes.TracebackFrame.GroupNumberFromName("path");
            int groupTracebackLine     = regexes.TracebackFrame.GroupNumberFromName("line");

            var delay = new Sleep(0.01);
            int i     = 0;

            while (lr.ReadLine(out line))
            {
retryFromHere:
                i += 1;
                if (i % ProgressInterval == 0)
                {
                    progress.Maximum  = lr.Length;
                    progress.Progress = lr.Position;

                    // Suspend processing for a bit
                    yield return(delay);
                }

                Match m;
                if (regexes.DiffModule.TryMatch(ref line, out m))
                {
                    moduleNames.Add(m.Groups[groupModule].Value);
                }
                else if (regexes.BytesDelta.TryMatch(ref line, out m))
                {
                    var added   = (m.Groups[groupType].Value == "+");
                    var traceId = UInt32.Parse(m.Groups[groupTraceId].Value, NumberStyles.HexNumber);
                    var info    = new DeltaInfo {
                        BytesDelta = int.Parse(m.Groups[groupDeltaBytes].Value, NumberStyles.HexNumber) *
                                     (added ? 1 : -1),
                        NewBytes = int.Parse(m.Groups[groupNewBytes].Value, NumberStyles.HexNumber),
                        OldBytes = int.Parse(m.Groups[groupOldBytes].Value, NumberStyles.HexNumber),
                        NewCount = int.Parse(m.Groups[groupNewCount].Value, NumberStyles.HexNumber),
                    };

                    if (lr.ReadLine(out line))
                    {
                        if (regexes.CountDelta.TryMatch(ref line, out m))
                        {
                            info.OldCount   = int.Parse(m.Groups[groupOldCount].Value, NumberStyles.HexNumber);
                            info.CountDelta = int.Parse(m.Groups[groupCountDelta].Value, NumberStyles.HexNumber) *
                                              (added ? 1 : -1);
                        }
                    }

                    bool readingLeadingWhitespace = true, doRetry = false;

                    frames.Clear();
                    var itemModules = new NameTable(StringComparer.Ordinal);
                    var itemFunctions = new NameTable(StringComparer.Ordinal);

                    while (lr.ReadLine(out line))
                    {
                        if (line.ToString().Trim().Length == 0)
                        {
                            if (readingLeadingWhitespace)
                            {
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }
                        else if (regexes.TracebackFrame.TryMatch(ref line, out m))
                        {
                            readingLeadingWhitespace = false;

                            var moduleName = moduleNames[m.Groups[groupTracebackModule].Value];
                            itemModules.Add(moduleName);

                            var functionName = functionNames[m.Groups[groupTracebackFunction].Value];
                            itemFunctions.Add(functionName);

                            var frame = new TracebackFrame {
                                Module   = moduleName,
                                Function = functionName,
                                Offset   = UInt32.Parse(m.Groups[groupTracebackOffset].Value, NumberStyles.HexNumber)
                            };
                            if (m.Groups[groupTracebackOffset2].Success)
                            {
                                frame.Offset2 = UInt32.Parse(m.Groups[groupTracebackOffset2].Value, NumberStyles.HexNumber);
                            }

                            if (m.Groups[groupTracebackPath].Success)
                            {
                                frame.SourceFile = m.Groups[groupTracebackPath].Value;
                            }

                            if (m.Groups[groupTracebackLine].Success)
                            {
                                frame.SourceLine = int.Parse(m.Groups[groupTracebackLine].Value);
                            }

                            frames.Add(frame);
                        }
                        else
                        {
                            // We hit the beginning of a new allocation, so make sure it gets parsed
                            doRetry = true;
                            break;
                        }
                    }

                    if (tracebacks.ContainsKey(traceId))
                    {
                        info.Traceback = tracebacks[traceId];
                        Program.ErrorList.ReportError("Duplicate traceback for id {0}!", traceId);
                    }
                    else
                    {
                        var frameArray = ImmutableArrayPool <TracebackFrame> .Allocate(frames.Count);

                        frames.CopyTo(frameArray.Array, frameArray.Offset);

                        info.Traceback = tracebacks[traceId] = new TracebackInfo {
                            TraceId   = traceId,
                            Frames    = frameArray,
                            Modules   = itemModules,
                            Functions = itemFunctions
                        };
                    }

                    deltas.Add(info);

                    if (doRetry)
                    {
                        goto retryFromHere;
                    }
                }
                else if (line.StartsWith("//"))
                {
                    // Comment, ignore it
                }
                else if (line.StartsWith("Total increase") || line.StartsWith("Total decrease"))
                {
                    // Ignore this too
                }
                else if (line.StartsWith("         ") && (line.EndsWith(".pdb")))
                {
                    // Symbol path for a module, ignore it
                }
                else
                {
                    Program.ErrorList.ReportError("Unrecognized diff content: {0}", line.ToString());
                }
            }

            var result = new HeapDiff(
                filename, moduleNames, functionNames, deltas, tracebacks
                );

            yield return(new Result(result));
        }
コード例 #3
0
ファイル: HeapDiff.cs プロジェクト: konlil/HeapProfiler
 public DeltaInfoTooltipContent(DeltaInfo delta, DeltaInfo.RenderParams renderParams)
 {
     Delta        = delta;
     RenderParams = renderParams;
 }
コード例 #4
0
ファイル: HeapDiff.cs プロジェクト: ctalbert/HeapProfiler
        public float Render(Graphics g, ref DeltaInfo.RenderParams rp, string headerText)
        {
            var lineHeight = g.MeasureString(
                "AaBbYyZz", rp.Font, rp.ContentRegion.Width, rp.StringFormat
            ).Height;

            g.ResetClip();
            g.FillRectangle(rp.ShadeBrush, 0, rp.ContentRegion.Y, rp.ContentRegion.Width, lineHeight - 1);

            var y = 0.0f;

            g.DrawString(headerText, rp.Font, rp.TextBrush, 0.0f, rp.ContentRegion.Top + y, rp.StringFormat);
            y += g.MeasureString(headerText, rp.Font, rp.ContentRegion.Width, rp.StringFormat).Height;

            int f = 0;
            for (int i = 0, c = Frames.Count, o = Frames.Offset; i < c; i++) {
                var frame = Frames.Array[i + o];
                var text = frame.ToString();

                var layoutRect = new RectangleF(
                    0.0f, rp.ContentRegion.Top + y, rp.ContentRegion.Width, lineHeight
                );
                Region[] fillRegions = null;

                g.ResetClip();

                Match m;
                if ((rp.FunctionFilter != null) && (frame.Function != null) && rp.FunctionFilter.TryMatch(frame.Function, out m)) {
                    var startIndex = m.Index + text.IndexOf(frame.Function);
                    var endIndex = startIndex + m.Length;

                    if ((endIndex > startIndex) && (startIndex >= 0)) {
                        rp.StringFormat.SetMeasurableCharacterRanges(new[] {
                            new CharacterRange(startIndex, endIndex - startIndex)
                        });

                        fillRegions = g.MeasureCharacterRanges(
                            text, rp.Font, layoutRect, rp.StringFormat
                        );

                        foreach (var fillRegion in fillRegions) {
                            g.SetClip(fillRegion, System.Drawing.Drawing2D.CombineMode.Replace);
                            g.FillRegion(rp.FunctionHighlightBrush, fillRegion);
                            g.DrawString(text, rp.Font, rp.FunctionHighlightTextBrush, layoutRect, rp.StringFormat);
                        }

                        g.ResetClip();
                        foreach (var fillRegion in fillRegions) {
                            g.ExcludeClip(fillRegion);
                        }
                    }
                }

                g.DrawString(text, rp.Font, rp.TextBrush, layoutRect, rp.StringFormat);

                y += g.MeasureString(text, rp.Font, rp.ContentRegion.Width, rp.StringFormat).Height;

                f += 1;
                if ((f == 2) && !rp.IsExpanded) {
                    if (Frames.Count > 2) {
                        rp.StringFormat.Alignment = StringAlignment.Far;

                        var elideString = String.Format(
                            "(+{0} frame(s))", Frames.Count - 2
                        );
                        rp.StringFormat.SetMeasurableCharacterRanges(
                            new[] { new CharacterRange(0, elideString.Length) }
                        );

                        var regions = g.MeasureCharacterRanges(elideString, rp.Font, layoutRect, rp.StringFormat);
                        foreach (var region in regions)
                            g.FillRegion(rp.ElideBackgroundBrush, region);

                        g.DrawString(elideString, rp.Font, rp.ElideTextBrush, layoutRect, rp.StringFormat);

                        rp.StringFormat.Alignment = StringAlignment.Near;
                    }

                    break;
                }
            }

            return y;
        }
コード例 #5
0
ファイル: HeapDiff.cs プロジェクト: ctalbert/HeapProfiler
        public static IEnumerator<object> FromFile(string filename, IProgressListener progress)
        {
            progress.Status = "Loading diff...";

            Future<string> fText;

            // We could stream the lines in from the IO thread while we parse them, but this
            //  part of the load is usually pretty quick even on a regular hard disk, and
            //  loading the whole diff at once eliminates some context switches
            using (var fda = new FileDataAdapter(
                filename, FileMode.Open,
                FileAccess.Read, FileShare.Read, 1024 * 128
            )) {
                var fBytes = fda.ReadToEnd();
                yield return fBytes;

                fText = Future.RunInThread(
                    () => Encoding.ASCII.GetString(fBytes.Result)
                );
                yield return fText;
            }

            yield return fText;
            var lr = new LineReader(fText.Result);
            LineReader.Line line;

            progress.Status = "Parsing diff...";

            var frames = new List<TracebackFrame>();
            var moduleNames = new NameTable(StringComparer.Ordinal);
            var symbolTypes = new NameTable(StringComparer.Ordinal);
            var functionNames = new NameTable(StringComparer.Ordinal);
            var deltas = new List<DeltaInfo>();
            var tracebacks = new Dictionary<UInt32, TracebackInfo>();

            var regexes = new Regexes();

            // Regex.Groups[string] does an inefficient lookup, so we do that lookup once here
            int groupModule = regexes.DiffModule.GroupNumberFromName("module");
            int groupSymbolType = regexes.DiffModule.GroupNumberFromName("symbol_type");
            int groupTraceId = regexes.BytesDelta.GroupNumberFromName("trace_id");
            int groupType = regexes.BytesDelta.GroupNumberFromName("type");
            int groupDeltaBytes = regexes.BytesDelta.GroupNumberFromName("delta_bytes");
            int groupNewBytes = regexes.BytesDelta.GroupNumberFromName("new_bytes");
            int groupOldBytes = regexes.BytesDelta.GroupNumberFromName("old_bytes");
            int groupNewCount = regexes.BytesDelta.GroupNumberFromName("new_count");
            int groupOldCount = regexes.CountDelta.GroupNumberFromName("old_count");
            int groupCountDelta = regexes.CountDelta.GroupNumberFromName("delta_count");
            int groupTracebackModule = regexes.TracebackFrame.GroupNumberFromName("module");
            int groupTracebackFunction = regexes.TracebackFrame.GroupNumberFromName("function");
            int groupTracebackOffset = regexes.TracebackFrame.GroupNumberFromName("offset");
            int groupTracebackOffset2 = regexes.TracebackFrame.GroupNumberFromName("offset2");
            int groupTracebackPath = regexes.TracebackFrame.GroupNumberFromName("path");
            int groupTracebackLine = regexes.TracebackFrame.GroupNumberFromName("line");

            int i = 0;
            while (lr.ReadLine(out line)) {
                if (i % ProgressInterval == 0) {
                    progress.Maximum = lr.Length;
                    progress.Progress = lr.Position;

                    // Suspend processing until any messages in the windows message queue have been processed
                    yield return new Yield();
                }

            retryFromHere:

                Match m;
                if (regexes.DiffModule.TryMatch(ref line, out m)) {
                    moduleNames.Add(m.Groups[groupModule].Value);
                } else if (regexes.BytesDelta.TryMatch(ref line, out m)) {
                    var traceId = UInt32.Parse(m.Groups[groupTraceId].Value, NumberStyles.HexNumber);
                    var info = new DeltaInfo {
                        Added = (m.Groups[groupType].Value == "+"),
                        BytesDelta = int.Parse(m.Groups[groupDeltaBytes].Value, NumberStyles.HexNumber),
                        NewBytes = int.Parse(m.Groups[groupNewBytes].Value, NumberStyles.HexNumber),
                        OldBytes = int.Parse(m.Groups[groupOldBytes].Value, NumberStyles.HexNumber),
                        NewCount = int.Parse(m.Groups[groupNewCount].Value, NumberStyles.HexNumber),
                    };

                    if (lr.ReadLine(out line)) {
                        if (regexes.CountDelta.TryMatch(ref line, out m)) {
                            info.OldCount = int.Parse(m.Groups[groupOldCount].Value, NumberStyles.HexNumber);
                            info.CountDelta = int.Parse(m.Groups[groupCountDelta].Value, NumberStyles.HexNumber);
                        }
                    }

                    bool readingLeadingWhitespace = true, doRetry = false;

                    frames.Clear();
                    var itemModules = new NameTable(StringComparer.Ordinal);
                    var itemFunctions = new NameTable(StringComparer.Ordinal);

                    while (lr.ReadLine(out line)) {
                        if (line.ToString().Trim().Length == 0) {
                            if (readingLeadingWhitespace)
                                continue;
                            else
                                break;
                        } else if (regexes.TracebackFrame.TryMatch(ref line, out m)) {
                            readingLeadingWhitespace = false;

                            var moduleName = moduleNames[m.Groups[groupTracebackModule].Value];
                            itemModules.Add(moduleName);

                            var functionName = functionNames[m.Groups[groupTracebackFunction].Value];
                            itemFunctions.Add(functionName);

                            var frame = new TracebackFrame {
                                Module = moduleName,
                                Function = functionName,
                                Offset = UInt32.Parse(m.Groups[groupTracebackOffset].Value, NumberStyles.HexNumber)
                            };
                            if (m.Groups[groupTracebackOffset2].Success)
                                frame.Offset2 = UInt32.Parse(m.Groups[groupTracebackOffset2].Value, NumberStyles.HexNumber);

                            if (m.Groups[groupTracebackPath].Success)
                                frame.SourceFile = m.Groups[groupTracebackPath].Value;

                            if (m.Groups[groupTracebackLine].Success)
                                frame.SourceLine = int.Parse(m.Groups[groupTracebackLine].Value);

                            frames.Add(frame);
                        } else {
                            // We hit the beginning of a new allocation, so make sure it gets parsed
                            doRetry = true;
                            break;
                        }
                    }

                    if (tracebacks.ContainsKey(traceId)) {
                        info.Traceback = tracebacks[traceId];
                        Console.WriteLine("Duplicate traceback for id {0}!", traceId);
                    } else {
                        var frameArray = ImmutableArrayPool<TracebackFrame>.Allocate(frames.Count);
                        frames.CopyTo(frameArray.Array, frameArray.Offset);

                        info.Traceback = tracebacks[traceId] = new TracebackInfo {
                            TraceId = traceId,
                            Frames = frameArray,
                            Modules = itemModules,
                            Functions = itemFunctions
                        };
                    }

                    deltas.Add(info);

                    if (doRetry)
                        goto retryFromHere;
                } else if (line.StartsWith("//")) {
                    // Comment, ignore it
                } else if (line.StartsWith("Total increase") || line.StartsWith("Total decrease")) {
                    // Ignore this too
                } else if (line.StartsWith("         ") && (line.EndsWith(".pdb"))) {
                    // Symbol path for a module, ignore it
                } else {
                    Console.WriteLine("Unrecognized diff content: {0}", line.ToString());
                }
            }

            var result = new HeapDiff(
                filename, moduleNames, functionNames, deltas, tracebacks
            );
            yield return new Result(result);
        }
コード例 #6
0
ファイル: HeapDiff.cs プロジェクト: ctalbert/HeapProfiler
 public DeltaInfoTooltipContent(DeltaInfo delta, DeltaInfo.RenderParams renderParams)
 {
     Delta = delta;
     RenderParams = renderParams;
 }