Add thread metrics and category support to Profiler and visualizer
This commit is contained in:
@@ -14,6 +14,7 @@ namespace Nerfed.Editor.Systems
|
||||
private int selectedFrame = 0;
|
||||
private int previousSelectedFrame = -1;
|
||||
private IOrderedEnumerable<KeyValuePair<string, (double ms, double selfMs, uint calls, double avgMs, double p95Ms)>> orderedCombinedData = null;
|
||||
private IOrderedEnumerable<KeyValuePair<int, Profiler.RollingThreadMetrics>> orderedThreadRollingData = null;
|
||||
private readonly ProfilerVisualizer.TimelineState timelineState = new ProfilerVisualizer.TimelineState();
|
||||
private readonly List<Profiler.Frame> frameSnapshot = new List<Profiler.Frame>(256);
|
||||
|
||||
@@ -67,6 +68,22 @@ namespace Nerfed.Editor.Systems
|
||||
timelineState.FollowLatest = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
int mode = (int)Profiler.Mode;
|
||||
ImGui.SetNextItemWidth(130f);
|
||||
if (ImGui.Combo("Mode", ref mode, "Instrumented\0Sampled\0"))
|
||||
{
|
||||
Profiler.Mode = (Profiler.CaptureMode)mode;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
int stride = Profiler.SamplingStride;
|
||||
ImGui.SetNextItemWidth(90f);
|
||||
if (ImGui.SliderInt("Stride", ref stride, 1, 64))
|
||||
{
|
||||
Profiler.SamplingStride = stride;
|
||||
}
|
||||
|
||||
if (Profiler.IsRecording)
|
||||
{
|
||||
// Select last frame when recording to see latest frame data.
|
||||
@@ -86,6 +103,7 @@ namespace Nerfed.Editor.Systems
|
||||
double s = 1000;
|
||||
ImGui.Text($"Frame: {frame.FrameCount} ({ms:0.000} ms | {(s / ms):0} fps)");
|
||||
ImGui.Text($"Budget: {frame.BudgetMilliseconds:0.00} ms ({(frame.OverBudget ? "over" : "within")})");
|
||||
ImGui.Text($"Thread Budget: {Profiler.ThreadBudgetMilliseconds:0.00} ms | Capture: {Profiler.Mode}");
|
||||
ImGui.Text($"Alloc: {frame.AllocatedBytesDelta / 1024d:0.0} KB | GC: G0 {frame.Gen0CollectionsDelta}, G1 {frame.Gen1CollectionsDelta}, G2 {frame.Gen2CollectionsDelta}");
|
||||
ImGui.EndChild();
|
||||
|
||||
@@ -102,8 +120,11 @@ namespace Nerfed.Editor.Systems
|
||||
{
|
||||
previousSelectedFrame = selectedFrame;
|
||||
orderedCombinedData = CalculateCombinedData(frame);
|
||||
orderedThreadRollingData = CalculateThreadRollingData();
|
||||
}
|
||||
|
||||
DrawThreadRolling(orderedThreadRollingData);
|
||||
|
||||
DrawHierachy(frame);
|
||||
|
||||
ImGui.SameLine();
|
||||
@@ -122,12 +143,14 @@ namespace Nerfed.Editor.Systems
|
||||
|
||||
ImGui.BeginChild("Hierachy", new Vector2(150, 0), ImGuiChildFlags.ResizeX);
|
||||
|
||||
if (ImGui.BeginTable("ProfilerData", 4, tableFlags, new Vector2(0, 0)))
|
||||
if (ImGui.BeginTable("ProfilerData", 6, tableFlags, new Vector2(0, 0)))
|
||||
{
|
||||
ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch, 0.6f, 0);
|
||||
ImGui.TableSetupColumn("thread", ImGuiTableColumnFlags.WidthStretch, 0.15f, 1);
|
||||
ImGui.TableSetupColumn("ms", ImGuiTableColumnFlags.WidthStretch, 0.15f, 1);
|
||||
ImGui.TableSetupColumn("self", ImGuiTableColumnFlags.WidthStretch, 0.15f, 2);
|
||||
ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch, 0.40f, 0);
|
||||
ImGui.TableSetupColumn("category", ImGuiTableColumnFlags.WidthStretch, 0.15f, 1);
|
||||
ImGui.TableSetupColumn("tags", ImGuiTableColumnFlags.WidthStretch, 0.10f, 2);
|
||||
ImGui.TableSetupColumn("thread", ImGuiTableColumnFlags.WidthStretch, 0.10f, 3);
|
||||
ImGui.TableSetupColumn("ms", ImGuiTableColumnFlags.WidthStretch, 0.10f, 4);
|
||||
ImGui.TableSetupColumn("self", ImGuiTableColumnFlags.WidthStretch, 0.10f, 5);
|
||||
ImGui.TableSetupScrollFreeze(0, 1); // Make row always visible
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
@@ -158,6 +181,10 @@ namespace Nerfed.Editor.Systems
|
||||
isOpen = ImGui.TreeNodeEx(node.Label, treeNodeFlags);
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{node.Category}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"0x{node.TagMask:X}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{node.ManagedThreadId}");
|
||||
ImGui.TableNextColumn();
|
||||
@@ -235,6 +262,53 @@ namespace Nerfed.Editor.Systems
|
||||
return combinedRecordData.OrderByDescending(x => x.Value.ms);
|
||||
}
|
||||
|
||||
private static IOrderedEnumerable<KeyValuePair<int, Profiler.RollingThreadMetrics>> CalculateThreadRollingData()
|
||||
{
|
||||
IReadOnlyDictionary<int, Profiler.RollingThreadMetrics> rollingData = Profiler.GetRollingThreadMetricsSnapshot();
|
||||
return rollingData.OrderByDescending(x => x.Value.P95Ms);
|
||||
}
|
||||
|
||||
private static void DrawThreadRolling(in IOrderedEnumerable<KeyValuePair<int, Profiler.RollingThreadMetrics>> orderedThreadRollingData)
|
||||
{
|
||||
if (orderedThreadRollingData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.BeginChild("ThreadRolling", new Vector2(0, 140), ImGuiChildFlags.Border);
|
||||
if (ImGui.BeginTable("ProfilerThreadRollingData", 6, tableFlags, new Vector2(0, 0)))
|
||||
{
|
||||
ImGui.TableSetupColumn("thread", ImGuiTableColumnFlags.WidthStretch, 0.15f, 0);
|
||||
ImGui.TableSetupColumn("avg", ImGuiTableColumnFlags.WidthStretch, 0.20f, 1);
|
||||
ImGui.TableSetupColumn("p95", ImGuiTableColumnFlags.WidthStretch, 0.20f, 2);
|
||||
ImGui.TableSetupColumn("max", ImGuiTableColumnFlags.WidthStretch, 0.20f, 3);
|
||||
ImGui.TableSetupColumn("samples", ImGuiTableColumnFlags.WidthStretch, 0.15f, 4);
|
||||
ImGui.TableSetupColumn("misses", ImGuiTableColumnFlags.WidthStretch, 0.15f, 5);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
foreach (KeyValuePair<int, Profiler.RollingThreadMetrics> metric in orderedThreadRollingData)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"T{metric.Key}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{metric.Value.AverageMs:0.000}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{metric.Value.P95Ms:0.000}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{metric.Value.MaxMs:0.000}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{metric.Value.Samples}");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text($"{metric.Value.BudgetMisses}");
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
private static ProfilerVisualizer.TimelineRenderResult DrawFlameGraph(IReadOnlyList<Profiler.Frame> frames, ProfilerVisualizer.TimelineState timelineState)
|
||||
{
|
||||
if (frames == null || frames.Count == 0)
|
||||
|
||||
Reference in New Issue
Block a user