static float LoadOneTrace(StackSource source, Dictionary <string, float> dict) { var calltree = new CallTree(ScalingPolicyKind.ScaleToData); calltree.StackSource = source; float total = 0; foreach (var node in calltree.ByID) { if (node.InclusiveMetric == 0) { continue; } float weight = 0; string key = node.Name; dict.TryGetValue(key, out weight); dict[key] = weight + node.InclusiveMetric; total += node.ExclusiveMetric; } return(total); }
public StackView(TraceLog traceLog, StackSource stackSource, SymbolReader symbolReader) { _traceLog = traceLog; _rawStackSource = stackSource; _symbolReader = symbolReader; LookupWarmNGENSymbols(); }
public static CallTree CreateCallTreeFromStackSource(StackSource stackSource) { var calltree = new CallTree(ScalingPolicyKind.ScaleToData); calltree.StackSource = stackSource; return(calltree); }
public static void WriteStacks(StackSource source, XmlWriter writer) { writer.WriteStartElement("StackSource"); writer.WriteStartElement("Frames"); writer.WriteAttributeString("Count", source.CallFrameIndexLimit.ToString()); for (int i = 0; i < source.CallFrameIndexLimit; i++) { writer.WriteStartElement("Frame"); writer.WriteAttributeString("ID", i.ToString()); var frameName = source.GetFrameName((StackSourceFrameIndex)i, true); writer.WriteString(frameName); writer.WriteEndElement(); // Frame } writer.WriteEndElement(); // Frames writer.WriteStartElement("Stacks"); writer.WriteAttributeString("Count", source.CallStackIndexLimit.ToString()); for (int i = 0; i < source.CallStackIndexLimit; i++) { writer.WriteStartElement("Stack"); writer.WriteAttributeString("ID", i.ToString()); var FrameID = source.GetFrameIndex((StackSourceCallStackIndex)i); var callerID = source.GetCallerIndex((StackSourceCallStackIndex)i); writer.WriteAttributeString("CallerID", ((int)callerID).ToString()); writer.WriteAttributeString("FrameID", ((int)FrameID).ToString()); writer.WriteEndElement(); // Stack } writer.WriteEndElement(); // Stacks writer.WriteStartElement("Samples"); writer.WriteAttributeString("Count", source.SampleIndexLimit.ToString()); // We use the invariant culture, otherwise if we encode in France and decode // in English we get parse errors (this happened!); var invariantCulture = CultureInfo.InvariantCulture; source.ForEach(delegate(StackSourceSample sample) { // <Sample ID="1" Time="3432.23" StackID="2" Metric="1" EventKind="CPUSample" /> writer.WriteStartElement("Sample"); writer.WriteAttributeString("ID", ((int)sample.SampleIndex).ToString()); writer.WriteAttributeString("Time", sample.TimeRelativeMSec.ToString("f3", invariantCulture)); writer.WriteAttributeString("StackID", ((int)sample.StackIndex).ToString()); if (sample.Metric != 1) { var asInt = (int)sample.Metric; if (sample.Metric == asInt) { writer.WriteAttributeString("Metric", asInt.ToString()); } else { writer.WriteAttributeString("Metric", sample.Metric.ToString("f3", invariantCulture)); } } writer.WriteEndElement(); }); writer.WriteEndElement(); // Samples writer.WriteEndElement(); // StackSource }
internal static void Export(StackSource source, TextWriter writer, string name) { var samplesPerThread = GetSortedSamplesPerThread(source); foreach (var samples in samplesPerThread.Values) { MakeSureSamplesDoNotOverlap(samples); } var exportedFrameNameToExportedFrameId = new Dictionary <string, int>(); var profileEventsPerThread = new Dictionary <string, IReadOnlyList <ProfileEvent> >(); foreach (var pair in samplesPerThread) { var frameIdToSamples = WalkTheStackAndExpandSamples(source, pair.Value, exportedFrameNameToExportedFrameId); var sortedProfileEvents = GetAggregatedOrderedProfileEvents(frameIdToSamples); profileEventsPerThread.Add(pair.Key, sortedProfileEvents); } ; var orderedFrameNames = exportedFrameNameToExportedFrameId.OrderBy(pair => pair.Value).Select(pair => pair.Key).ToArray(); WriteToFile(profileEventsPerThread, orderedFrameNames, writer, name); }
/// <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 void OnSetGCHandle(SetGCHandleTraceData data) { if (ProcessId != data.ProcessID) { return; } // This is not a pinned handle. if ((GCHandleKind.AsyncPinned != data.Kind) && (GCHandleKind.Pinned != data.Kind)) { return; } PinningStackAnalysisObject objectInfo = GetPinningInfo(data.ObjectID); Debug.Assert(objectInfo != null); if (objectInfo == null) { return; } // TODO FIX NOW worry about duplicates between the public and private CLR providers. if (objectInfo.PinInfo == null) { objectInfo.PinInfo = new List <PinningStackAnalysisPinInfo>(); } var stackIndex = StackSource.GetCallStack(data.CallStackIndex(), data); objectInfo.PinInfo.Add(new PinningStackAnalysisPinInfo(data.TimeStampRelativeMSec, stackIndex, data.Kind)); }
private static TraceEventStackSource GetTraceEventStackSource(StackSource source) { StackSourceStacks rawSource = source; while (true) { if (rawSource is TraceEventStackSource asTraceEventStackSource) { return(asTraceEventStackSource); } if (rawSource is CopyStackSource asCopyStackSource) { rawSource = asCopyStackSource.SourceStacks; continue; } if (rawSource is StackSource asStackSource && asStackSource != asStackSource.BaseStackSource) { rawSource = asStackSource.BaseStackSource; continue; } return(null); } }
/// <summary> /// Initialize a new AggregateStackSource. /// </summary> /// <param name="sources">An IEnumerable of KeyValuePairs mapping source names to StackSources.</param> public AggregateStackSource(IEnumerable <KeyValuePair <string, StackSource> > sources) { m_sourceCount = sources.Count() + 1; // +1 for the pseudo-source. m_sourceNames = new string[m_sourceCount]; m_sources = new StackSource[m_sourceCount]; // We initialize this when we see the first sample m_firstSampleTime = new double[m_sourceCount]; for (int j = 0; j < m_firstSampleTime.Length; j++) { m_firstSampleTime[j] = double.NegativeInfinity; } // True if all sub-sources support retrieving samples by index. bool supportsSamples = true; // The time limit for this source. m_RelativeMSecLimit = 0.0f; int i = 1; // Unpack sources. foreach (var pair in sources) { var name = pair.Key; var source = pair.Value; m_sourceNames[i] = name; m_sources[i] = source; i++; m_RelativeMSecLimit = Math.Max(m_RelativeMSecLimit, source.SampleTimeRelativeMSecLimit); if (source.SampleIndexLimit == 0) { supportsSamples = false; } } // Set up pseudo-source. m_sources[0] = m_pseudo = new PseudoStackSource(m_sourceNames); // Set up our returned sample. m_sampleStorage = new StackSourceSample(this); // Set up index maps. m_stackMap = new IndexMap(m_sources.Select(s => s.CallStackIndexLimit)); m_frameMap = new IndexMap(m_sources.Select(s => s.CallFrameIndexLimit)); if (supportsSamples) { // The sampleMap has size (m_sourceCount - 1) because m_pseudo doesn't have samples. m_sampleMap = new IndexMap(m_sources.Skip(1).Select(s => s.SampleIndexLimit)); } else { m_sampleMap = null; } }
/// <summary> /// Looks up symbols for all modules that have an inclusive count >= minCount. /// stackSource, if given, can be used to be the filter. If null, 'this' is used. /// If stackSource is given, it needs to use the same indexes for frames as 'this' /// </summary> public void LookupWarmSymbols(int minCount, SymbolReader reader, StackSource stackSource = null) { if (stackSource == null) { stackSource = this; } Debug.Assert(stackSource.CallFrameIndexLimit == this.CallFrameIndexLimit); Debug.Assert(stackSource.CallStackIndexLimit == this.CallStackIndexLimit); reader.Log.WriteLine("Resolving all symbols for modules with inclusive times > {0}", minCount); if ((reader.Flags & SymbolReaderFlags.CacheOnly) != 0) { reader.Log.WriteLine("Cache-Only set: will only look on the local machine."); } // Get a list of all the unique frames. We also keep track of unique stacks for efficiency var stackModuleLists = new ModuleList[stackSource.CallStackIndexLimit]; var stackCounts = new int[stackSource.CallStackIndexLimit]; var totalCount = 0; // Compute for each stack, the set of inclusive modules for that stack stackSource.ProduceSamples(delegate(StackSourceSample sample) { stackCounts[(int)sample.StackIndex]++; totalCount++; }); reader.Log.WriteLine("Got a total of {0} samples", totalCount); // for each stack in the trace, find the list of modules for that stack var moduleCounts = new int[TraceLog.ModuleFiles.MaxModuleFileIndex]; for (int i = 0; i < stackCounts.Length; i++) { var count = stackCounts[i]; if (count > 0) { var modules = GetModulesForStack(stackModuleLists, (StackSourceCallStackIndex)i); // Update the counts for each module in that stack. while (modules != null) { moduleCounts[(int)modules.Module.ModuleFileIndex] += count; modules = modules.Next; } } } // Now that we have an list of the inclusive counts of all frames. Find all stacks that meet the threshold for (int i = 0; i < moduleCounts.Length; i++) { if (moduleCounts[i] >= minCount) { var moduleFile = TraceLog.ModuleFiles[(ModuleFileIndex)i]; reader.Log.WriteLine("Resolving symbols (count={0}) for module {1} ", moduleCounts[i], moduleFile.FilePath); TraceLog.CallStacks.CodeAddresses.LookupSymbolsForModule(reader, moduleFile); } } reader.Log.WriteLine("Done Resolving all symbols for modules with inclusive times > {0}", minCount); }
private void OnOpenLargeAllocStacks(object sender, RoutedEventArgs e) { StackSource stacks = m_dataFile.CreateStackSource("GC Heap Alloc Ignore Free (Coarse Sampling)", m_process.ProcessID, m_statusBar.LogWriter, true); StackWindow stackWin = null; m_dataFile.StackWindowTo(null, ref stackWin, stacks, "LOH Heap Alloc"); }
public static void WriteStackViewAsXml(StackSource source, string fileName, Action <XmlWriter> additionalData = null) { if (File.Exists(fileName)) { File.Delete(fileName); } using (var writeStream = File.Create(fileName)) WriteStackViewAsXml(source, writeStream, additionalData); }
/// <summary> /// exports provided StackSource to a https://www.speedscope.app/ format /// schema: https://www.speedscope.app/file-format-schema.json /// </summary> public static void WriteStackViewAsJson(StackSource source, string filePath) { if (File.Exists(filePath)) { File.Delete(filePath); } using (var writeStream = File.CreateText(filePath)) Export(source, writeStream, Path.GetFileNameWithoutExtension(filePath)); }
public OSGroupingStackSource(StackSource stackSource) { m_baseStackSource = stackSource; // Intialize the StackInfo cache (and the IncPathsMatchedSoFarStorage variable) m_stackInfoCache = new StackInfo[StackInfoCacheSize]; for (int i = 0; i < m_stackInfoCache.Length; i++) { m_stackInfoCache[i] = new StackInfo(); } }
StackView ITrace.GetCPUStacks(AnalyzerTraceProcess process) { StackView stackView = null; TraceProcess traceProcess = TraceLog.Processes[(ProcessIndex)process.UniqueID]; if (traceProcess != null) { StackSource stackSource = TraceLog.CPUStacks(traceProcess); stackView = new StackView(traceProcess.Log, stackSource, SymbolReader); } return(stackView); }
private StackView GetCPUStacks(Process process) { StackView stackView = null; TraceProcess traceProcess = UnderlyingSource.Processes[(ProcessIndex)process.UniqueID]; if (traceProcess != null) { StackSource stackSource = UnderlyingSource.CPUStacks(traceProcess); stackView = new StackView(traceProcess.Log, stackSource, SymbolReader); } return(stackView); }
public void FlushBlockedThreadsAt(double endTime) { foreach (int threadid in EndingStates.Keys) { if (EndingStates[threadid].Key == LinuxThreadState.BLOCKED_TIME) { KeyValuePair <LinuxThreadState, LinuxEvent> sampleInfo = EndingStates[threadid]; sampleInfo.Value.Period = TimeStamp - sampleInfo.Value.TimeMSec; AddThreadPeriod(threadid, sampleInfo.Value.TimeMSec, TimeStamp); StackSource.AddSample(StackSource.CreateSampleFor(sampleInfo.Value, this)); } } }
/// <summary> /// Build a flame chart for the given StackSource /// </summary> /// <param name="stackSource">The set of stacks to represent</param> /// <param name="fileToWrite">The name of the output file</param> /// <param name="rootFunction">Optional. If specified, "roots" the flame chart on that function so all of its ancestors are not present.</param> /// <param name="title">Optional. The title of the flame chart</param> /// <returns>A boolean indicating whether the operation succeeded.</returns> public static bool BuildFlameChart(StackSource stackSource, string fileToWrite, string rootFunction, string title) { string intermediateFilePath = fileToWrite + "_tmp"; if (!BuildInternalTempRepresentation(stackSource, intermediateFilePath, rootFunction)) { return(false); } string titleLabel = title ?? rootFunction ?? ""; return(InternalBuildFlameChart(intermediateFilePath, titleLabel, fileToWrite)); }
public static void WriteStackViewAsZippedXml(StackSource source, string fileName, Action <XmlWriter> additionalData = null) { if (File.Exists(fileName)) { File.Delete(fileName); } using (var archive = ZipFile.Open(fileName, ZipArchiveMode.Create)) { var entry = archive.CreateEntry(Path.GetFileNameWithoutExtension(fileName)); using (var entryStream = entry.Open()) WriteStackViewAsXml(source, entryStream, additionalData); } }
public static void WriteStackViewAsXml(StackSource source, Stream writeStream, Action <XmlWriter> additionalData = null) { using (var writer = XmlWriter.Create(writeStream, new XmlWriterSettings() { Indent = true, IndentChars = " " })) { writer.WriteStartElement("StackWindow"); XmlStackSourceWriter.WriteStacks(source, writer); additionalData?.Invoke(writer); writer.WriteEndElement(); } }
/// <summary> /// exports provided StackSource to a Chromium Trace File format /// schema: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/ /// </summary> public static void WriteStackViewAsJson(StackSource source, string filePath, bool compress) { if (compress && !filePath.EndsWith(".gz", StringComparison.OrdinalIgnoreCase)) { filePath += ".gz"; } if (File.Exists(filePath)) { File.Delete(filePath); } using (var writeStream = compress ? (Stream) new GZipStream(File.Create(filePath), CompressionMode.Compress, leaveOpen: false) : File.Create(filePath)) using (var streamWriter = new StreamWriter(writeStream)) { Export(source, streamWriter, Path.GetFileNameWithoutExtension(filePath)); } }
private static void Export(StackSource source, TextWriter writer, string name) { var samplesPerThread = GetSortedSamplesPerThread(source); var exportedFrameNameToExportedFrameId = new Dictionary <string, int>(); var exportedFrameIdToFrameTuple = new Dictionary <int, FrameInfo>(); var profileEventsPerThread = new Dictionary <ThreadInfo, IReadOnlyList <ProfileEvent> >(); foreach (var pair in samplesPerThread) { var frameIdToSamples = WalkTheStackAndExpandSamples(source, pair.Value, exportedFrameNameToExportedFrameId, exportedFrameIdToFrameTuple); var sortedProfileEvents = GetAggregatedOrderedProfileEvents(frameIdToSamples); profileEventsPerThread.Add(pair.Key, sortedProfileEvents); } ; WriteToFile(exportedFrameIdToFrameTuple, profileEventsPerThread, writer, name); }
private static void Export(StackSource source, TextWriter writer, string name) { var samplesPerThread = GetSortedSamplesPerThread(source); var exportedFrameNameToExportedFrameId = new Dictionary <string, int>(); var exportedFrameIdToFrameTuple = new Dictionary <int, FrameInfo>(); var profileEventsPerThread = new Dictionary <ThreadInfo, IReadOnlyList <ProfileEvent> >(); foreach (var pair in samplesPerThread) { var sortedProfileEvents = GetProfileEvents(source, pair.Value, exportedFrameNameToExportedFrameId, exportedFrameIdToFrameTuple); Debug.Assert(Validate(sortedProfileEvents), "The output should be always valid"); profileEventsPerThread.Add(pair.Key, sortedProfileEvents); } ; WriteToFile(exportedFrameIdToFrameTuple, profileEventsPerThread, writer, name); }
public CallTreeDataProvider(TraceLog log, FilterParams filterParams, SymbolReader reader, ITraceDataPlugin plugin) { if (log == null) { ThrowHelper.ThrowArgumentNullException(nameof(log)); } if (filterParams == null) { ThrowHelper.ThrowArgumentNullException(nameof(filterParams)); } if (reader == null) { ThrowHelper.ThrowArgumentNullException(nameof(reader)); } if (plugin == null) { ThrowHelper.ThrowArgumentNullException(nameof(plugin)); } this.reader = reader; TraceEvents events = log.Events; this.stacksource = plugin.GetStackSource(events); this.summaryPredicate = plugin.SummaryPredicate; CallTree.DisableParallelism = true; // important this.stacksource = new FilterStackSource(filterParams, this.stacksource, ScalingPolicyKind.TimeMetric); this.callTree = new CallTree(ScalingPolicyKind.TimeMetric) { StackSource = this.stacksource }; float minIncusiveTimePercent; if (float.TryParse(filterParams.MinInclusiveTimePercent, out minIncusiveTimePercent) && minIncusiveTimePercent > 0) { this.callTree.FoldNodesUnder(minIncusiveTimePercent * this.callTree.Root.InclusiveMetric / 100, true); } }
private static void Export(StackSource source, TextWriter writer, string name) { var samplesPerThread = GetSortedSamplesPerThread(source); var exportedFrameNameToExportedFrameId = new Dictionary <string, int>(); var exportedFrameIdToFrameTuple = new Dictionary <int, FrameInfo>(); var profileEventsPerThread = new Dictionary <string, IReadOnlyList <ProfileEvent> >(samplesPerThread.Count); foreach (var pair in samplesPerThread) { var sortedProfileEvents = GetProfileEvents(source, pair.Value, exportedFrameNameToExportedFrameId, exportedFrameIdToFrameTuple); Debug.Assert(Validate(sortedProfileEvents), "The output should be always valid"); profileEventsPerThread.Add(pair.Key.Name, sortedProfileEvents); } ; var orderedFrameNames = exportedFrameNameToExportedFrameId.OrderBy(pair => pair.Value).Select(pair => pair.Key).ToArray(); WriteToFile(profileEventsPerThread, orderedFrameNames, writer, name); }
private void OnOpenInducedStacks(object sender, RoutedEventArgs e) { StackSourceBuilder builder = new StackSourceBuilder(m_traceLog); List <TraceGC> events = m_runtime.GC.GCs; for (int i = 0; i < events.Count; i++) { TraceGC ev = events[i]; if (ev.IsInduced()) { GcEventExtra extra = GetGcEventExtra(ev.Number, false); if (extra != null) { builder.AddSample(extra.GCStartThread, ev.PauseDurationMSec, ev.StartRelativeMSec, String.Format("StartGC({0}, {1}, G{2})", ev.Reason, ev.Type, ev.Generation), extra.GCStartIndex); } } } StackSource source = builder.Stacks; if (source.SampleIndexLimit == 0) { MessageBox.Show("No stacks found for induced GC", ".Net Heap Analyzer", MessageBoxButton.OK); } else { StackWindow stackWindow = null; m_dataFile.StackWindowTo(null, ref stackWindow, source, "Induced GC", FirstEventTime, LastEventTime); } }
public LinuxPerfScriptStackSourceSample(StackSource source) : base(source) { }
private static void PrintStack(IConsole console, int threadId, StackSourceSample stackSourceSample, StackSource stackSource) { console.Out.WriteLine($"Thread (0x{threadId:X}):"); var stackIndex = stackSourceSample.StackIndex; while (!stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), verboseName: false).StartsWith("Thread (")) { console.Out.WriteLine($" {stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), verboseName: false)}" .Replace("UNMANAGED_CODE_TIME", "[Native Frames]")); stackIndex = stackSource.GetCallerIndex(stackIndex); } console.Out.WriteLine(); }
public static void WriteStacks(StackSource source, XmlWriter writer) { writer.WriteStartElement("StackSource"); writer.WriteStartElement("Frames"); writer.WriteAttributeString("Count", source.CallFrameIndexLimit.ToString()); for (int i = 0; i < source.CallFrameIndexLimit; i++) { writer.WriteStartElement("Frame"); writer.WriteAttributeString("ID", i.ToString()); var frameName = source.GetFrameName((StackSourceFrameIndex)i, true); // Check for the optimization tier. The frame name would contain the optimization tier in the form: // Module![OptimizationTier]Symbol // Extract the optimization tier into an attribute and convert the frame name to this form for storage: // Module!Symbol if (frameName != null && frameName.Length >= 4) { int openBracketIndex = frameName.IndexOf("![") + 1; if (openBracketIndex > 0) { int closeBracketIndex = frameName.IndexOf(']', openBracketIndex + 1); if (closeBracketIndex - openBracketIndex > 1) { var optimizationTierStr = frameName.Substring(openBracketIndex + 1, closeBracketIndex - openBracketIndex - 1); if (Enum.TryParse <OptimizationTier>(optimizationTierStr, out var optimizationTier)) { if (optimizationTier != OptimizationTier.Unknown) { writer.WriteAttributeString("OptimizationTier", optimizationTierStr); } frameName = frameName.Substring(0, openBracketIndex) + frameName.Substring(closeBracketIndex + 1); } } } } writer.WriteString(frameName); writer.WriteEndElement(); // Frame } writer.WriteEndElement(); // Frames writer.WriteStartElement("Stacks"); writer.WriteAttributeString("Count", source.CallStackIndexLimit.ToString()); for (int i = 0; i < source.CallStackIndexLimit; i++) { writer.WriteStartElement("Stack"); writer.WriteAttributeString("ID", i.ToString()); var FrameID = source.GetFrameIndex((StackSourceCallStackIndex)i); var callerID = source.GetCallerIndex((StackSourceCallStackIndex)i); writer.WriteAttributeString("CallerID", ((int)callerID).ToString()); writer.WriteAttributeString("FrameID", ((int)FrameID).ToString()); writer.WriteEndElement(); // Stack } writer.WriteEndElement(); // Stacks writer.WriteStartElement("Samples"); writer.WriteAttributeString("Count", source.SampleIndexLimit.ToString()); // We use the invariant culture, otherwise if we encode in France and decode // in English we get parse errors (this happened!); var invariantCulture = CultureInfo.InvariantCulture; source.ForEach(delegate(StackSourceSample sample) { // <Sample ID="1" Time="3432.23" StackID="2" Metric="1" EventKind="CPUSample" /> writer.WriteStartElement("Sample"); writer.WriteAttributeString("ID", ((int)sample.SampleIndex).ToString()); writer.WriteAttributeString("Time", sample.TimeRelativeMSec.ToString("f3", invariantCulture)); writer.WriteAttributeString("StackID", ((int)sample.StackIndex).ToString()); if (sample.Metric != 1) { var asInt = (int)sample.Metric; if (sample.Metric == asInt) { writer.WriteAttributeString("Metric", asInt.ToString()); } else { writer.WriteAttributeString("Metric", sample.Metric.ToString("f3", invariantCulture)); } } writer.WriteEndElement(); }); writer.WriteEndElement(); // Samples writer.WriteEndElement(); // StackSource }
private unsafe void HandleStacks(byte *userData, int frameCount, long eventTimestamp, int pointerSize, uint pid, uint tid) { int callerIndex = -1; if (!this.processPseudoFrameMappingTable.TryGetValue(pid, out var offset)) { offset = this.PseudoFrames.Count; this.processPseudoFrameMappingTable.Add(pid, offset); this.PseudoFrames.Add(string.Empty); // 2nd-pass will fill in Process w3wp (pid) } callerIndex = this.AddOrUpdateCallerIndex(callerIndex, offset); this.callerIdsNeedingUpdates.Add(callerIndex); if (!this.threadPseudoFrameMappingTable.TryGetValue(tid, out offset)) { offset = this.PseudoFrames.Count; this.threadPseudoFrameMappingTable.Add(tid, offset); this.PseudoFrames.Add(string.Empty); // 2nd-pass will fill in Thread (tid) } callerIndex = this.AddOrUpdateCallerIndex(callerIndex, offset); this.callerIdsNeedingUpdates.Add(callerIndex); for (int i = frameCount - 1; i > -1; i--) { var eip = pointerSize == 8 ? *(ulong *)(userData + (i * 8)) : (ulong)*(int *)(userData + (i * 4)); var key = new Frame(pid, eip); if (!this.pidEipToFrameIndexTable.TryGetValue(key, out int frameIndex)) { frameIndex = this.Frames.Count; this.pidEipToFrameIndexTable.Add(key, frameIndex); this.Frames.Add(key); } callerIndex = this.AddOrUpdateCallerIndex(callerIndex, frameIndex); } StackSource dummy = null; var sample = new StackSourceSample(dummy) { Scenario = (int)pid, // hack alert: we use scenario as pid, it's just so that I can take source integrates for Stacks.cs TimeRelativeMSec = (eventTimestamp - this.sessionStartTimeQPC) * 1000.0 / this.perfFreq, Metric = 1.0F, StackIndex = (StackSourceCallStackIndex)callerIndex, SampleIndex = (StackSourceSampleIndex)this.Samples.Count }; var endTime = sample.TimeRelativeMSec + 1.0; if (endTime > this.MaxTimeRelativeMSec) { this.MaxTimeRelativeMSec = endTime; } // TODO: BUG: yes, it turns out we can multiple stacks for the same event, we just throw older ones. // primarily because with whom do we associate it? var key2 = new CorrelatedStackEvent(eventTimestamp, tid); if (!this.samplesTimeStampMap.ContainsKey(key2)) { this.samplesTimeStampMap.Add(key2, this.Samples.Count); } this.Samples.Add(sample); }