Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions src/PerfView.Tests/DebuggerStackSourceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Diagnostics.Tracing.StackSources;
using Microsoft.Diagnostics.Tracing.Stacks;
using System.IO;
using Xunit;

namespace PerfViewTests
{
public class DebuggerStackSourceTests
{
[Fact]
public void TestLastSampleIsNotDropped()
{
// Create a sample cdbstack file with two samples
var cdbStackContent = @"Call Site
coreclr!JIT_MonEnterWorker_Portable
System_Windows_ni!MS.Internal.ManagedPeerTable.TryGetManagedPeer(IntPtr, Boolean, System.Object ByRef)
Call Site
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart";

DebuggerStackSource stackSource;
using (var reader = new StringReader(cdbStackContent))
{
stackSource = new DebuggerStackSource(reader);
}

// Count the samples
int sampleCount = 0;
stackSource.ForEach(sample => sampleCount++);

// We should have 2 samples, but the bug causes only 1 to be added
Assert.Equal(2, sampleCount);
}

[Fact]
public void TestSingleSampleIsAdded()
{
// Create a sample cdbstack file with a single sample (no subsequent "Call Site")
var cdbStackContent = @"Call Site
coreclr!JIT_MonEnterWorker_Portable
System_Windows_ni!MS.Internal.ManagedPeerTable.TryGetManagedPeer(IntPtr, Boolean, System.Object ByRef)";

DebuggerStackSource stackSource;
using (var reader = new StringReader(cdbStackContent))
{
stackSource = new DebuggerStackSource(reader);
}

// Count the samples
int sampleCount = 0;
stackSource.ForEach(sample => sampleCount++);

// We should have 1 sample
Assert.Equal(1, sampleCount);
}

[Fact]
public void TestSampleMetricIsSet()
{
// Create a sample cdbstack file with one sample
var cdbStackContent = @"Call Site
coreclr!JIT_MonEnterWorker_Portable
System_Windows_ni!MS.Internal.ManagedPeerTable.TryGetManagedPeer(IntPtr, Boolean, System.Object ByRef)";

DebuggerStackSource stackSource;
using (var reader = new StringReader(cdbStackContent))
{
stackSource = new DebuggerStackSource(reader);
}

// Check that metric is set to 1 for each sample
stackSource.ForEach(sample =>
{
Assert.Equal(1, sample.Metric);
});
}
}
}
38 changes: 25 additions & 13 deletions src/PerfView/OtherSources/DebuggerStackSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ private struct DebuggerCallStackFrame
public StackSourceFrameIndex frame;
}

private void AddSampleFromStack(GrowableArray<DebuggerCallStackFrame> stack, StackSourceSample sample, ref float time)
{
StackSourceCallStackIndex parent = StackSourceCallStackIndex.Invalid;
for (int i = stack.Count - 1; i >= 0; --i)
{
parent = Interner.CallStackIntern(stack[i].frame, parent);
}

stack.Clear();

sample.Metric = 1;
sample.StackIndex = parent;
sample.TimeRelativeMSec = time;
time++;
AddSample(sample);
}

private void Read(TextReader reader)
{
var framePattern = new Regex(@"\b(\w+?)\!(\S\(?[\S\s]*\)?)");
Expand Down Expand Up @@ -93,25 +110,20 @@ private void Read(TextReader reader)
// clear the stack
if (stack.Count != 0)
{

StackSourceCallStackIndex parent = StackSourceCallStackIndex.Invalid;
for (int i = stack.Count - 1; i >= 0; --i)
{
parent = Interner.CallStackIntern(stack[i].frame, parent);
}

stack.Clear();

sample.StackIndex = parent;
sample.TimeRelativeMSec = time;
time++;
AddSample(sample);
AddSampleFromStack(stack, sample, ref time);
}
newCallStackFound = true;

}
}
}

// Handle the last sample if there are any remaining frames
if (stack.Count != 0)
{
AddSampleFromStack(stack, sample, ref time);
}

Interner.DoneInterning();
}
#endregion
Expand Down