Exemple #1
0
        public StackGraphNode GetNodeForFrame(TracebackFrame frameInfo, out bool isNew)
        {
            StackGraphNode result;

            if ((frameInfo.Module == null) || (frameInfo.Function == null))
            {
                isNew = false;
                return(null);
            }

            var key = new StackGraphKey(KeyType, frameInfo.Module, frameInfo.Function, frameInfo.SourceFile);

            lock (Lock) {
                if (!this.TryGetValue(key, out result))
                {
                    isNew           = true;
                    this.Add(result = new StackGraphNode(key));
                }
                else
                {
                    isNew = false;
                }
            }

            return(result);
        }
Exemple #2
0
        static void Deserialize(ref DeserializationContext context, out TracebackFrame output)
        {
            var br = new BinaryReader(context.Stream, Encoding.UTF8);

            output = new TracebackFrame();

            output.Offset = br.ReadUInt32();
            if (br.ReadBoolean())
            {
                output.Offset2 = br.ReadUInt32();
            }
            else
            {
                output.Offset2 = (UInt32)context.Key.Value;
            }

            output.Module     = ReadString(br);
            output.Function   = ReadString(br);
            output.SourceFile = ReadString(br);

            if (br.ReadBoolean())
            {
                output.SourceLine = br.ReadInt32();
            }
        }
Exemple #3
0
        static void Serialize(ref SerializationContext context, ref TracebackFrame input)
        {
            var bw = new BinaryWriter(context.Stream, Encoding.UTF8);

            bw.Write(input.Offset);

            bw.Write(false);
            if (input.Offset2.HasValue && (input.Offset2 != (UInt32)context.Key.Value))
            {
                throw new InvalidDataException();
            }

            /*
             * bw.Write(input.Offset2.HasValue);
             * if (input.Offset2.HasValue)
             *  bw.Write(input.Offset2.Value);
             */

            WriteString(bw, input.Module);
            WriteString(bw, input.Function);
            WriteString(bw, input.SourceFile);

            bw.Write(input.SourceLine.HasValue);
            if (input.SourceLine.HasValue)
            {
                bw.Write(input.SourceLine.Value);
            }

            bw.Flush();
        }
Exemple #4
0
        public bool IsMatch(TracebackFrame frame)
        {
            if ((ModuleRegex != null) && ((frame.Module == null) || !ModuleRegex.IsMatch(frame.Module)))
            {
                return(false);
            }

            if ((FunctionRegex != null) && ((frame.Function == null) || !FunctionRegex.IsMatch(frame.Function)))
            {
                return(false);
            }

            return(true);
        }
Exemple #5
0
        public StackGraphNode GetNodeForChildFrame(TracebackFrame frameInfo)
        {
            bool           isNew;
            StackGraphNode result;

            lock (Children)
                result = Children.GetNodeForFrame(frameInfo, out isNew);

            if (isNew)
            {
                lock (result.Parents)
                    result.Parents.Add(this);
            }

            return(result);
        }
Exemple #6
0
        static void Deserialize(ref DeserializationContext context, out TracebackFrame output)
        {
            var br = new BinaryReader(context.Stream, Encoding.UTF8);

            output = new TracebackFrame();

            output.Offset = br.ReadUInt32();
            if (br.ReadBoolean())
                output.Offset2 = br.ReadUInt32();

            output.Module = ReadString(br);
            output.Function = ReadString(br);
            output.SourceFile = ReadString(br);

            if (br.ReadBoolean())
                output.SourceLine = br.ReadInt32();
        }
Exemple #7
0
        protected bool ResolveFrame(UInt32 frame, out TracebackFrame resolved, out Future <TracebackFrame> pendingResolve)
        {
            if (ResolvedSymbolCache.TryGetValue(frame, out resolved))
            {
                pendingResolve = null;
                return(true);
            }

            if (!PendingSymbolResolves.TryGetValue(frame, out pendingResolve))
            {
                var f    = PendingSymbolResolves[frame] = new Future <TracebackFrame>();
                var item = new PendingSymbolResolve(frame, f);

                SymbolResolveQueue.Enqueue(item);
            }

            return(false);
        }
Exemple #8
0
        public bool Equals(TracebackFrame rhs)
        {
            if (Module != rhs.Module)
            {
                return(false);
            }
            if (Function != rhs.Function)
            {
                return(false);
            }
            if (Offset != rhs.Offset)
            {
                return(false);
            }
            if (Offset2 != rhs.Offset2)
            {
                return(false);
            }

            return(true);
        }
Exemple #9
0
        static void Serialize(ref SerializationContext context, ref TracebackFrame input)
        {
            var bw = new BinaryWriter(context.Stream, Encoding.UTF8);

            bw.Write(input.Offset);
            bw.Write(input.Offset2.HasValue);
            if (input.Offset2.HasValue)
            {
                bw.Write(input.Offset2.Value);
            }

            WriteString(bw, input.Module);
            WriteString(bw, input.Function);
            WriteString(bw, input.SourceFile);

            bw.Write(input.SourceLine.HasValue);
            if (input.SourceLine.HasValue)
            {
                bw.Write(input.SourceLine.Value);
            }

            bw.Flush();
        }
Exemple #10
0
 protected static string IndexSymbolByFunction(ref TracebackFrame frame)
 {
     var fn = (frame.Function ?? "???");
     return fn;
 }
Exemple #11
0
        protected static string IndexSymbolByFunction(ref TracebackFrame frame)
        {
            var fn = (frame.Function ?? "???");

            return(fn);
        }
        protected bool ResolveFrame(UInt32 frame, out TracebackFrame resolved, out Future<TracebackFrame> pendingResolve)
        {
            if (ResolvedSymbolCache.TryGetValue(frame, out resolved)) {
                pendingResolve = null;
                return true;
            }

            if (!PendingSymbolResolves.TryGetValue(frame, out pendingResolve)) {
                var f = PendingSymbolResolves[frame] = new Future<TracebackFrame>();
                var item = new PendingSymbolResolve(frame, f);

                SymbolResolveQueue.Enqueue(item);
            }

            return false;
        }
Exemple #13
0
        public StackGraphNode GetNodeForFrame(TracebackFrame frameInfo)
        {
            bool temp;

            return(GetNodeForFrame(frameInfo, out temp));
        }
Exemple #14
0
        protected IEnumerator <object> SymbolResolverTask()
        {
            var batch        = new List <PendingSymbolResolve>();
            var nullProgress = new CallbackProgressListener();

            ActivityIndicator.CountedItem progress = null;

            while (true)
            {
                var count = SymbolResolveBatchSize - batch.Count;
                SymbolResolveQueue.DequeueMultiple(batch, count);

                if (batch.Count == 0)
                {
                    if (progress != null)
                    {
                        progress.Decrement();
                        progress = null;
                    }

                    if (!SymbolResolveState.Progress.Active && (SymbolResolveQueue.Count <= 0))
                    {
                        SymbolResolveState.Count = 0;
                    }

                    var f = SymbolResolveQueue.Dequeue();
                    using (f)
                        yield return(f);

                    batch.Add(f.Result);
                }
                else
                {
                    if (progress == null)
                    {
                        progress = SymbolResolveState.Progress.Increment();
                    }

                    var maximum = SymbolResolveState.Count + Math.Max(0, SymbolResolveQueue.Count) + 1;
                    progress.Maximum  = maximum;
                    progress.Progress = Math.Min(maximum, SymbolResolveState.Count);

                    string infile = Path.GetTempFileName(), outfile = Path.GetTempFileName();

                    var padNumberRight = (Func <uint, int, string>)((num, length) => {
                        var result = String.Format("{0:X}", num);
                        if (result.Length < length)
                        {
                            result = new String(' ', length - result.Length) + result;
                        }

                        return(result);
                    });

                    var symbolModules = SymbolModules.ToArray();
                    yield return(Future.RunInThread(() => {
                        using (var sw = new StreamWriter(infile, false, Encoding.ASCII)) {
                            sw.WriteLine("// Loaded modules:");
                            sw.WriteLine("//     Base Size Module");

                            foreach (var module in symbolModules)
                            {
                                sw.WriteLine(
                                    "//            {0} {1} {2}",
                                    padNumberRight(module.BaseAddress, 8),
                                    padNumberRight(module.Size, 8),
                                    Path.GetFullPath(module.Filename)
                                    );
                            }

                            sw.WriteLine("//");
                            sw.WriteLine("// Process modules enumerated.");

                            sw.WriteLine();
                            sw.WriteLine("*- - - - - - - - - - Heap 0 Hogs - - - - - - - - - -");
                            sw.WriteLine();

                            for (int i = 0; i < batch.Count; i++)
                            {
                                sw.WriteLine(
                                    "{0:X8} bytes + {1:X8} at {2:X8} by BackTrace{3:X8}",
                                    1, 0, i + 1, i + 1
                                    );

                                sw.WriteLine("\t{0:X8}", batch[i].Frame);
                                sw.WriteLine();
                            }
                        }
                    }));

                    var psi = new ProcessStartInfo(
                        Settings.UmdhPath, String.Format(
                            "\"{0}\" -f:\"{1}\"", infile, outfile
                            )
                        );

                    using (var rp = Scheduler.Start(
                               Program.RunProcess(psi, ProcessPriorityClass.Idle),
                               TaskExecutionPolicy.RunAsBackgroundTask
                               ))
                        yield return(rp);

                    using (Finally.Do(() => {
                        try {
                            File.Delete(infile);
                        } catch {
                        }
                        try {
                            File.Delete(outfile);
                        } catch {
                        }
                    })) {
                        var rtc = new RunToCompletion <HeapDiff>(
                            HeapDiff.FromFile(outfile, nullProgress)
                            );

                        using (rtc)
                            yield return(rtc);

                        var fProcess = Future.RunInThread(() => {
                            var cacheBatch = Database.SymbolCache.CreateBatch(batch.Count);

                            DecisionUpdateCallback <HashSet <UInt32> > updateCallback = (ref HashSet <UInt32> oldValue, ref HashSet <UInt32> newValue) => {
                                newValue.UnionWith(oldValue);
                                return(true);
                            };

                            foreach (var traceback in rtc.Result.Tracebacks)
                            {
                                var index = (int)(traceback.Key) - 1;

                                var key   = batch[index].Frame;
                                var frame = traceback.Value.Frames.Array[traceback.Value.Frames.Offset];
                                batch[index].Result.Complete(frame);

                                lock (SymbolResolveLock) {
                                    ResolvedSymbolCache[key] = frame;
                                    PendingSymbolResolves.Remove(key);
                                }

                                cacheBatch.Add(key, frame);
                                if (frame.Function != null)
                                {
                                    var tempHash = new HashSet <uint>();
                                    tempHash.Add(key);
                                }
                            }

                            foreach (var frame in batch)
                            {
                                if (frame.Result.Completed)
                                {
                                    continue;
                                }

                                Interlocked.Increment(ref TotalFrameResolveFailures);

                                var tf = new TracebackFrame(frame.Frame);

                                frame.Result.Complete(tf);

                                lock (SymbolResolveLock) {
                                    ResolvedSymbolCache[frame.Frame] = tf;
                                    PendingSymbolResolves.Remove(frame.Frame);
                                }

                                cacheBatch.Add(frame.Frame, tf);

                                // Console.WriteLine("Could not resolve: {0:X8}", frame.Frame);
                            }

                            return(new IBatch[] { cacheBatch });
                        });

                        yield return(fProcess);

                        foreach (var manglerBatch in fProcess.Result)
                        {
                            yield return(manglerBatch.Execute());
                        }

                        Interlocked.Add(ref SymbolResolveState.Count, batch.Count);
                        batch.Clear();
                    }
                }
            }
        }
Exemple #15
0
        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));
        }
Exemple #16
0
        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);
        }
Exemple #17
0
        protected IEnumerator<object> SymbolResolverTask()
        {
            var batch = new List<UInt32>();
            var nullProgress = new CallbackProgressListener();
            ActivityIndicator.CountedItem progress = null;

            while (true) {
                var count = SymbolResolveBatchSize - batch.Count;
                SymbolResolveQueue.DequeueMultiple(batch, count);

                if (batch.Count == 0) {
                    if (progress != null) {
                        progress.Decrement();
                        progress = null;
                    }

                    if (!SymbolResolveState.Progress.Active && (SymbolResolveQueue.Count <= 0)) {
                        SymbolResolveState.Count = 0;
                        OnSymbolCacheUpdated();
                    }

                    var f = SymbolResolveQueue.Dequeue();
                    using (f)
                        yield return f;

                    batch.Add(f.Result);
                } else {
                    if (progress == null)
                        progress = SymbolResolveState.Progress.Increment();

                    var maximum = SymbolResolveState.Count + Math.Max(0, SymbolResolveQueue.Count) + 1;
                    progress.Maximum = maximum;
                    progress.Progress = Math.Min(maximum, SymbolResolveState.Count);

                    string infile = Path.GetTempFileName(), outfile = Path.GetTempFileName();

                    var padNumberRight = (Func<uint, int, string>)((num, length) => {
                        var result = String.Format("{0:X}", num);
                        if (result.Length < length)
                            result = new String(' ', length - result.Length) + result;

                        return result;
                    });

                    var symbolModules = SymbolModules.ToArray();
                    yield return Future.RunInThread(() => {
                        using (var sw = new StreamWriter(infile, false, Encoding.ASCII)) {
                            sw.WriteLine("// Loaded modules:");
                            sw.WriteLine("//     Base Size Module");

                            foreach (var module in symbolModules)
                                sw.WriteLine(
                                    "//            {0} {1} {2}",
                                    padNumberRight(module.BaseAddress, 8),
                                    padNumberRight(module.Size, 8),
                                    Path.GetFullPath(module.Filename)
                                );

                            sw.WriteLine("//");
                            sw.WriteLine("// Process modules enumerated.");

                            sw.WriteLine();
                            sw.WriteLine("*- - - - - - - - - - Heap 0 Hogs - - - - - - - - - -");
                            sw.WriteLine();

                            for (int i = 0; i < batch.Count; i++) {
                                sw.WriteLine(
                                    "{0:X8} bytes + {1:X8} at {2:X8} by BackTrace{3:X8}",
                                    1, 0, i + 1, i + 1
                                );

                                sw.WriteLine("\t{0:X8}", batch[i]);
                                sw.WriteLine();
                            }
                        }
                    });

                    IDictionary<string, string> environment = null;
                    yield return GetEnvironment().Bind(() => environment);

                    var psi = new ProcessStartInfo(
                        Settings.UmdhPath, String.Format(
                            "\"{0}\" -f:\"{1}\"", infile, outfile
                        )
                    );

                    using (var rp = Scheduler.Start(
                        Program.RunProcess(
                            psi, ProcessPriorityClass.Idle, environment
                        ),
                        TaskExecutionPolicy.RunAsBackgroundTask
                    ))
                        yield return rp;

                    using (Finally.Do(() => {
                        try {
                            File.Delete(infile);
                        } catch {
                        }
                        try {
                            File.Delete(outfile);
                        } catch {
                        }
                    })) {
                        var rtc = new RunToCompletion<HeapDiff>(
                            HeapDiff.FromFile(outfile, nullProgress)
                        );

                        using (rtc)
                            yield return rtc;

                        var fProcess = Future.RunInThread(() => {
                            var cacheBatch = Database.SymbolCache.CreateBatch(batch.Count);

                            DecisionUpdateCallback<HashSet<UInt32>> updateCallback = (ref HashSet<UInt32> oldValue, ref HashSet<UInt32> newValue) => {
                                newValue.UnionWith(oldValue);
                                return true;
                            };

                            foreach (var traceback in rtc.Result.Tracebacks) {
                                var index = (int)(traceback.Key) - 1;

                                var key = batch[index];
                                var frame = traceback.Value.Frames.Array[traceback.Value.Frames.Offset];

                                lock (SymbolResolveLock) {
                                    ResolvedSymbolCache[key] = frame;
                                    PendingSymbolResolves.Remove(key);
                                }

                                cacheBatch.Add(key, frame);
                                if (frame.Function != null) {
                                    var tempHash = new HashSet<uint>();
                                    tempHash.Add(key);
                                }
                            }

                            foreach (var frame in batch) {
                                if (!PendingSymbolResolves.Contains(frame))
                                    continue;

                                Interlocked.Increment(ref TotalFrameResolveFailures);

                                var tf = new TracebackFrame(frame);

                                lock (SymbolResolveLock) {
                                    ResolvedSymbolCache[frame] = tf;
                                    PendingSymbolResolves.Remove(frame);
                                }

                                cacheBatch.Add(frame, tf);

                                // Console.WriteLine("Could not resolve: {0:X8}", frame.Frame);
                            }

                            return new IBatch[] { cacheBatch };
                        });

                        yield return fProcess;

                        foreach (var manglerBatch in fProcess.Result)
                            yield return manglerBatch.Execute();

                        Interlocked.Add(ref SymbolResolveState.Count, batch.Count);
                        batch.Clear();
                    }
                }
            }
        }
Exemple #18
0
        protected bool ResolveFrame(UInt32 frame, out TracebackFrame resolved)
        {
            if (ResolvedSymbolCache.TryGetValue(frame, out resolved)) {
                return true;
            }

            bool temp;
            if (!PendingSymbolResolves.Contains(frame)) {
                PendingSymbolResolves.Add(frame);
                SymbolResolveQueue.Enqueue(frame);
            }

            return false;
        }
Exemple #19
0
        static void Serialize(ref SerializationContext context, ref TracebackFrame input)
        {
            var bw = new BinaryWriter(context.Stream, Encoding.UTF8);

            bw.Write(input.Offset);
            bw.Write(input.Offset2.HasValue);
            if (input.Offset2.HasValue)
                bw.Write(input.Offset2.Value);

            WriteString(bw, input.Module);
            WriteString(bw, input.Function);
            WriteString(bw, input.SourceFile);

            bw.Write(input.SourceLine.HasValue);
            if (input.SourceLine.HasValue)
                bw.Write(input.SourceLine.Value);

            bw.Flush();
        }