mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Plugins - Added profiling API
UI - Added profiling tab to debugger
This commit is contained in:
1 parent
f13ab9852f
commit
4b24834fd6
18 files changed
+518
-18
No files matched your search
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user