internal static CallstackFunction[] GetObjects(List <string> frameNames) { int frameCount = frameNames.Count; // Stop the stack if we reach the max callstack depth if (frameCount > TracepointAnalysis.MaxCallstackDepth) { frameCount = TracepointAnalysis.MaxCallstackDepth; } //// Sometimes helpful: Stop the stack if we hit rpcrt4.dll since this marks a COM transition //for (int c = 0; c < frameCount; c++) //{ // if (frameNames[c].Contains("rpcrt4.dll")) // { // frameCount = c; // break; // } //} CallstackFunction[] result = new CallstackFunction[frameCount]; for (int c = 0; c < frameCount; c++) { result[c] = GetObject(frameNames[c]); } return(result); }
private static bool IsFunctionInList(CallstackFunction function, List <CallTreeNode> callTreeRoots) { foreach (CallTreeNode node in callTreeRoots) { if (node.Function == function) { return(true); } } return(false); }
private static CallstackFunction GetObject(string frameName) { if (s_dict == null) { s_dict = new Dictionary <string, CallstackFunction>(); } CallstackFunction @this; if (!s_dict.TryGetValue(frameName, out @this)) { @this = new CallstackFunction(frameName); s_dict.Add(frameName, @this); } return(@this); }
static void Main(string[] args) { List <Callstack> stacks; List <CallTreeNode> callTreeRoots; CallstackFilter filter = delegate(CallstackKey key) { // This function can be used to remove functions that you think are unrelated to the leak. // Example: // if (key.Contains("FunctionWithBalancedAddRefsAndReleases")) // return false; return(true); }; TracepointAnalysis.MaxCallstackDepth = 50; TracepointAnalysis.ReadFile(@"C:\Users\greggm\Desktop\leakdiag.txt", filter, out stacks, out callTreeRoots); TracepointAnalysis.ComputeAddRefReleaseDeltas(callTreeRoots); int totalDelta = callTreeRoots[0].Function.DeltaValue + callTreeRoots[1].Function.DeltaValue; const int expectedDelta = 2; if (totalDelta != expectedDelta) { if (totalDelta <= 0) { Console.WriteLine("AddRef/Release problem went away"); } else { Console.WriteLine("AddRef/Release problem is bigger than expected"); } return; } CallstackFunction.DumpFunctionsWithDelta(2); DumpStacks(stacks); //DumpCallTree(callTreeRoots); }
static private CallTreeNode AddNode(Dictionary <CallstackFunction, CallTreeNode> dict, CallstackFunction frame) { CallTreeNode node; if (dict.TryGetValue(frame, out node)) { node.m_hitCount++; return(node); } else { node = new CallTreeNode(frame); dict.Add(frame, node); return(node); } }
private CallTreeNode(CallstackFunction frame) { this.Function = frame; this.Children = new Dictionary <CallstackFunction, CallTreeNode>(); this.m_hitCount = 1; }
/// <summary> /// Reads in a file that contains the text from the debugger's output window and analyises the tracepoint callstacks /// </summary> /// <param name="path">Path to a file containing the saved output window text</param> /// <param name="filter">Optional delegate to filter out callstacks that are uninteresting</param> /// <param name="stacks">Returns a list of all the callstacks in the output with their hit count</param> /// <param name="callTreeRoots">Returns the roots of the tracepoint call trees</param> static public void ReadFile(string path, CallstackFilter filter, out List <Callstack> stacks, out List <CallTreeNode> callTreeRoots) { int currentLine = 0; int currentRefCount = 0; Dictionary <CallstackFunction, CallTreeNode> callTreeRootMap = new Dictionary <CallstackFunction, CallTreeNode>(); Dictionary <CallstackKey, Callstack> callstackMap = new Dictionary <CallstackKey, Callstack>(); stacks = new List <Callstack>(); StreamReader inputFile = File.OpenText(path); List <string> currentCallstack = null; Regex callstackStartLineFormat = new Regex(@"[0-9]+\:\ ?\t.+(\.dll|\.exe)\!.+"); while (!inputFile.EndOfStream) { currentLine++; string line = inputFile.ReadLine(); if (currentCallstack == null) { Match match = callstackStartLineFormat.Match(line); if (match.Success && match.Index == 0) { string s = line.Substring(line.IndexOf('\t') + 1).Trim(); //Additional code to validate the debug output. Useful when figuring out why a //call stack may have gotten dropped. string refcountStr = line.Substring(0, line.IndexOf(':')); int newRefCount = int.Parse(refcountStr); // mscordbi - ignore the 'InterlockedCompareExchange frame' if (inputFile.EndOfStream) { Debugger.Break(); } currentLine++; line = inputFile.ReadLine(); s = line.Substring(line.IndexOf('\t') + 1).Trim(); // Is an AddRef frame? if (s.EndsWith("::AddRef") || s.Contains("InterlockedIncrement")) { if (newRefCount != currentRefCount + 1) { //Debugger.Break(); } currentRefCount++; } // Is a release frame? else if (s.EndsWith("::Release") || s.Contains("InterlockedDecrement")) { if (newRefCount != currentRefCount - 1) { //Debugger.Break(); } currentRefCount--; } else { Debugger.Break(); } // Create a new call stack currentCallstack = new List <string>(); currentCallstack.Add(s); currentRefCount = newRefCount; } } else { if (IsOnlyWhiteSpace(line)) { CallstackFunction[] frames = CallstackFunction.GetObjects(currentCallstack); CallstackKey key = new CallstackKey(frames); if (filter == null || filter(key)) { Callstack.AddCallstack(stacks, callstackMap, key); CallTreeNode.AddCallstack(callTreeRootMap, key); } currentCallstack = null; } else if (line.Length > 1 && line[0] == '\t') { string s = line.Substring(1); currentCallstack.Add(s); } } } callTreeRoots = new List <CallTreeNode>(callTreeRootMap.Values); }