public void Read(TextReader reader) { var sample = new StackSourceSample(this); sample.Metric = 1; for (; ;) { var line = reader.ReadLine(); if (line == null) { break; } if (StackForLine != null) { sample.StackIndex = StackForLine(Interner, line); } else { // Form the stack for this entry (trivial one element stack) var frameIndex = Interner.FrameIntern(line); sample.StackIndex = Interner.CallStackIntern(frameIndex, StackSourceCallStackIndex.Invalid); } if (sample.StackIndex != StackSourceCallStackIndex.Invalid) { AddSample(sample); } } Interner.DoneInterning(); }
// TODO is making this public a hack? public StackSourceFrameIndex GetFrameIndex(CodeAddressIndex codeAddressIndex, out bool isReasonableTopStack) { isReasonableTopStack = false; string moduleName = "?"; ModuleFileIndex moduleIdx = m_log.CodeAddresses.ModuleFileIndex(codeAddressIndex); if (moduleIdx != Diagnostics.Tracing.ModuleFileIndex.Invalid) { moduleName = m_log.ModuleFiles[moduleIdx].FilePath; if (moduleName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase)) { isReasonableTopStack = true; } } var internedModule = Interner.ModuleIntern(moduleName); string methodName = "?"; var methodIdx = m_log.CodeAddresses.MethodIndex(codeAddressIndex); if (methodIdx != MethodIndex.Invalid) { methodName = m_log.CodeAddresses.Methods.FullMethodName(methodIdx); } else if (ShowUnknownAddressses) { methodName = "0x" + m_log.CallStacks.CodeAddresses.Address(codeAddressIndex).ToString("x"); } var internedFrame = Interner.FrameIntern(methodName, internedModule); return(internedFrame); }
public StackSourceFrameIndex GetFrameIndexForName(string frameName, StackSourceModuleIndex moduleIdx = StackSourceModuleIndex.Invalid) { if (moduleIdx == StackSourceModuleIndex.Invalid) { moduleIdx = m_emptyModuleIdx; } return(Interner.FrameIntern(frameName, moduleIdx)); }
public StackSourceCallStackIndex GetCallStackForThread(TraceThread thread) { var processStack = GetCallStackForProcess(thread.Process); var threadName = "Thread (" + thread.ThreadID + ")"; var internedThreadFrame = Interner.FrameIntern(threadName, m_emptyModuleIdx); var threadStack = Interner.CallStackIntern(internedThreadFrame, processStack); return(threadStack); }
// Advanced usage public StackSourceCallStackIndex GetCallStackForProcess(TraceProcess process) { string ptrSize = process.Is64Bit ? "64" : "32"; var processName = "Process" + ptrSize + " " + process.Name + " (" + process.ProcessID + ")"; var internedProcessFrame = Interner.FrameIntern(processName, m_emptyModuleIdx); var processStack = Interner.CallStackIntern(internedProcessFrame, StackSourceCallStackIndex.Invalid); return(processStack); }
/// <summary> /// Note that on windows, lastAccessTime does not really work (acts like lastWriteTime). They turned it off for efficiency reasons. /// </summary> public FileSizeStackSource(string directoryPath, TextWriter log, bool useWriteTime = true) { m_useWriteTime = useWriteTime; m_nowUtc = DateTime.UtcNow; m_log = log; // Make the full path the root node. var stackBase = Interner.CallStackIntern(Interner.FrameIntern("DIR: " + Path.GetFullPath(directoryPath)), StackSourceCallStackIndex.Invalid); AddSamplesForDirectory(directoryPath, stackBase); Interner.DoneInterning(); }
protected override StackSourceFrameIndex InternFrame(string displayName) { StackSourceFrameIndex frameIndex; if (!frames.TryGetValue(displayName, out frameIndex)) { lock (internFrameLock) { frameIndex = Interner.FrameIntern(displayName); frames[displayName] = frameIndex; } } return(frameIndex); }
/// <summary> /// Find the StackSourceCallStackIndex for the TraceEvent call stack index 'callStackIndex' which has a top of its /// stack as 'top'. If callStckMap is non-null it is used as an interning table for CallStackIndex -> StackSourceCallStackIndex. /// This can speed up the transformation dramatically. /// </summary> /// <param name="callStackIndex"></param> /// <param name="top"></param> /// <param name="callStackMap"></param> /// <returns></returns> public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, StackSourceCallStackIndex top, Dictionary <int, StackSourceCallStackIndex> callStackMap) { if (callStackIndex == CallStackIndex.Invalid) { return(top); } StackSourceCallStackIndex cachedValue; if (callStackMap != null && callStackMap.TryGetValue((int)callStackIndex, out cachedValue)) { return(cachedValue); } bool isReasonableTopStack; var frameIdx = GetFrameIndex(m_log.CallStacks.CodeAddressIndex(callStackIndex), out isReasonableTopStack); CallStackIndex nonInternedCallerIdx = m_log.CallStacks.Caller(callStackIndex); StackSourceCallStackIndex callerIdx; if (nonInternedCallerIdx == CallStackIndex.Invalid) { callerIdx = top; if (!isReasonableTopStack) { var brokenFrame = Interner.FrameIntern("BROKEN", m_emptyModuleIdx); callerIdx = Interner.CallStackIntern(brokenFrame, callerIdx); } } else { callerIdx = GetCallStack(nonInternedCallerIdx, top, callStackMap); } var ret = Interner.CallStackIntern(frameIdx, callerIdx); if (callStackMap != null) { callStackMap[(int)callStackIndex] = ret; } return(ret); }
public MyStackSource() { StackSourceModuleIndex emptyModuleIdx = Interner.ModuleIntern(""); // Make up a stack source with 10 samples in it, all with the same stack. var mySample = new StackSourceSample(this); for (int i = 0; i < 10; i++) { mySample.TimeRelativeMSec = i; mySample.Metric = 10 + i; // Just to make things interesting. mySample.StackIndex = StackSourceCallStackIndex.Invalid; // Add a frame 'Frame 1' mySample.StackIndex = Interner.CallStackIntern(Interner.FrameIntern("Frame 1", emptyModuleIdx), mySample.StackIndex); // Add a frame 'Frame 2' mySample.StackIndex = Interner.CallStackIntern(Interner.FrameIntern("Frame 2", emptyModuleIdx), mySample.StackIndex); // This copies mySample, so you can keep reusing mySample for the next sample AddSample(mySample); } }
void Read(TextReader reader) { var framePattern = new Regex(@"\b(\w+?)\!(\S\(?[\S\s]*\)?)"); var stackStart = new Regex(@"Call Site"); // the call stack from the debugger kc command looksl like this //Call Site //coreclr!JIT_MonEnterWorker_Portable //System_Windows_ni!MS.Internal.ManagedPeerTable.TryGetManagedPeer(IntPtr, Boolean, System.Object ByRef) //System_Windows_ni!MS.Internal.ManagedPeerTable.EnsureManagedPeer(IntPtr, Int32, System.Type, Boolean) //System_Windows_ni!MS.Internal.FrameworkCallbacks.CheckPeerType(IntPtr, System.String, Boolean) //System_Windows_ni!DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int32, IntPtr, Int32) //coreclr!UM2MThunk_WrapperHelper //coreclr!UMThunkStubWorker //coreclr!UMThunkStub //agcore!CParser::StartObjectElement //agcore!CParser::Attribute //agcore!CParser::LoadXaml var stack = new GrowableArray <DebuggerCallStackFrame>(); bool newCallStackFound = false; var sample = new StackSourceSample(this); float time = 0; for (; ;) { var line = reader.ReadLine(); if (line == null) { break; } var match = framePattern.Match(line); if (match.Success && newCallStackFound) { var module = match.Groups[1].Value; var methodName = match.Groups[2].Value; // trim the methodName if it has file name info (if the trace is collected with kv instead of kc) int index = methodName.LastIndexOf(")+"); if (index != -1) { methodName = methodName.Substring(0, index + 1); } var moduleIndex = Interner.ModuleIntern(module); var frameIndex = Interner.FrameIntern(methodName, moduleIndex); DebuggerCallStackFrame frame = new DebuggerCallStackFrame(); frame.frame = frameIndex; stack.Add(frame); } else { var stackStartMatch = stackStart.Match(line); if (stackStartMatch.Success) { // start a new sample. // add the previous sample // clear the stack if (stack.Count != 0) { StackSourceCallStackIndex parent = StackSourceCallStackIndex.Invalid; for (int i = stack.Count - 1; i >= 0; --i) { parent = Interner.CallStackIntern(stack[i].frame, parent); } stack.Clear(); sample.StackIndex = parent; sample.TimeRelativeMSec = time; time++; AddSample(sample); } newCallStackFound = true; } } } Interner.DoneInterning(); }
void Read(TextReader reader) { // TODO this is relatively inefficient. var regEx = new Regex(@"^\s*(\d+)\s*(\d+)\s*\[\s*(\d+)\s*\]\s*(\S*?)!?(.*)"); var stack = new GrowableArray <WTStackElem>(); WTStackElem elem = new WTStackElem(); long time = 0; var sample = new StackSourceSample(this); for (; ;) { var line = reader.ReadLine(); if (line == null) { break; } var match = regEx.Match(line); if (match.Success) { // Parse the line. int excInstrSoFar = int.Parse(match.Groups[1].Value); int depth = int.Parse(match.Groups[3].Value); string module = match.Groups[4].Value; string method = match.Groups[5].Value; // Form the name for this line var moduleIndex = Interner.ModuleIntern(module); var frameIndex = Interner.FrameIntern(method, moduleIndex); // Get the parent stack for this line var parent = StackSourceCallStackIndex.Invalid; if (depth > 0) { parent = stack[depth - 1].FirstCallStackIndex; // TODO handle out of range } // Form the stack for this entry var callStackIndex = Interner.CallStackIntern(frameIndex, parent); int exclInstr; // Number of instructions executed on this line int extra = stack.Count - depth; // The number of frames we need to pop off (including me) if (extra > 0) { // We returned from one or more methods OR we have not left the current method // elem = stack[depth]; // We expect to return to the same method we were at at this depth. if (callStackIndex == elem.CallStackIndex) { exclInstr = excInstrSoFar - elem.ExclInstrSoFar; // We are continuing the function } else { // We are tail-calling to another routine. exclInstr = excInstrSoFar; elem.CallStackIndex = callStackIndex; } // Pop off all the frames we returned from Debug.Assert(exclInstr >= 0); stack.RemoveRange(depth, extra); } else { // Means we are adding a new frame (we called someone) Debug.Assert(extra == 0); // We always add only one more frame (e.g. we never go from depth 2 to 4) elem.CallStackIndex = callStackIndex; elem.FirstCallStackIndex = callStackIndex; exclInstr = excInstrSoFar; } elem.ExclInstrSoFar = excInstrSoFar; stack.Add(elem); time += exclInstr; sample.Metric = exclInstr; sample.TimeRelativeMSec = time - exclInstr; sample.StackIndex = elem.FirstCallStackIndex; AddSample(sample); } } Interner.DoneInterning(); }
private void AddSamplesForDirectory(string directoryPath, StackSourceCallStackIndex directoryStack) { StackSourceSample sample = null; try { var directory = new FastDirectory(directoryPath); foreach (var member in directory.Members) { if (member.IsDirectory) { var stack = Interner.CallStackIntern(Interner.FrameIntern("DIR: " + member.Name), directoryStack); AddSamplesForDirectory(Path.Combine(directoryPath, member.Name), stack); } else { var stack = directoryStack; // Allow easy grouping by extension. var ext = Path.GetExtension(member.Name).ToLower(); // And whether the DLL/EXE is managed or not. var suffix = ""; if (string.Compare(ext, ".dll", true) == 0 || string.Compare(ext, ".exe", true) == 0 || string.Compare(ext, ".winmd", true) == 0) { suffix = ""; string fileName = Path.Combine(directoryPath, member.Name); try { using (var peFile = new PEFile.PEFile(fileName)) { suffix = peFile.Header.IsManaged ? " (MANAGED)" : " (UNMANAGED)"; if (peFile.Header.IsPE64) { suffix += " (64Bit)"; } if (peFile.HasPrecompiledManagedCode) { if (peFile.IsManagedReadyToRun) { short major, minor; peFile.ReadyToRunVersion(out major, out minor); suffix += " (ReadyToRun(" + major + "." + minor + "))"; } else { suffix += " (NGEN)"; } } } } catch (Exception) { m_log.WriteLine("Error: exception looking at file " + fileName); m_log.Flush(); } } stack = Interner.CallStackIntern(Interner.FrameIntern("EXT: " + ext + suffix), stack); // Finally the file name itself. stack = Interner.CallStackIntern(Interner.FrameIntern("FILE: " + member.Name), stack); if (sample == null) { sample = new StackSourceSample(this); } sample.Metric = member.Size; sample.StackIndex = stack; if (m_useWriteTime) { sample.TimeRelativeMSec = (m_nowUtc - member.LastWriteTimeUtc).TotalDays; } else { sample.TimeRelativeMSec = (m_nowUtc - member.LastAccessTimeUtc).TotalDays; } AddSample(sample); m_totalSize += member.Size; int count = SampleIndexLimit; if ((count % 1000) == 0) { m_log.WriteLine("[Processed " + count + " files, size " + (m_totalSize / 1000000).ToString("n0") + " MB in directory scan at " + Path.Combine(directoryPath, member.Name) + " ]"); } } } } catch (Exception e) { m_log.WriteLine("Error processing directory " + directoryPath + ": " + e.Message); } }
private void Read(Stream rawStream) { XmlReaderSettings settings = new XmlReaderSettings() { IgnoreWhitespace = true, IgnoreComments = true }; XmlReader reader = XmlTextReader.Create(rawStream, settings); var stack = new GrowableArray <StackSourceSample>(); bool metricsInclusive = false; // If true, we need to convert them to exclusive as part of processing while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { if (reader.Name == "node") { var sample = new StackSourceSample(this); string callTree = reader.GetAttribute("call_tree"); // Case for allocation stacks string sizeStr = reader.GetAttribute("size"); if (sizeStr != null) { metricsInclusive = true; // allocation numbers are inclusive int size = 0; int.TryParse(sizeStr, out size); sample.Metric = size; string recoredObectsStr = reader.GetAttribute("recorded_objects"); int recoredObects = 0; if (recoredObectsStr != null) { int.TryParse(recoredObectsStr, out recoredObects); } sample.Count = recoredObects; } else { Debug.Assert(metricsInclusive == false); // CPU time is exclusive. // For CPU string own_time_msStr = reader.GetAttribute("own_time_ms"); if (own_time_msStr != null) { int own_time_ms; int.TryParse(own_time_msStr, out own_time_ms); sample.Metric = own_time_ms; string countStr = reader.GetAttribute("count"); int count = 0; if (countStr != null) { int.TryParse(countStr, out count); } sample.Count = count; } } // Get the parent stack for this line var parentStackIndex = StackSourceCallStackIndex.Invalid; int depth = stack.Count; if (depth > 0) { StackSourceSample parent = stack[depth - 1]; parentStackIndex = parent.StackIndex; if (metricsInclusive) { // The values are inclusive, but StackSoruceSamples are the exclusive amounts, so remove children. parent.Count -= sample.Count; parent.Metric -= sample.Metric; } } if (callTree != null) { var frameIndex = Interner.FrameIntern(callTree); sample.StackIndex = Interner.CallStackIntern(frameIndex, parentStackIndex); } stack.Add(sample); } } if (reader.NodeType == XmlNodeType.EndElement || reader.IsEmptyElement) { if (reader.Name == "node") { StackSourceSample sample = stack.Pop(); if ((sample.Count > 0 || sample.Metric > 0) && sample.StackIndex != StackSourceCallStackIndex.Invalid) { AddSample(sample); } } } } Debug.Assert(stack.Count == 0); Interner.DoneInterning(); }
public ManagedExeSizeStackSource(string managedExePath) { // Make the full path the root node. var stackBase = Interner.CallStackIntern(Interner.FrameIntern("FILE: " + Path.GetFileName(managedExePath)), StackSourceCallStackIndex.Invalid); StackSourceSample sample = new StackSourceSample(this);; Assembly assembly = Assembly.ReflectionOnlyLoadFrom(managedExePath); AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += delegate(object sender, ResolveEventArgs args) { Trace.WriteLine("RequestingAssembly " + args.RequestingAssembly.FullName); Trace.WriteLine("Name Requested " + args.Name); Assembly ret = null; try { if (args.Name.StartsWith("System") || args.Name.StartsWith("Microsoft")) { ret = Assembly.ReflectionOnlyLoad(args.Name); } } catch (Exception) { } if (ret == null) { Trace.WriteLine("Could not resolve assembly reference " + args.Name); } return(ret); }; Type[] types = null; try { Trace.WriteLine("Calling GetTypes"); types = assembly.GetTypes(); } catch (ReflectionTypeLoadException e) { Trace.WriteLine("Got exception " + e); foreach (var loaderException in e.LoaderExceptions) { Trace.WriteLine("Loader Exception " + loaderException); } types = e.Types; } Trace.WriteLine("Got " + types.Length + " types"); foreach (Type type in types) { if (type == null) { continue; } Trace.WriteLine("Looking at TYPE " + type.FullName); foreach (MethodInfo methodDef in type.GetMethods()) { Trace.WriteLine("Looking at METHOD " + methodDef.Name); MethodBody methodBody = methodDef.GetMethodBody(); int ilLen = 0; if (methodBody != null) { byte[] il = methodBody.GetILAsByteArray(); if (il != null) { ilLen = il.Length; } } PerfView.App.CommandProcessor.LogFile.WriteLine(string.Format("Method {0} size {1}", methodDef.Name, ilLen)); sample.StackIndex = Interner.CallStackIntern(Interner.FrameIntern("METHOD " + methodDef.Name), stackBase); sample.Metric = ilLen; AddSample(sample); } } Interner.DoneInterning(); Trace.WriteLine("Done"); }
protected virtual StackSourceFrameIndex InternFrame(string displayName) { return(Interner.FrameIntern(displayName)); }
public CSVStackSource(CSVReader reader, string eventName, double startRelativeMSec, double endRelativeMSec) { lock (reader) { reader.m_stackEventType = eventName; reader.T0 = (long)(startRelativeMSec * 1000); reader.T1 = long.MaxValue - 1000000; double endusec = endRelativeMSec * 1000; if (endusec < reader.T1) { reader.T1 = (long)endusec; } reader.m_trace.Parameters.T0 = reader.T0; reader.m_trace.Parameters.T1 = reader.T1; var result = reader.m_trace.StackStream(delegate(ETLTrace.Frame frame, ETLTrace.TreeComputer treeComputer, long timeUsec, ulong weight) { m_fullModulePaths = treeComputer.fullModuleNames; StackSourceSample sample = new StackSourceSample(this); sample.TimeRelativeMSec = timeUsec / 1000.0; sample.Metric = weight; if (reader.m_stackEventType == "CSwitch") { sample.Metric = sample.Metric / 1000.0F; } if (sample.Metric == 0) { sample.Metric = 1; } // Get rid of quotes. treeComputer.fullModuleNames["\"Unknown\""] = "UNKNOWN"; // We are traversing frames from the root (threadStart), to leaf (caller before callee). StackSourceCallStackIndex stackIndex = StackSourceCallStackIndex.Invalid; bool callerFrameIsThread = false; while (frame != null) { var fullFrameName = treeComputer.atomsNodeNames.MakeString(frame.id); string moduleName = ""; // Parse it into module and function name var frameName = fullFrameName; var index = fullFrameName.IndexOf('!'); if (index >= 0) { frameName = fullFrameName.Substring(index + 1); frameName = frameName.Replace(';', ','); // They use ';' for template separators for some reason, fix it. moduleName = fullFrameName.Substring(0, index); string fullModuleName; if (treeComputer.fullModuleNames.TryGetValue(moduleName, out fullModuleName)) { moduleName = fullModuleName; } if (moduleName.Length > 4 && moduleName[moduleName.Length - 4] == '.') { #if false // TODO decide if we want to ignore the .NI.DLL and if so do it uniformly. if (moduleName.Length > 7 && moduleName[moduleName.Length - 7] == '.' && moduleName[moduleName.Length - 6] == 'n' && moduleName[moduleName.Length - 5] == 'i') { moduleName = moduleName.Substring(0, moduleName.Length - 7); } else #endif moduleName = moduleName.Substring(0, moduleName.Length - 4); } // If the thread does not call into ntdll, we consider it broken if (callerFrameIsThread && !moduleName.EndsWith("ntdll", StringComparison.Ordinal)) { var brokenFrame = Interner.FrameIntern("BROKEN", Interner.ModuleIntern("")); stackIndex = Interner.CallStackIntern(brokenFrame, stackIndex); } } else { Match m = Regex.Match(frameName, @"^tid *\( *(\d+)\)"); if (m.Success) { frameName = "Thread (" + m.Groups[1].Value + ")"; } else { m = Regex.Match(frameName, @"^(.*?)(\.exe)? *\( *(\d+)\) *$"); if (m.Success) { frameName = "Process " + m.Groups[1].Value + " (" + m.Groups[3].Value + ")"; } } } var myModuleIndex = Interner.ModuleIntern(moduleName); var myFrameIndex = Interner.FrameIntern(frameName, myModuleIndex); stackIndex = Interner.CallStackIntern(myFrameIndex, stackIndex); callerFrameIsThread = frameName.StartsWith("tid "); frame = frame.next; } sample.StackIndex = stackIndex; AddSample(sample); }); Interner.DoneInterning(); } }
void Read(TextReader reader) { var stack = new GrowableArray <StackSourceCallStackIndex>(); var line = reader.ReadLine(); // Skip the first line, which is column headers. var sample = new StackSourceSample(this); for (; ;) { line = reader.ReadLine(); if (line == null) { break; } // 0 1 2 3 4 5 6 7 8 // Order, # of Calls, % Incl Time, % Excl Time, Depth, Function, Module, Incl Time, Excl Time,% Sw. Out, Incl Switched Out, Type, Comments Min Avg Max Excl Switched Out int idx = 0; int depth = 0; string method = null; string module = null; int intVal; long longVal; for (int col = 0; col <= 8; col++) { var newIdx = line.IndexOf('\t', idx); Debug.Assert(0 < newIdx); if (newIdx < 0) { goto SKIP; } switch (col) { case 1: int.TryParse(line.Substring(idx, newIdx - idx), System.Globalization.NumberStyles.Number, null, out intVal); sample.Count = intVal; break; case 4: int.TryParse(line.Substring(idx, newIdx - idx), System.Globalization.NumberStyles.Number, null, out depth); break; case 5: while (idx < newIdx) { if (line[idx] != ' ') { break; } idx++; } method = line.Substring(idx, newIdx - idx); method = method.Replace((char)0xFFFD, '@'); // They used this character to separate the method name from signature. break; case 6: module = ""; if (depth != 0) { module = line.Substring(idx, newIdx - idx); } break; case 8: long.TryParse(line.Substring(idx, newIdx - idx), System.Globalization.NumberStyles.Number, null, out longVal); sample.Metric = longVal / 1000000; // TODO what is the metric? break; } idx = newIdx + 1; } var moduleIdx = Interner.ModuleIntern(module); var frameIdx = Interner.FrameIntern(method, moduleIdx); var prevFrame = StackSourceCallStackIndex.Invalid; if (0 < depth && depth <= stack.Count) { prevFrame = stack[depth - 1]; } var callStackIdx = Interner.CallStackIntern(frameIdx, prevFrame); if (depth < stack.Count) { stack.Count = depth; } stack.Add(callStackIdx); sample.StackIndex = callStackIdx; AddSample(sample); SKIP :; } Interner.DoneInterning(); }