Plugins - Added profiling API

UI - Added profiling tab to debugger
This commit is contained in:
Robert committed 2021-05-16 20:22:13 +02:00
1 parent f13ab9852f
commit 4b24834fd6
18 files changed
+518 -18

No files matched your search

+21 -1
View File
@@ -17,6 +17,7 @@ namespace Artemis.Core
public class Plugin : CorePropertyChanged, IDisposable
{
private readonly List<PluginFeatureInfo> _features;
private readonly List<Profiler> _profilers;
private bool _isEnabled;
@@ -28,6 +29,7 @@ namespace Artemis.Core
Info.Plugin = this;
_features = new List<PluginFeatureInfo>();
_profilers = new List<Profiler>();
}
/// <summary>
@@ -64,6 +66,8 @@ namespace Artemis.Core
/// </summary>
public ReadOnlyCollection<PluginFeatureInfo> Features => _features.AsReadOnly();
public ReadOnlyCollection<Profiler> Profilers => _profilers.AsReadOnly();
/// <summary>
/// The assembly the plugin code lives in
/// </summary>
@@ -114,7 +118,7 @@ namespace Artemis.Core
{
return _features.FirstOrDefault(i => i.Instance is T)?.Instance as T;
}
/// <summary>
/// Looks up the feature info the feature of type <typeparamref name="T" />
/// </summary>
@@ -126,6 +130,22 @@ namespace Artemis.Core
return _features.First(i => i.FeatureType == typeof(T));
}
/// <summary>
/// Gets a profiler with the provided <paramref name="name" />, if it does not yet exist it will be created.
/// </summary>
/// <param name="name">The name of the profiler</param>
/// <returns>A new or existing profiler with the provided <paramref name="name" /></returns>
public Profiler GetProfiler(string name)
{
Profiler? profiler = _profilers.FirstOrDefault(p => p.Name == name);
if (profiler != null)
return profiler;
profiler = new Profiler(this, name);
_profilers.Add(profiler);
return profiler;
}
/// <inheritdoc />
public override string ToString()
{
+10 -11
View File
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Artemis.Storage.Entities.Plugins;
@@ -12,11 +10,9 @@ namespace Artemis.Core
/// </summary>
public abstract class PluginFeature : CorePropertyChanged, IDisposable
{
private readonly Stopwatch _renderStopwatch = new();
private readonly Stopwatch _updateStopwatch = new();
private bool _isEnabled;
private Exception? _loadException;
/// <summary>
/// Gets the plugin feature info related to this feature
/// </summary>
@@ -27,6 +23,11 @@ namespace Artemis.Core
/// </summary>
public Plugin Plugin { get; internal set; } = null!; // Will be set right after construction
/// <summary>
/// Gets the profiler that can be used to take profiling measurements
/// </summary>
public Profiler Profiler { get; internal set; } = null!; // Will be set right after construction
/// <summary>
/// Gets whether the plugin is enabled
/// </summary>
@@ -112,24 +113,22 @@ namespace Artemis.Core
internal void StartUpdateMeasure()
{
_updateStopwatch.Start();
Profiler.StartMeasurement("Update");
}
internal void StopUpdateMeasure()
{
UpdateTime = _updateStopwatch.Elapsed;
_updateStopwatch.Reset();
Profiler.StopMeasurement("Update");
}
internal void StartRenderMeasure()
{
_renderStopwatch.Start();
Profiler.StartMeasurement("Render");
}
internal void StopRenderMeasure()
{
RenderTime = _renderStopwatch.Elapsed;
_renderStopwatch.Reset();
Profiler.StopMeasurement("Render");
}
internal void SetEnabled(bool enable, bool isAutoEnable = false)
+1 -2
View File
@@ -58,8 +58,7 @@ namespace Artemis.Core
/// <summary>
/// The plugins display icon that's shown in the settings see <see href="https://materialdesignicons.com" /> for
/// available
/// icons
/// available icons
/// </summary>
[JsonProperty]
public string? Icon
@@ -0,0 +1,72 @@
using System.Collections.Generic;
namespace Artemis.Core
{
/// <summary>
/// Represents a profiler that can measure time between calls distinguished by identifiers
/// </summary>
public class Profiler
{
internal Profiler(Plugin plugin, string name)
{
Plugin = plugin;
Name = name;
}
/// <summary>
/// Gets the plugin this profiler belongs to
/// </summary>
public Plugin Plugin { get; }
/// <summary>
/// Gets the name of this profiler
/// </summary>
public string Name { get; }
/// <summary>
/// Gets a dictionary containing measurements by their identifiers
/// </summary>
public Dictionary<string, ProfilingMeasurement> Measurements { get; set; } = new();
/// <summary>
/// Starts measuring time for the provided <paramref name="identifier" />
/// </summary>
/// <param name="identifier">A unique identifier for this measurement</param>
public void StartMeasurement(string identifier)
{
if (!Measurements.TryGetValue(identifier, out ProfilingMeasurement? measurement))
{
measurement = new ProfilingMeasurement(identifier);
Measurements.Add(identifier, measurement);
}
measurement.Start();
}
/// <summary>
/// Stops measuring time for the provided <paramref name="identifier" />
/// </summary>
/// <param name="identifier">A unique identifier for this measurement</param>
/// <returns>The number of ticks that passed since the <see cref="StartMeasurement" /> call with the same identifier</returns>
public long StopMeasurement(string identifier)
{
if (!Measurements.TryGetValue(identifier, out ProfilingMeasurement? measurement))
{
measurement = new ProfilingMeasurement(identifier);
Measurements.Add(identifier, measurement);
}
return measurement.Stop();
}
/// <summary>
/// Clears measurements with the the provided <paramref name="identifier" />
/// </summary>
/// <param name="identifier"></param>
public void ClearMeasurements(string identifier)
{
Measurements.Remove(identifier);
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Linq;
namespace Artemis.Core
{
/// <summary>
/// Represents a set of profiling measurements
/// </summary>
public class ProfilingMeasurement
{
private bool _filledArray;
private int _index;
private long _last;
private DateTime? _start;
internal ProfilingMeasurement(string identifier)
{
Identifier = identifier;
}
/// <summary>
/// Gets the unique identifier of this measurement
/// </summary>
public string Identifier { get; }
/// <summary>
/// Gets the last 1000 measurements
/// </summary>
public long[] Measurements { get; } = new long[1000];
/// <summary>
/// Starts measuring time until <see cref="Stop" /> is called
/// </summary>
public void Start()
{
_start = DateTime.UtcNow;
}
/// <summary>
/// Stops measuring time and stores the time passed in the <see cref="Measurements" /> list
/// </summary>
/// <returns>The time passed since the last <see cref="Start" /> call</returns>
public long Stop()
{
if (_start == null)
return 0;
long difference = (DateTime.UtcNow - _start.Value).Ticks;
Measurements[_index] = difference;
_start = null;
_index++;
if (_index >= 1000)
{
_filledArray = true;
_index = 0;
}
_last = difference;
return difference;
}
/// <summary>
/// Gets the last measured time
/// </summary>
public TimeSpan GetLast()
{
return new(_last);
}
/// <summary>
/// Gets the average time of the last 1000 measurements
/// </summary>
public TimeSpan GetAverage()
{
if (!_filledArray && _index == 0)
return TimeSpan.Zero;
return _filledArray
? new TimeSpan((long) Measurements.Average(m => m))
: new TimeSpan((long) Measurements.Take(_index).Average(m => m));
}
/// <summary>
/// Gets the min time of the last 1000 measurements
/// </summary>
public TimeSpan GetMin()
{
if (!_filledArray && _index == 0)
return TimeSpan.Zero;
return _filledArray
? new TimeSpan(Measurements.Min())
: new TimeSpan(Measurements.Take(_index).Min());
}
/// <summary>
/// Gets the max time of the last 1000 measurements
/// </summary>
public TimeSpan GetMax()
{
if (!_filledArray && _index == 0)
return TimeSpan.Zero;
return _filledArray
? new TimeSpan(Measurements.Max())
: new TimeSpan(Measurements.Take(_index).Max());
}
}
}