예제 #1
0
        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);
        }
예제 #2
0
 public StackView(TraceLog traceLog, StackSource stackSource, SymbolReader symbolReader)
 {
     _traceLog       = traceLog;
     _rawStackSource = stackSource;
     _symbolReader   = symbolReader;
     LookupWarmNGENSymbols();
 }
예제 #3
0
        public static CallTree CreateCallTreeFromStackSource(StackSource stackSource)
        {
            var calltree = new CallTree(ScalingPolicyKind.ScaleToData);

            calltree.StackSource = stackSource;
            return(calltree);
        }
예제 #4
0
        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);
        }
예제 #6
0
        /// <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);
            }
        }
예제 #7
0
        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));
        }
예제 #8
0
        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);
            }
        }
예제 #9
0
        /// <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;
            }
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        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");
        }
예제 #12
0
 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));
        }
예제 #14
0
        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);
        }
예제 #16
0
        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));
        }
예제 #19
0
 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);
     }
 }
예제 #20
0
        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);
        }
예제 #24
0
        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);
        }
예제 #26
0
        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);
            }
        }
예제 #27
0
 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();
        }
예제 #29
0
        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
        }
예제 #30
0
        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);
        }