diff options
Diffstat (limited to 'src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs')
-rw-r--r-- | src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs | 123 |
1 files changed, 75 insertions, 48 deletions
diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs index 343fddf6..b48efd67 100644 --- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs +++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs @@ -2,23 +2,41 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using StardewModdingAPI.Framework.Utilities; namespace StardewModdingAPI.Framework.PerformanceCounter { internal class PerformanceCounterCollection { - public IDictionary<string, PerformanceCounter> PerformanceCounters { get; } = new Dictionary<string, PerformanceCounter>(); - private DateTime StartDateTime = DateTime.Now; - private long CallCount; - public string Name { get; private set; } - public bool IsImportant { get; set; } - private readonly Stopwatch Stopwatch = new Stopwatch(); - private readonly PerformanceCounterManager PerformanceCounterManager; - public double MonitorThresholdMilliseconds { get; set; } - public bool Monitor { get; set; } + /// <summary>The list of triggered performance counters.</summary> private readonly List<AlertContext> TriggeredPerformanceCounters = new List<AlertContext>(); + /// <summary>The stopwatch used to track the invocation time.</summary> + private readonly Stopwatch InvocationStopwatch = new Stopwatch(); + + /// <summary>The performance counter manager.</summary> + private readonly PerformanceCounterManager PerformanceCounterManager; + + /// <summary>Holds the time to calculate the average calls per second.</summary> + private DateTime CallsPerSecondStart = DateTime.UtcNow; + + /// <summary>The number of invocations of this collection.</summary> + private long CallCount; + + public IDictionary<string, PerformanceCounter> PerformanceCounters { get; } = new Dictionary<string, PerformanceCounter>(); + + /// <summary>The name of this collection.</summary> + public string Name { get; } + + /// <summary>Flag if this collection is important (used for the console summary command).</summary> + public bool IsImportant { get; } + + /// <summary>The alert threshold in milliseconds.</summary> + public double AlertThresholdMilliseconds { get; set; } + + /// <summary>If alerting is enabled or not</summary> + public bool EnableAlerts { get; set; } + + public PerformanceCounterCollection(PerformanceCounterManager performanceCounterManager, string name, bool isImportant) { this.Name = name; @@ -32,111 +50,120 @@ namespace StardewModdingAPI.Framework.PerformanceCounter this.Name = name; } + /// <summary>Tracks a single invocation for a named source.</summary> + /// <param name="source">The name of the source.</param> + /// <param name="entry">The entry.</param> public void Track(string source, PerformanceCounterEntry entry) { if (!this.PerformanceCounters.ContainsKey(source)) - { this.PerformanceCounters.Add(source, new PerformanceCounter(this, source)); - } + this.PerformanceCounters[source].Add(entry); - if (this.Monitor) - { - this.TriggeredPerformanceCounters.Add(new AlertContext(source, entry.Elapsed.TotalMilliseconds)); - } + if (this.EnableAlerts) + this.TriggeredPerformanceCounters.Add(new AlertContext(source, entry.ElapsedMilliseconds)); } + /// <summary>Returns the average execution time for all non-game internal sources.</summary> + /// <returns>The average execution time in milliseconds</returns> public double GetModsAverageExecutionTime() { - return this.PerformanceCounters.Where(p => p.Key != Constants.GamePerformanceCounterName).Sum(p => p.Value.GetAverage()); + return this.PerformanceCounters.Where(p => + p.Key != Constants.GamePerformanceCounterName).Sum(p => p.Value.GetAverage()); } + /// <summary>Returns the overall average execution time.</summary> + /// <returns>The average execution time in milliseconds</returns> public double GetAverageExecutionTime() { return this.PerformanceCounters.Sum(p => p.Value.GetAverage()); } + /// <summary>Returns the average execution time for game-internal sources.</summary> + /// <returns>The average execution time in milliseconds</returns> public double GetGameAverageExecutionTime() { if (this.PerformanceCounters.TryGetValue(Constants.GamePerformanceCounterName, out PerformanceCounter gameExecTime)) - { return gameExecTime.GetAverage(); - } return 0; } + /// <summary>Begins tracking the invocation of this collection.</summary> public void BeginTrackInvocation() { - if (this.Monitor) + if (this.EnableAlerts) { this.TriggeredPerformanceCounters.Clear(); - this.Stopwatch.Reset(); - this.Stopwatch.Start(); + this.InvocationStopwatch.Reset(); + this.InvocationStopwatch.Start(); } this.CallCount++; - } + /// <summary>Ends tracking the invocation of this collection. Also records an alert if alerting is enabled + /// and the invocation time exceeds the threshold.</summary> public void EndTrackInvocation() { - if (!this.Monitor) return; + if (!this.EnableAlerts) return; - this.Stopwatch.Stop(); - if (this.Stopwatch.Elapsed.TotalMilliseconds >= this.MonitorThresholdMilliseconds) - { - this.AddAlert(this.Stopwatch.Elapsed.TotalMilliseconds, - this.MonitorThresholdMilliseconds, this.TriggeredPerformanceCounters); - } + this.InvocationStopwatch.Stop(); + + if (this.InvocationStopwatch.Elapsed.TotalMilliseconds >= this.AlertThresholdMilliseconds) + this.AddAlert(this.InvocationStopwatch.Elapsed.TotalMilliseconds, + this.AlertThresholdMilliseconds, this.TriggeredPerformanceCounters); } - public void AddAlert(double executionTimeMilliseconds, double threshold, List<AlertContext> alerts) + /// <summary>Adds an alert.</summary> + /// <param name="executionTimeMilliseconds">The execution time in milliseconds.</param> + /// <param name="thresholdMilliseconds">The configured threshold.</param> + /// <param name="alerts">The list of alert contexts.</param> + public void AddAlert(double executionTimeMilliseconds, double thresholdMilliseconds, List<AlertContext> alerts) { this.PerformanceCounterManager.AddAlert(new AlertEntry(this, executionTimeMilliseconds, - threshold, alerts)); + thresholdMilliseconds, alerts)); } - public void AddAlert(double executionTimeMilliseconds, double threshold, AlertContext alert) + /// <summary>Adds an alert for a single AlertContext</summary> + /// <param name="executionTimeMilliseconds">The execution time in milliseconds.</param> + /// <param name="thresholdMilliseconds">The configured threshold.</param> + /// <param name="alert">The context</param> + public void AddAlert(double executionTimeMilliseconds, double thresholdMilliseconds, AlertContext alert) { - this.AddAlert(executionTimeMilliseconds, threshold, new List<AlertContext>() {alert}); + this.AddAlert(executionTimeMilliseconds, thresholdMilliseconds, new List<AlertContext>() {alert}); } + /// <summary>Resets the calls per second counter.</summary> public void ResetCallsPerSecond() { this.CallCount = 0; - this.StartDateTime = DateTime.Now; + this.CallsPerSecondStart = DateTime.UtcNow; } + /// <summary>Resets all performance counters in this collection.</summary> public void Reset() { foreach (var i in this.PerformanceCounters) - { i.Value.Reset(); - i.Value.ResetPeak(); - } } + /// <summary>Resets the performance counter for a specific source.</summary> + /// <param name="source">The source name</param> public void ResetSource(string source) { foreach (var i in this.PerformanceCounters) - { if (i.Value.Source.Equals(source, StringComparison.InvariantCultureIgnoreCase)) - { i.Value.Reset(); - i.Value.ResetPeak(); - } - } } + /// <summary>Returns the average calls per second.</summary> + /// <returns>The average calls per second.</returns> public long GetAverageCallsPerSecond() { - long runtimeInSeconds = (long) DateTime.Now.Subtract(this.StartDateTime).TotalSeconds; + long runtimeInSeconds = (long) DateTime.UtcNow.Subtract(this.CallsPerSecondStart).TotalSeconds; - if (runtimeInSeconds == 0) - { - return 0; - } + if (runtimeInSeconds == 0) return 0; return this.CallCount / runtimeInSeconds; } |