Files
RobustToolbox/Robust.Client/Profiling/LiveProfileViewControl.cs

180 lines
5.0 KiB
C#

using System;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Profiling;
using Robust.Shared.Utility;
namespace Robust.Client.Profiling;
public sealed class LiveProfileViewControl : Control
{
[Dependency] private readonly ProfManager _profManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
public int MaxDepth { get; set; } = 2;
private readonly Font? _font;
private readonly char[] _sampleBuffer = new char[32];
public LiveProfileViewControl()
{
IoCManager.InjectDependencies(this);
if (!_resourceCache.TryGetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf", out var font))
return;
_font = font.MakeDefault();
}
protected internal override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (!_profManager.IsEnabled || _font == null)
return;
var baseLine = new Vector2(0, _font.GetAscent(UIScale));
ref readonly var buffer = ref _profManager.Buffer;
ref readonly var index = ref buffer.Index(buffer.IndexWriteOffset - 1);
DrawData drawData = default;
drawData.Font = _font;
drawData.Buffer = buffer;
drawData.Index = index;
drawData.Handle = handle;
var i = index.StartPos;
DrawCmds(in drawData, ref i, ref baseLine, 0);
}
private void DrawCmds(
in DrawData data,
ref long i,
ref Vector2 baseline,
int depth)
{
for (; i < data.Index.EndPos; i++)
{
ref var cmd = ref data.Buffer.Log(i);
DrawCmd(in data, ref i, ref baseline, depth, in cmd);
}
}
private void DrawCmdSample(
in DrawData data,
ref Vector2 baseline,
in ProfLogValue value)
{
DrawSample(in data, baseline, value.StringId, value.Value);
baseline += new Vector2(0, data.Font.GetLineHeight(UIScale));
}
private void DrawSample(
in DrawData data,
Vector2 baseline,
int stringId,
in ProfValue value)
{
var cmdString = _profManager.GetString(stringId);
baseline += data.Handle.DrawString(data.Font, baseline, cmdString, UIScale, Color.White);
baseline += data.Handle.DrawString(data.Font, baseline, ": ", UIScale, Color.White);
var str = value.Type switch
{
ProfValueType.TimeAllocSample =>
FormatHelpers.FormatIntoMem(_sampleBuffer, $"{value.TimeAllocSample.Time * 1000:N2} ms, {value.TimeAllocSample.Alloc} B"),
ProfValueType.Int32 => FormatHelpers.FormatIntoMem(_sampleBuffer, $"{value.Int32}"),
ProfValueType.Int64 => FormatHelpers.FormatIntoMem(_sampleBuffer, $"{value.Int64}"),
_ => "???".AsMemory()
};
data.Handle.DrawString(data.Font, baseline, str.Span, UIScale, Color.White);
}
private void DrawCmd(
in DrawData data,
ref long i,
ref Vector2 baseline,
int depth,
in ProfLog log)
{
switch (log.Type)
{
case ProfLogType.Value:
DrawCmdSample(in data, ref baseline, in log.Value);
break;
case ProfLogType.GroupStart:
DrawEnterGroup(in data, ref i, ref baseline, depth);
break;
}
}
private void DrawEnterGroup(
in DrawData data,
ref long i,
ref Vector2 baseline,
int depth)
{
depth += 1;
var indentSize = 12 * UIScale;
var startBaseline = baseline;
baseline += new Vector2(indentSize, data.Font.GetLineHeight(UIScale));
if (depth > MaxDepth)
{
var startIdx = i;
// Skip contents of this group.
for (; i < data.Index.EndPos; i++)
{
ref var cmd = ref data.Buffer.Log(i);
if (cmd.Type != ProfLogType.GroupEnd)
continue;
if (cmd.GroupEnd.StartIndex <= startIdx)
break;
}
}
else
{
i += 1;
for (; i < data.Index.EndPos; i++)
{
ref var cmd = ref data.Buffer.Log(i);
if (cmd.Type == ProfLogType.GroupEnd)
break;
DrawCmd(in data, ref i, ref baseline, depth, in cmd);
}
}
// Gone through entire list = unmatched begin/end pair
if (i == data.Index.EndPos)
return;
ref var cmdEnd = ref data.Buffer.Log(i).GroupEnd;
baseline -= new Vector2(indentSize, 0);
DrawSample(in data, startBaseline, cmdEnd.StringId, cmdEnd.Value);
}
private struct DrawData
{
public ProfBuffer Buffer;
public ProfIndex Index;
public Font Font;
public DrawingHandleScreen Handle;
}
}