From 84973ce5727ad20fe8b8ba4f89e59c8b754f799e Mon Sep 17 00:00:00 2001 From: Drachenkaetzchen Date: Wed, 15 Jan 2020 19:08:50 +0100 Subject: Added peak execution time over the last 60 seconds --- .../PerformanceCounterCollection.cs | 47 ++++++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs') 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 { + /// The size of the ring buffer. + private const int MAX_ENTRIES = 16384; + /// The list of triggered performance counters. private readonly List TriggeredPerformanceCounters = new List(); @@ -22,6 +26,10 @@ namespace StardewModdingAPI.Framework.PerformanceCounter /// The number of invocations of this collection. private long CallCount; + /// The circular buffer which stores all peak invocations + private readonly CircularBuffer PeakInvocations; + + /// The associated performance counters. public IDictionary PerformanceCounters { get; } = new Dictionary(); /// The name of this collection. @@ -39,6 +47,7 @@ namespace StardewModdingAPI.Framework.PerformanceCounter public PerformanceCounterCollection(PerformanceCounterManager performanceCounterManager, string name, bool isImportant) { + this.PeakInvocations = new CircularBuffer(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(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; + } + /// Begins tracking the invocation of this collection. 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. 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 /// Resets all performance counters in this collection. public void Reset() { + this.PeakInvocations.Clear(); foreach (var i in this.PerformanceCounters) i.Value.Reset(); } -- cgit