in src/PerfView/OtherSources/XMLStackSource.cs [312:575]
private void Read(XmlReader reader)
{
Stack<string> frameStack = null;
// We use the invarient culture, otherwise if we encode in france and decode
// in english we get parse errors (this happened!);
var invariantCulture = CultureInfo.InvariantCulture;
var inputDepth = reader.Depth;
var depthForSamples = 0;
while (reader.Read())
{
PROCESS_NODE:
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "Sample")
{
var sample = new StackSourceSample(this);
sample.Metric = 1;
if (reader.MoveToFirstAttribute())
{
do
{
if (reader.Name == "Time")
{
sample.TimeRelativeMSec = double.Parse(reader.ReadContentAsString(), invariantCulture);
}
else if (reader.Name == "StackID")
{
sample.StackIndex = (StackSourceCallStackIndex)reader.ReadContentAsInt();
}
else if (reader.Name == "Metric")
{
sample.Metric = float.Parse(reader.ReadContentAsString(), invariantCulture);
}
} while (reader.MoveToNextAttribute());
}
sample.SampleIndex = (StackSourceSampleIndex)m_curSample;
m_samples.Set(m_curSample++, sample);
if (sample.TimeRelativeMSec > m_maxTime)
{
m_maxTime = sample.TimeRelativeMSec;
}
// See if there is a literal stack present as the body of
if (!reader.Read())
{
break;
}
if (reader.NodeType != XmlNodeType.Text)
{
goto PROCESS_NODE;
}
string rawStack = reader.Value.Trim();
if (0 < rawStack.Length)
{
InitInterner();
StackSourceCallStackIndex stackIdx = StackSourceCallStackIndex.Invalid;
string[] frames = rawStack.Split('\n');
for (int i = frames.Length - 1; 0 <= i; --i)
{
var frameIdx = m_interner.FrameIntern(frames[i].Trim());
stackIdx = m_interner.CallStackIntern(frameIdx, stackIdx);
}
sample.StackIndex = stackIdx;
}
}
else if (reader.Name == "Stack")
{
int stackID = -1;
int callerID = -1;
int frameID = -1;
if (reader.MoveToFirstAttribute())
{
do
{
if (reader.Name == "ID")
{
stackID = reader.ReadContentAsInt();
}
else if (reader.Name == "FrameID")
{
frameID = reader.ReadContentAsInt();
}
else if (reader.Name == "CallerID")
{
callerID = reader.ReadContentAsInt();
}
} while (reader.MoveToNextAttribute());
if (0 <= stackID)
{
m_stacks.Set(stackID, new Frame(frameID, callerID));
}
}
}
else if (reader.Name == "Frame")
{
var frameID = -1;
var optimizationTierStr = string.Empty;
if (reader.MoveToFirstAttribute())
{
do
{
if (reader.Name == "ID")
{
frameID = reader.ReadContentAsInt();
}
else if (reader.Name == "OptimizationTier")
{
if (m_showOptimizationTiers)
{
var optimizationTierCandidateStr = reader.ReadContentAsString();
if (Enum.TryParse<OptimizationTier>(optimizationTierCandidateStr, out var optimizationTier) &&
optimizationTier != OptimizationTier.Unknown)
{
optimizationTierStr = optimizationTierCandidateStr;
}
}
}
} while (reader.MoveToNextAttribute());
}
reader.Read(); // Move on to body of the element
var frameName = reader.ReadContentAsString();
if (optimizationTierStr.Length > 0)
{
int exclamationIndex = frameName.IndexOf('!');
if (exclamationIndex >= 0)
{
frameName =
frameName.Substring(0, exclamationIndex + 1) +
$"[{optimizationTierStr}]" +
frameName.Substring(exclamationIndex + 1);
}
}
m_frames.Set(frameID, frameName);
}
else if (reader.Name == "Frames")
{
var count = reader.GetAttribute("Count");
if (count != null && m_frames.Count == 0)
{
m_frames = new GrowableArray<string>(int.Parse(count));
}
}
else if (reader.Name == "Stacks")
{
var count = reader.GetAttribute("Count");
if (count != null && m_stacks.Count == 0)
{
m_stacks = new GrowableArray<Frame>(int.Parse(count));
}
#if DEBUG
for (int i = 0; i < m_stacks.Count; i++)
m_stacks[i] = new Frame(int.MinValue, int.MinValue);
#endif
}
else if (reader.Name == "Samples")
{
var count = reader.GetAttribute("Count");
if (count != null && m_samples.Count == 0)
{
m_samples = new GrowableArray<StackSourceSample>(int.Parse(count));
}
depthForSamples = reader.Depth;
}
// This is the logic for the JSON case. These are the anonymous object representing a sample.
else if (reader.Name == "item")
{
// THis is an item which is an element of the 'Samples' array.
if (reader.Depth == depthForSamples + 1)
{
var sample = new StackSourceSample(this);
sample.Metric = 1;
InitInterner();
int depthForSample = reader.Depth;
if (frameStack == null)
{
frameStack = new Stack<string>();
}
frameStack.Clear();
while (reader.Read())
{
PROCESS_NODE_SAMPLE:
if (reader.Depth <= depthForSample)
{
break;
}
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == "Time")
{
sample.TimeRelativeMSec = reader.ReadElementContentAsDouble();
goto PROCESS_NODE_SAMPLE;
}
else if (reader.Name == "Metric")
{
sample.Metric = (float)reader.ReadElementContentAsDouble();
goto PROCESS_NODE_SAMPLE;
}
else if (reader.Name == "item")
{
// Item is a string under stack under the sample.
if (reader.Depth == depthForSample + 2)
{
frameStack.Push(reader.ReadElementContentAsString());
goto PROCESS_NODE_SAMPLE;
}
}
}
}
// Reverse the order of the frames in the stack.
sample.StackIndex = StackSourceCallStackIndex.Invalid;
while (0 < frameStack.Count)
{
var frameIdx = m_interner.FrameIntern(frameStack.Pop());
sample.StackIndex = m_interner.CallStackIntern(frameIdx, sample.StackIndex);
}
if (sample.TimeRelativeMSec > m_maxTime)
{
m_maxTime = sample.TimeRelativeMSec;
}
sample.SampleIndex = (StackSourceSampleIndex)m_curSample;
m_samples.Set(m_curSample++, sample);
}
}
break;
case XmlNodeType.EndElement:
if (reader.Depth <= inputDepth)
{
reader.Read();
goto Done;
}
break;
case XmlNodeType.Text:
default:
break;
}
}
Done:;
#if DEBUG
for (int i = 0; i < m_samples.Count; i++)
Debug.Assert(m_samples[i] != null);
for (int i = 0; i < m_frames.Count; i++)
Debug.Assert(m_frames[i] != null);
for (int i = 0; i < m_stacks.Count; i++)
{
Debug.Assert(m_stacks[i].frameID >= 0);
Debug.Assert(m_stacks[i].callerID >= -1);
}
#endif
}