/// <summary> /// Unwind the wrapped sources to get to a TraceEventStackSource if possible. /// </summary> private static TraceEventStackSource GetTraceEventStackSource(StackSource source) { StackSourceStacks rawSource = source; TraceEventStackSource asTraceEventStackSource = null; for (; ;) { asTraceEventStackSource = rawSource as TraceEventStackSource; if (asTraceEventStackSource != null) { return(asTraceEventStackSource); } var asCopyStackSource = rawSource as CopyStackSource; if (asCopyStackSource != null) { rawSource = asCopyStackSource.SourceStacks; continue; } var asStackSource = rawSource as StackSource; if (asStackSource != null && asStackSource != asStackSource.BaseStackSource) { rawSource = asStackSource.BaseStackSource; continue; } return(null); } }
private (string etlx, Dictionary <string, ETWHelper.CallTreeItem> callTree) TryGetCallTree(int pid) { string maybeEtlx = null; try { var(tlog, etlx) = ETWHelper.GetTraceLog(outFile); maybeEtlx = etlx; using (tlog) { var proc = tlog.Processes.FirstOrDefault(p => p.ProcessID == pid); var stacks = new TraceEventStackSource(proc.EventsInProcess.Filter(t => t is SampledProfileTraceData)); var callTree = ETWHelper.GetCallTree(stacks, out var timeModifier); //if (GetAllResultFiles(outFile) is var allFiles && allFiles.Length > 1) //{ // string tempName = Path.ChangeExtension(outFile, ".etl.new"); // TraceEventSession.Merge(allFiles, tempName); // // Delete the originals. // foreach (var mergeInput in allFiles) // File.Delete(mergeInput); // // Place the output in its final resting place. // File.Move(tempName, outFile); //} return(etlx, callTree); } } catch (Exception ex) { return(maybeEtlx, new Dictionary <string, ETWHelper.CallTreeItem>()); } }
private void LookupWarmNGENSymbols() { TraceEventStackSource asTraceEventStackSource = GetTraceEventStackSource(_rawStackSource); if (asTraceEventStackSource == null) { return; } SymbolReaderOptions savedOptions = _symbolReader.Options; try { // NGEN PDBs (even those not yet produced) are considered to be in the cache. _symbolReader.Options = SymbolReaderOptions.CacheOnly; // Resolve all NGEN images. asTraceEventStackSource.LookupWarmSymbols(1, _symbolReader, _rawStackSource, s => s.Name.EndsWith(".ni", StringComparison.OrdinalIgnoreCase)); // Invalidate cached data structures to finish resolving symbols. InvalidateCachedStructures(); } finally { _symbolReader.Options = savedOptions; } }
public static StackSource CPUStacks(this TraceLog eventLog, TraceProcess process = null, bool showUnknownAddresses = false, Predicate <TraceEvent> predicate = null) { TraceEvents events = process == null?eventLog.Events.Filter(x => (predicate == null || predicate(x)) && x is SampledProfileTraceData && x.ProcessID != 0) : process.EventsInProcess.Filter(x => (predicate == null || predicate(x)) && x is SampledProfileTraceData); var traceStackSource = new TraceEventStackSource(events) { ShowUnknownAddresses = showUnknownAddresses }; return(traceStackSource); }
public static StackSource CPUStacks(this TraceLog eventLog, TraceProcess process = null, Predicate <TraceEvent> predicate = null) { TraceEvents events; if (process == null) { events = eventLog.Events.Filter((x) => ((predicate == null) || predicate(x)) && x is SampledProfileTraceData && x.ProcessID != 0); } else { events = process.EventsInProcess.Filter((x) => ((predicate == null) || predicate(x)) && x is SampledProfileTraceData); } var traceStackSource = new TraceEventStackSource(events); // We clone the samples so that we don't have to go back to the ETL file from here on. return(CopyStackSource.Clone(traceStackSource)); }
public static StackSource SingleEventTypeStack(this TraceEvents events, TraceProcess process = null, Predicate <TraceEvent> predicate = null) { // optimization only if (process != null) { var start = Math.Max(events.StartTimeRelativeMSec, process.StartTimeRelativeMsec); var end = Math.Min(events.EndTimeRelativeMSec, process.EndTimeRelativeMsec); events = events.FilterByTime(start, end); events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID == process.ProcessID); } else { events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID != 0); // TODO: Is it really correc that x.ProcessID != 0 should be there? What if we want see these? } var traceStackSource = new TraceEventStackSource(events) { ShowUnknownAddresses = true }; return(CopyStackSource.Clone(traceStackSource)); }
public static StackSource CPUStacks( this Microsoft.Diagnostics.Tracing.Etlx.TraceLog eventLog, Microsoft.Diagnostics.Tracing.Etlx.TraceProcess process = null, Predicate <TraceEvent> predicate = null) { Microsoft.Diagnostics.Tracing.Etlx.TraceEvents events; if (process == null) { events = eventLog.Events.Filter((x) => ((predicate == null) || predicate(x)) && x is SampledProfileTraceData && x.ProcessID != 0); } else { events = process.EventsInProcess.Filter((x) => ((predicate == null) || predicate(x)) && x is SampledProfileTraceData); } var traceStackSource = new TraceEventStackSource(events); traceStackSource.ShowUnknownAddresses = true; // Clone the samples so that the caller doesn't have to go back to the ETL file from here on. return(CopyStackSource.Clone(traceStackSource)); }
private SourceLocation GetSourceLocation(CallTreeNodeBase asCallTreeNodeBase, string cellText, out SortedDictionary <int, float> metricOnLine) { metricOnLine = null; var m = Regex.Match(cellText, "<<(.*!.*)>>"); if (m.Success) { cellText = m.Groups[1].Value; } var frameIndexCounts = new Dictionary <StackSourceFrameIndex, float>(); asCallTreeNodeBase.GetSamples(false, delegate(StackSourceSampleIndex sampleIdx) { var matchingFrameIndex = StackSourceFrameIndex.Invalid; var sample = this.stacksource.GetSampleByIndex(sampleIdx); var callStackIdx = sample.StackIndex; while (callStackIdx != StackSourceCallStackIndex.Invalid) { var frameIndex = this.stacksource.GetFrameIndex(callStackIdx); var frameName = this.stacksource.GetFrameName(frameIndex, false); if (frameName == cellText) { matchingFrameIndex = frameIndex; // We keep overwriting it, so we get the entry closest to the root. } callStackIdx = this.stacksource.GetCallerIndex(callStackIdx); } if (matchingFrameIndex != StackSourceFrameIndex.Invalid) { float count = 0; frameIndexCounts.TryGetValue(matchingFrameIndex, out count); frameIndexCounts[matchingFrameIndex] = count + sample.Metric; } return(true); }); var maxFrameIdx = StackSourceFrameIndex.Invalid; float maxFrameIdxCount = -1; foreach (var keyValue in frameIndexCounts) { if (keyValue.Value >= maxFrameIdxCount) { maxFrameIdxCount = keyValue.Value; maxFrameIdx = keyValue.Key; } } if (maxFrameIdx == StackSourceFrameIndex.Invalid) { return(null); } // Find the most primitive TraceEventStackSource TraceEventStackSource asTraceEventStackSource = GetTraceEventStackSource(this.stacksource); if (asTraceEventStackSource == null) { return(null); } var frameToLine = new Dictionary <StackSourceFrameIndex, int>(); var sourceLocation = asTraceEventStackSource.GetSourceLine(maxFrameIdx, this.reader); if (sourceLocation != null) { var filePathForMax = sourceLocation.SourceFile.BuildTimeFilePath; metricOnLine = new SortedDictionary <int, float>(); // Accumulate the counts on a line basis foreach (StackSourceFrameIndex frameIdx in frameIndexCounts.Keys) { var loc = asTraceEventStackSource.GetSourceLine(frameIdx, this.reader); if (loc != null && loc.SourceFile.BuildTimeFilePath == filePathForMax) { frameToLine[frameIdx] = loc.LineNumber; float metric; metricOnLine.TryGetValue(loc.LineNumber, out metric); metric += frameIndexCounts[frameIdx]; metricOnLine[loc.LineNumber] = metric; } } } bool commonMethodIdxSet = false; MethodIndex commonMethodIdx = MethodIndex.Invalid; var nativeAddressFreq = new SortedDictionary <ulong, Tuple <int, float> >(); foreach (var keyValue in frameIndexCounts) { var codeAddr = asTraceEventStackSource.GetFrameCodeAddress(keyValue.Key); if (codeAddr != CodeAddressIndex.Invalid) { var methodIdx = asTraceEventStackSource.TraceLog.CodeAddresses.MethodIndex(codeAddr); if (methodIdx != MethodIndex.Invalid) { if (!commonMethodIdxSet) { commonMethodIdx = methodIdx; // First time, set it as the common method. } else if (methodIdx != commonMethodIdx) { methodIdx = MethodIndex.Invalid; // More than one method, give up. } commonMethodIdxSet = true; } var nativeAddr = asTraceEventStackSource.TraceLog.CodeAddresses.Address(codeAddr); var lineNum = 0; frameToLine.TryGetValue(keyValue.Key, out lineNum); nativeAddressFreq[nativeAddr] = new Tuple <int, float>(lineNum, keyValue.Value); } } foreach (var keyValue in nativeAddressFreq) { Console.WriteLine(" {0,12:x} : {1,6} {2,10:f1}", keyValue.Key, keyValue.Value.Item1, keyValue.Value.Item2); } if (sourceLocation == null) { return(null); } foreach (var keyVal in metricOnLine) { Console.WriteLine(" Line {0,5}: Metric {1,5:n1}", keyVal.Key, keyVal.Value); } return(sourceLocation); }