diff --git a/src/PerfView/StackViewer/StackWindow.xaml.cs b/src/PerfView/StackViewer/StackWindow.xaml.cs index dd4dc5273..aafe75701 100644 --- a/src/PerfView/StackViewer/StackWindow.xaml.cs +++ b/src/PerfView/StackViewer/StackWindow.xaml.cs @@ -2297,7 +2297,8 @@ private void DoGotoSource(object sender, ExecutedRoutedEventArgs e) } SortedDictionary metricOnLine; - var sourceLocation = GetSourceLocation(asCallTreeNodeBase, cellText, out metricOnLine); + SortedDictionary exclusiveMetricOnLine; + var sourceLocation = GetSourceLocation(asCallTreeNodeBase, cellText, out metricOnLine, out exclusiveMetricOnLine); string sourcePathToOpen = null; string logicalSourcePath = null; @@ -2321,7 +2322,7 @@ private void DoGotoSource(object sender, ExecutedRoutedEventArgs e) { sourcePathToOpen = CacheFiles.FindFile(sourcePathToOpen, Path.GetExtension(sourcePathToOpen)); StatusBar.Log("Annotating source with metric to the file " + sourcePathToOpen); - AnnotateLines(logicalSourcePath, sourcePathToOpen, metricOnLine); + AnnotateLines(logicalSourcePath, sourcePathToOpen, ("Inc", metricOnLine) ,("Exc", exclusiveMetricOnLine)); } } } @@ -2360,9 +2361,10 @@ private void DoGotoSource(object sender, ExecutedRoutedEventArgs e) // TODO FIX NOW review private SourceLocation GetSourceLocation(CallTreeNodeBase asCallTreeNodeBase, string cellText, - out SortedDictionary metricOnLine) + out SortedDictionary metricOnLine, out SortedDictionary exclusiveMetricOnLine) { metricOnLine = null; + exclusiveMetricOnLine = null; var m = Regex.Match(cellText, "<<(.*!.*)>>"); if (m.Success) { @@ -2372,12 +2374,14 @@ private SourceLocation GetSourceLocation(CallTreeNodeBase asCallTreeNodeBase, st // Find the most numerous call stack // TODO this can be reasonably expensive. If it is a problem do something about it (e.g. sampling) var frameIndexCounts = new Dictionary(); + var exclusiveFrameIndexCounts = new Dictionary(); asCallTreeNodeBase.GetSamples(false, delegate (StackSourceSampleIndex sampleIdx) { // Find the callStackIdx which corresponds to the name in the cell, and log it to callStackIndexCounts var matchingFrameIndex = StackSourceFrameIndex.Invalid; var sample = m_stackSource.GetSampleByIndex(sampleIdx); var callStackIdx = sample.StackIndex; + bool exclusiveSample = true; while (callStackIdx != StackSourceCallStackIndex.Invalid) { var frameIndex = m_stackSource.GetFrameIndex(callStackIdx); @@ -2387,6 +2391,13 @@ private SourceLocation GetSourceLocation(CallTreeNodeBase asCallTreeNodeBase, st matchingFrameIndex = frameIndex; // We keep overwriting it, so we get the entry closest to the root. } + if (exclusiveSample) + { + exclusiveSample = false; + float count = 0; + exclusiveFrameIndexCounts.TryGetValue(matchingFrameIndex, out count); + exclusiveFrameIndexCounts[matchingFrameIndex] = count + sample.Metric; + } callStackIdx = m_stackSource.GetCallerIndex(callStackIdx); } if (matchingFrameIndex != StackSourceFrameIndex.Invalid) @@ -2437,18 +2448,25 @@ private SourceLocation GetSourceLocation(CallTreeNodeBase asCallTreeNodeBase, st if (sourceLocation != null) { var filePathForMax = sourceLocation.SourceFile.BuildTimeFilePath; - metricOnLine = new SortedDictionary(); // Accumulate the counts on a line basis - foreach (StackSourceFrameIndex frameIdx in frameIndexCounts.Keys) + AccumulateCounts(frameIndexCounts, out metricOnLine); + AccumulateCounts(exclusiveFrameIndexCounts, out exclusiveMetricOnLine); + + void AccumulateCounts(Dictionary indexCounts, out SortedDictionary metricHash) { - var loc = asTraceEventStackSource.GetSourceLine(frameIdx, reader); - if (loc != null && loc.SourceFile.BuildTimeFilePath == filePathForMax) + metricHash = new SortedDictionary(); + + foreach (StackSourceFrameIndex frameIdx in indexCounts.Keys) { - frameToLine[frameIdx] = loc.LineNumber; - float metric; - metricOnLine.TryGetValue(loc.LineNumber, out metric); - metric += frameIndexCounts[frameIdx]; - metricOnLine[loc.LineNumber] = metric; + var loc = asTraceEventStackSource.GetSourceLine(frameIdx, reader); + if (loc != null && loc.SourceFile.BuildTimeFilePath == filePathForMax) + { + frameToLine[frameIdx] = loc.LineNumber; + float metric; + metricHash.TryGetValue(loc.LineNumber, out metric); + metric += indexCounts[frameIdx]; + metricHash[loc.LineNumber] = metric; + } } } } @@ -2509,7 +2527,7 @@ private SourceLocation GetSourceLocation(CallTreeNodeBase asCallTreeNodeBase, st return sourceLocation; } - private void AnnotateLines(string inFileName, string outFileName, SortedDictionary lineData) + private void AnnotateLines(string inFileName, string outFileName, params ValueTuple>[] lineData) { using (var inFile = File.OpenText(inFileName)) using (var outFile = File.CreateText(outFileName)) @@ -2525,18 +2543,21 @@ private void AnnotateLines(string inFileName, string outFileName, SortedDictiona lineNum++; - float value; - if (lineData.TryGetValue(lineNum, out value)) - { - outFile.Write(ToCompactString(value)); - } - else if (lineNum == 1) - { - outFile.Write("Metric|"); - } - else + foreach (var data in lineData) { - outFile.Write(" "); + float value; + if (data.Item2.TryGetValue(lineNum, out value)) + { + outFile.Write(ToCompactString(value)); + } + else if (lineNum == 1) + { + outFile.Write($"{data.Item1.PadLeft(6)}|"); + } + else + { + outFile.Write(" "); + } } outFile.WriteLine(line);