////////////////////////////////////////////////////////////////////////////////// // // Private Implementation part // ////////////////////////////////////////////////////////////////////////////////// private void ConsoleBreakHandler(Object sender, ConsoleCancelEventArgs e) { // When Control+C is pressed, the Console.Readline() returns immediatelly with // null. There is no way how to distinguish between EOF and Ctrl+C. Therefore we set // a m_isConsoleBreakHandlerExecuted to true whenever the handler is executed. // The code around Console.ReadLine() check when null is returned if the // m_isConsoleBreakHandlerExecuted flag is set. If yes, we know that this is caused by // Ctrl+C, the code clrears the flag and repeats the read. m_isConsoleBreakHandlerExecuted = true; switch (e.SpecialKey) { case ConsoleSpecialKey.ControlBreak: Console.WriteLine(); WriteOutput(MDbgOutputConstants.StdError, "Immediate debugger termination reqested through <Ctrl+Break>"); WriteOutput(MDbgOutputConstants.StdError, "To break into debugger use Ctrl+C instead."); // // When ControlBreak is pressed, we cannot set e.Cancel=true.... // break; case ConsoleSpecialKey.ControlC: try { WriteOutput(MDbgOutputConstants.StdOutput, "\n<Ctrl+C>"); MDbgProcess p = m_shell.Debugger.Processes.Active; if (p.IsRunning) { p.AsyncStop().WaitOne(); } } catch { } e.Cancel = true; break; default: break; } }
protected virtual void Dispose(bool disposing) { // 防止被多次调用 if (disposed) { return; } if (disposing) { // 清除所有托管资源 if (_mdbgProcess != null) { // 确保基本进程在datach前已经终止了 var waithandler = _mdbgProcess.AsyncStop(); waithandler.WaitOne(); _mdbgProcess.Detach(); } } disposed = true; }
protected virtual void Dispose(bool disposing) { // Protect from being called multiple times. if (disposed) { return; } if (disposing) { // Clean up all managed resources. if (_mdbgProcess != null) { // Make sure the underlying CorProcess was stopped before // detached it. var waithandler = _mdbgProcess.AsyncStop(); waithandler.WaitOne(); _mdbgProcess.Detach(); } } disposed = true; }
static void Main(string[] args) { if (args.Length < 1) { Usage(); return; } int samples = 10; int sampleInterval = 1000; var state = ParseState.Unknown; foreach (var arg in args.Skip(1)) { switch (state) { case ParseState.Unknown: if (arg.ToLower() == "/s") { state = ParseState.Samples; } else if (arg.ToLower() == "/i") { state = ParseState.Interval; } else { Usage(); return; } break; case ParseState.Samples: if (!Int32.TryParse(arg, out samples)) { Usage(); return; } state = ParseState.Unknown; break; case ParseState.Interval: if (!Int32.TryParse(arg, out sampleInterval)) { Usage(); return; } state = ParseState.Unknown; break; default: break; } } string pidOrProcess = args[0]; var stats = new Dictionary <int, List <ThreadSnapshot> >(); var debugger = new MDbgEngine(); int pid = -1; var processes = Process.GetProcessesByName(pidOrProcess); if (processes.Length < 1) { try { pid = Int32.Parse(pidOrProcess); } catch { Console.WriteLine("Error: could not find any processes with that name or pid"); return; } } else { if (processes.Length > 1) { Console.WriteLine("Warning: multiple processes share that name, attaching to the first"); } pid = processes[0].Id; } MDbgProcess attached = null; try { attached = debugger.Attach(pid); } catch (Exception e) { Console.WriteLine("Error: failed to attach to process: " + e); return; } attached.Go().WaitOne(); for (int i = 0; i < samples; i++) { foreach (MDbgThread thread in attached.Threads) { var snapshot = ThreadSnapshot.GetThreadSnapshot(thread); List <ThreadSnapshot> snapshots; if (!stats.TryGetValue(snapshot.Id, out snapshots)) { snapshots = new List <ThreadSnapshot>(); stats[snapshot.Id] = snapshots; } snapshots.Add(snapshot); } attached.Go(); Thread.Sleep(sampleInterval); attached.AsyncStop().WaitOne(); } attached.Detach().WaitOne(); // perform basic analysis to see which are the top N stack traces observed, // weighted on cost Dictionary <Guid, long> costs = new Dictionary <Guid, long>(); Dictionary <Guid, string> stacks = new Dictionary <Guid, string>(); foreach (var stat in stats.Values) { long prevTime = -1; foreach (var snapshot in stat) { long time = snapshot.KernelTime + snapshot.UserTime; if (prevTime != -1) { foreach (var tuple in snapshot.StackHashes) { if (costs.ContainsKey(tuple.Item1)) { costs[tuple.Item1] += time - prevTime; } else { costs[tuple.Item1] = time - prevTime; stacks[tuple.Item1] = tuple.Item2; } } } prevTime = time; } } Console.WriteLine("Most expensive stacks"); Console.WriteLine("------------------------------------"); foreach (var group in costs.OrderByDescending(p => p.Value).GroupBy(p => p.Value)) { List <string> stacksToShow = new List <string>(); foreach (var pair in group.OrderByDescending(p => stacks[p.Key].Length)) { if (!stacksToShow.Any(s => s.Contains(stacks[pair.Key]))) { stacksToShow.Add(stacks[pair.Key]); } } foreach (var stack in stacksToShow) { Console.WriteLine(stack); Console.WriteLine("===> Cost ({0})", group.Key); Console.WriteLine(); } } var offenders = stats.Values .Select(_ => ThreadSnapshotStats.FromSnapshots(_)) .OrderBy(stat => stat.TotalKernelTime + stat.TotalUserTime) .Reverse(); foreach (var stat in offenders) { Console.WriteLine("------------------------------------"); Console.WriteLine(stat.ThreadId); Console.WriteLine("Kernel: {0} User: {1}", stat.TotalKernelTime, stat.TotalUserTime); foreach (var method in stat.CommonStack) { Console.WriteLine(method); } Console.WriteLine("Other Stacks:"); var prev = new List <string>(); foreach (var trace in stats[stat.ThreadId].Select(_ => _.StackTrace)) { if (!prev.SequenceEqual(trace)) { Console.WriteLine(); foreach (var method in trace) { Console.WriteLine(method); } } else { Console.WriteLine("<skipped>"); } prev = trace; } Console.WriteLine("------------------------------------"); } }