diff options
author | Drachenkaetzchen <felicia@drachenkatze.org> | 2020-01-15 19:08:50 +0100 |
---|---|---|
committer | Drachenkaetzchen <felicia@drachenkatze.org> | 2020-01-15 19:08:50 +0100 |
commit | 84973ce5727ad20fe8b8ba4f89e59c8b754f799e (patch) | |
tree | 90c7f55d3a42ec73afdf86cebd8ae980ec3c1c4d /src/SMAPI/Framework | |
parent | 238b5db4f7f2f05e8967cc5eda761733d4bf35b4 (diff) | |
download | SMAPI-84973ce5727ad20fe8b8ba4f89e59c8b754f799e.tar.gz SMAPI-84973ce5727ad20fe8b8ba4f89e59c8b754f799e.tar.bz2 SMAPI-84973ce5727ad20fe8b8ba4f89e59c8b754f799e.zip |
Added peak execution time over the last 60 seconds
Diffstat (limited to 'src/SMAPI/Framework')
4 files changed, 88 insertions, 8 deletions
diff --git a/src/SMAPI/Framework/PerformanceCounter/PeakEntry.cs b/src/SMAPI/Framework/PerformanceCounter/PeakEntry.cs new file mode 100644 index 00000000..95dc11f4 --- /dev/null +++ b/src/SMAPI/Framework/PerformanceCounter/PeakEntry.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace StardewModdingAPI.Framework.PerformanceCounter +{ + internal struct PeakEntry + { + /// <summary>The actual execution time in milliseconds.</summary> + public readonly double ExecutionTimeMilliseconds; + + /// <summary>The DateTime when the entry occured.</summary> + public DateTime EventTime; + + /// <summary>The context list, which records all sources involved in exceeding the threshold.</summary> + public readonly List<AlertContext> Context; + + public PeakEntry(double executionTimeMilliseconds, DateTime eventTime, List<AlertContext> context) + { + this.ExecutionTimeMilliseconds = executionTimeMilliseconds; + this.EventTime = eventTime; + this.Context = context; + } + } +} diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs index 33ddde2f..3d902e16 100644 --- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs +++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs @@ -68,6 +68,26 @@ namespace StardewModdingAPI.Framework.PerformanceCounter return this.PeakPerformanceCounterEntry; } + /// <summary>Returns the peak entry.</summary> + /// <returns>The peak entry.</returns> + public PerformanceCounterEntry? GetPeak(TimeSpan range, DateTime? relativeTo = null) + { + if (this._counter.IsEmpty) + return null; + + if (relativeTo == null) + relativeTo = DateTime.UtcNow; + + DateTime start = relativeTo.Value.Subtract(range); + + var entries = this._counter.Where(x => (x.EventTime >= start) && (x.EventTime <= relativeTo)).ToList(); + + if (!entries.Any()) + return null; + + return entries.OrderByDescending(x => x.ElapsedMilliseconds).First(); + } + /// <summary>Resets the peak entry.</summary> public void ResetPeak() { diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs index b48efd67..fe14ebf8 100644 --- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs +++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs @@ -2,11 +2,15 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Cyotek.Collections.Generic; namespace StardewModdingAPI.Framework.PerformanceCounter { internal class PerformanceCounterCollection { + /// <summary>The size of the ring buffer.</summary> + private const int MAX_ENTRIES = 16384; + /// <summary>The list of triggered performance counters.</summary> private readonly List<AlertContext> TriggeredPerformanceCounters = new List<AlertContext>(); @@ -22,6 +26,10 @@ namespace StardewModdingAPI.Framework.PerformanceCounter /// <summary>The number of invocations of this collection.</summary> private long CallCount; + /// <summary>The circular buffer which stores all peak invocations</summary> + private readonly CircularBuffer<PeakEntry> PeakInvocations; + + /// <summary>The associated performance counters.</summary> public IDictionary<string, PerformanceCounter> PerformanceCounters { get; } = new Dictionary<string, PerformanceCounter>(); /// <summary>The name of this collection.</summary> @@ -39,6 +47,7 @@ namespace StardewModdingAPI.Framework.PerformanceCounter public PerformanceCounterCollection(PerformanceCounterManager performanceCounterManager, string name, bool isImportant) { + this.PeakInvocations = new CircularBuffer<PeakEntry>(PerformanceCounterCollection.MAX_ENTRIES); this.Name = name; this.PerformanceCounterManager = performanceCounterManager; this.IsImportant = isImportant; @@ -46,6 +55,7 @@ namespace StardewModdingAPI.Framework.PerformanceCounter public PerformanceCounterCollection(PerformanceCounterManager performanceCounterManager, string name) { + this.PeakInvocations = new CircularBuffer<PeakEntry>(PerformanceCounterCollection.MAX_ENTRIES); this.PerformanceCounterManager = performanceCounterManager; this.Name = name; } @@ -89,15 +99,30 @@ namespace StardewModdingAPI.Framework.PerformanceCounter return 0; } + public double GetPeakExecutionTime(TimeSpan range, DateTime? relativeTo = null) + { + if (this.PeakInvocations.IsEmpty) + return 0; + + if (relativeTo == null) + relativeTo = DateTime.UtcNow; + + DateTime start = relativeTo.Value.Subtract(range); + + var entries = this.PeakInvocations.Where(x => (x.EventTime >= start) && (x.EventTime <= relativeTo)).ToList(); + + if (!entries.Any()) + return 0; + + return entries.OrderByDescending(x => x.ExecutionTimeMilliseconds).First().ExecutionTimeMilliseconds; + } + /// <summary>Begins tracking the invocation of this collection.</summary> public void BeginTrackInvocation() { - if (this.EnableAlerts) - { - this.TriggeredPerformanceCounters.Clear(); - this.InvocationStopwatch.Reset(); - this.InvocationStopwatch.Start(); - } + this.TriggeredPerformanceCounters.Clear(); + this.InvocationStopwatch.Reset(); + this.InvocationStopwatch.Start(); this.CallCount++; } @@ -106,10 +131,15 @@ namespace StardewModdingAPI.Framework.PerformanceCounter /// and the invocation time exceeds the threshold.</summary> public void EndTrackInvocation() { - if (!this.EnableAlerts) return; - this.InvocationStopwatch.Stop(); + this.PeakInvocations.Put( + new PeakEntry(this.InvocationStopwatch.Elapsed.TotalMilliseconds, + DateTime.UtcNow, + this.TriggeredPerformanceCounters)); + + if (!this.EnableAlerts) return; + if (this.InvocationStopwatch.Elapsed.TotalMilliseconds >= this.AlertThresholdMilliseconds) this.AddAlert(this.InvocationStopwatch.Elapsed.TotalMilliseconds, this.AlertThresholdMilliseconds, this.TriggeredPerformanceCounters); @@ -144,6 +174,7 @@ namespace StardewModdingAPI.Framework.PerformanceCounter /// <summary>Resets all performance counters in this collection.</summary> public void Reset() { + this.PeakInvocations.Clear(); foreach (var i in this.PerformanceCounters) i.Value.Reset(); } diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs index 49720431..a8e20eda 100644 --- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs +++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs @@ -33,6 +33,11 @@ namespace StardewModdingAPI.Framework.PerformanceCounter /// <summary>Resets all performance counters in all collections.</summary> public void Reset() { + foreach (PerformanceCounterCollection collection in this.PerformanceCounterCollections) + { + collection.Reset(); + } + foreach (var eventPerformanceCounter in this.PerformanceCounterCollections.SelectMany(performanceCounter => performanceCounter.PerformanceCounters)) { |