Add pooling for timeline event controls in profiler

This commit is contained in:
Wojtek Figat
2021-06-11 16:44:26 +02:00
parent 9c7378cf5b
commit 81fd026313
3 changed files with 134 additions and 43 deletions

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -50,7 +51,9 @@ namespace FlaxEditor.Windows.Profiler
private readonly SingleChart _mainChart;
private readonly Timeline _timeline;
private readonly Table _table;
private readonly SamplesBuffer<ProfilingTools.ThreadStats[]> _events = new SamplesBuffer<ProfilingTools.ThreadStats[]>();
private SamplesBuffer<ProfilingTools.ThreadStats[]> _events;
private List<Timeline.TrackLabel> _timelineLabelsCache;
private List<Timeline.Event> _timelineEventsCache;
private bool _showOnlyLastUpdateEvents;
public CPU()
@@ -163,7 +166,7 @@ namespace FlaxEditor.Windows.Profiler
public override void Clear()
{
_mainChart.Clear();
_events.Clear();
_events?.Clear();
}
/// <inheritdoc />
@@ -173,6 +176,8 @@ namespace FlaxEditor.Windows.Profiler
// Gather CPU events
var events = sharedData.GetEventsCPU();
if (_events == null)
_events = new SamplesBuffer<ProfilingTools.ThreadStats[]>();
_events.Add(events);
}
@@ -182,11 +187,28 @@ namespace FlaxEditor.Windows.Profiler
_showOnlyLastUpdateEvents = showOnlyLastUpdateEvents;
_mainChart.SelectedSampleIndex = selectedFrame;
if (_events == null)
return;
if (_timelineLabelsCache == null)
_timelineLabelsCache = new List<Timeline.TrackLabel>();
if (_timelineEventsCache == null)
_timelineEventsCache = new List<Timeline.Event>();
var viewRange = GetEventsViewRange();
UpdateTimeline(ref viewRange);
UpdateTable(ref viewRange);
}
/// <inheritdoc />
public override void OnDestroy()
{
Clear();
_timelineLabelsCache?.Clear();
_timelineEventsCache?.Clear();
base.OnDestroy();
}
private struct ViewRange
{
public double Start;
@@ -215,7 +237,7 @@ namespace FlaxEditor.Windows.Profiler
if (_showOnlyLastUpdateEvents)
{
// Find root event named 'Update' and use it as a view range
if (_events.Count != 0)
if (_events != null && _events.Count != 0)
{
var data = _events.Get(_mainChart.SelectedSampleIndex);
if (data != null)
@@ -251,14 +273,22 @@ namespace FlaxEditor.Windows.Profiler
double scale = 100.0;
float x = (float)((e.Start - startTime) * scale);
float width = (float)(length * scale);
string name = e.Name.Replace("::", ".");
var control = new Timeline.Event(x + xOffset, e.Depth + depthOffset, width)
Timeline.Event control;
if (_timelineEventsCache.Count != 0)
{
Name = name,
TooltipText = string.Format("{0}, {1} ms", name, ((int)(length * 1000.0) / 1000.0f)),
Parent = parent,
};
var last = _timelineEventsCache.Count - 1;
control = _timelineEventsCache[last];
_timelineEventsCache.RemoveAt(last);
}
else
{
control = new Timeline.Event();
}
control.Bounds = new Rectangle(x + xOffset, (e.Depth + depthOffset) * Timeline.Event.DefaultHeight, width, Timeline.Event.DefaultHeight - 1);
control.Name = e.Name.Replace("::", ".");
control.TooltipText = string.Format("{0}, {1} ms", control.Name, ((int)(length * 1000.0) / 1000.0f));
control.Parent = parent;
// Spawn sub events
int childrenDepth = e.Depth + 1;
@@ -282,10 +312,26 @@ namespace FlaxEditor.Windows.Profiler
{
var container = _timeline.EventsContainer;
// Clear previous events
container.DisposeChildren();
container.LockChildrenRecursive();
container.IsLayoutLocked = true;
int idx = 0;
while (container.Children.Count > idx)
{
var child = container.Children[idx];
if (child is Timeline.Event e)
{
_timelineEventsCache.Add(e);
child.Parent = null;
}
else if (child is Timeline.TrackLabel l)
{
_timelineLabelsCache.Add(l);
child.Parent = null;
}
else
{
idx++;
}
}
_timeline.Height = UpdateTimelineInner(ref viewRange);
@@ -340,13 +386,21 @@ namespace FlaxEditor.Windows.Profiler
// Add thread label
float xOffset = 90;
var label = new Timeline.TrackLabel
Timeline.TrackLabel trackLabel;
if (_timelineLabelsCache.Count != 0)
{
Bounds = new Rectangle(0, depthOffset * Timeline.Event.DefaultHeight, xOffset, (maxDepth + 2) * Timeline.Event.DefaultHeight),
Name = data[i].Name,
BackgroundColor = Style.Current.Background * 1.1f,
Parent = container,
};
var last = _timelineLabelsCache.Count - 1;
trackLabel = _timelineLabelsCache[last];
_timelineLabelsCache.RemoveAt(last);
}
else
{
trackLabel = new Timeline.TrackLabel();
}
trackLabel.Bounds = new Rectangle(0, depthOffset * Timeline.Event.DefaultHeight, xOffset, (maxDepth + 2) * Timeline.Event.DefaultHeight);
trackLabel.Name = data[i].Name;
trackLabel.BackgroundColor = Style.Current.Background * 1.1f;
trackLabel.Parent = container;
// Add events
for (int j = 0; j < events.Length; j++)
@@ -371,7 +425,6 @@ namespace FlaxEditor.Windows.Profiler
private void UpdateTable(ref ViewRange viewRange)
{
_table.DisposeChildren();
_table.LockChildrenRecursive();
UpdateTableInner(ref viewRange);

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -16,7 +17,8 @@ namespace FlaxEditor.Windows.Profiler
private readonly SingleChart _drawTimeGPU;
private readonly Timeline _timeline;
private readonly Table _table;
private readonly SamplesBuffer<ProfilerGPU.Event[]> _events = new SamplesBuffer<ProfilerGPU.Event[]>();
private SamplesBuffer<ProfilerGPU.Event[]> _events;
private List<Timeline.Event> _timelineEventsCache;
public GPU()
: base("GPU")
@@ -118,7 +120,7 @@ namespace FlaxEditor.Windows.Profiler
{
_drawTimeCPU.Clear();
_drawTimeGPU.Clear();
_events.Clear();
_events?.Clear();
}
/// <inheritdoc />
@@ -126,6 +128,8 @@ namespace FlaxEditor.Windows.Profiler
{
// Gather GPU events
var data = sharedData.GetEventsGPU();
if (_events == null)
_events = new SamplesBuffer<ProfilerGPU.Event[]>();
_events.Add(data);
// Peek draw time
@@ -138,10 +142,25 @@ namespace FlaxEditor.Windows.Profiler
{
_drawTimeCPU.SelectedSampleIndex = selectedFrame;
_drawTimeGPU.SelectedSampleIndex = selectedFrame;
if (_events == null)
return;
if (_timelineEventsCache == null)
_timelineEventsCache = new List<Timeline.Event>();
UpdateTimeline();
UpdateTable();
}
/// <inheritdoc />
public override void OnDestroy()
{
Clear();
_timelineEventsCache?.Clear();
base.OnDestroy();
}
private float AddEvent(float x, int maxDepth, int index, ProfilerGPU.Event[] events, ContainerControl parent)
{
ref ProfilerGPU.Event e = ref events[index];
@@ -150,12 +169,21 @@ namespace FlaxEditor.Windows.Profiler
float width = (float)(e.Time * scale);
string name = new string(e.Name);
new Timeline.Event(x, e.Depth, width)
Timeline.Event control;
if (_timelineEventsCache.Count != 0)
{
Name = name,
TooltipText = string.Format("{0}, {1} ms", name, ((int)(e.Time * 10000.0) / 10000.0f)),
Parent = parent,
};
var last = _timelineEventsCache.Count - 1;
control = _timelineEventsCache[last];
_timelineEventsCache.RemoveAt(last);
}
else
{
control = new Timeline.Event();
}
control.Bounds = new Rectangle(x, e.Depth * Timeline.Event.DefaultHeight, width, Timeline.Event.DefaultHeight - 1);
control.Name = name;
control.TooltipText = string.Format("{0}, {1} ms", name, ((int)(e.Time * 10000.0) / 10000.0f));
control.Parent = parent;
// Spawn sub events
int childrenDepth = e.Depth + 1;
@@ -201,8 +229,21 @@ namespace FlaxEditor.Windows.Profiler
{
var container = _timeline.EventsContainer;
// Clear previous events
container.DisposeChildren();
container.IsLayoutLocked = true;
int idx = 0;
while (container.Children.Count > idx)
{
var child = container.Children[idx];
if (child is Timeline.Event e)
{
_timelineEventsCache.Add(e);
child.Parent = null;
}
else
{
idx++;
}
}
container.LockChildrenRecursive();

View File

@@ -40,7 +40,8 @@ namespace FlaxEditor.Windows.Profiler
};
private Color _color;
private float _nameLength;
private string _name;
private float _nameLength = -1;
/// <summary>
/// The default height of the event.
@@ -50,18 +51,14 @@ namespace FlaxEditor.Windows.Profiler
/// <summary>
/// Gets or sets the event name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Event"/> class.
/// </summary>
/// <param name="x">The x position.</param>
/// <param name="depth">The timeline row index (event depth).</param>
/// <param name="width">The width.</param>
public Event(float x, int depth, float width)
: base(x, depth * DefaultHeight, width, DefaultHeight - 1)
public string Name
{
_nameLength = -1;
get => _name;
set
{
_name = value;
_nameLength = -1;
}
}
/// <inheritdoc />
@@ -88,12 +85,12 @@ namespace FlaxEditor.Windows.Profiler
Render2D.DrawRectangle(bounds, color * 0.5f);
if (_nameLength < 0 && style.FontMedium)
_nameLength = style.FontMedium.MeasureText(Name).X;
_nameLength = style.FontMedium.MeasureText(_name).X;
if (_nameLength < bounds.Width + 4)
{
Render2D.PushClip(bounds);
Render2D.DrawText(style.FontMedium, Name, bounds, Color.White, TextAlignment.Center, TextAlignment.Center);
Render2D.DrawText(style.FontMedium, _name, bounds, Color.White, TextAlignment.Center, TextAlignment.Center);
Render2D.PopClip();
}
}