From 910b4a2c4361c429b09bd35fa52d51b24cc17bc2 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Jan 2020 19:52:31 -0500 Subject: tweak namespace --- .../PerformanceMonitoring/PerformanceCounter.cs | 125 +++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/SMAPI/Framework/PerformanceMonitoring/PerformanceCounter.cs (limited to 'src/SMAPI/Framework/PerformanceMonitoring/PerformanceCounter.cs') diff --git a/src/SMAPI/Framework/PerformanceMonitoring/PerformanceCounter.cs b/src/SMAPI/Framework/PerformanceMonitoring/PerformanceCounter.cs new file mode 100644 index 00000000..3cf668ee --- /dev/null +++ b/src/SMAPI/Framework/PerformanceMonitoring/PerformanceCounter.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Harmony; + +namespace StardewModdingAPI.Framework.PerformanceMonitoring +{ + /// Tracks metadata about a particular code event. + internal class PerformanceCounter + { + /********* + ** Fields + *********/ + /// The size of the ring buffer. + private readonly int MaxEntries = 16384; + + /// The collection to which this performance counter belongs. + private readonly PerformanceCounterCollection ParentCollection; + + /// The performance counter entries. + private readonly Stack Entries; + + /// The entry with the highest execution time. + private PerformanceCounterEntry? PeakPerformanceCounterEntry; + + + /********* + ** Accessors + *********/ + /// The name of the source. + public string Source { get; } + + /// The alert threshold in milliseconds + public double AlertThresholdMilliseconds { get; set; } + + /// If alerting is enabled or not + public bool EnableAlerts { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The collection to which this performance counter belongs. + /// The name of the source. + public PerformanceCounter(PerformanceCounterCollection parentCollection, string source) + { + this.ParentCollection = parentCollection; + this.Source = source; + this.Entries = new Stack(this.MaxEntries); + } + + /// Add a performance counter entry to the list, update monitoring, and raise alerts if needed. + /// The entry to add. + public void Add(PerformanceCounterEntry entry) + { + // add entry + if (this.Entries.Count > this.MaxEntries) + this.Entries.Pop(); + this.Entries.Add(entry); + + // update metrics + if (this.PeakPerformanceCounterEntry == null || entry.ElapsedMilliseconds > this.PeakPerformanceCounterEntry.Value.ElapsedMilliseconds) + this.PeakPerformanceCounterEntry = entry; + + // raise alert + if (this.EnableAlerts && entry.ElapsedMilliseconds > this.AlertThresholdMilliseconds) + this.ParentCollection.AddAlert(entry.ElapsedMilliseconds, this.AlertThresholdMilliseconds, new AlertContext(this.Source, entry.ElapsedMilliseconds)); + } + + /// Clear all performance counter entries and monitoring. + public void Reset() + { + this.Entries.Clear(); + this.PeakPerformanceCounterEntry = null; + } + + /// Get the peak entry. + public PerformanceCounterEntry? GetPeak() + { + return this.PeakPerformanceCounterEntry; + } + + /// Get the entry with the highest execution time. + /// The time range to search. + /// The end time for the , or null for the current time. + public PerformanceCounterEntry? GetPeak(TimeSpan range, DateTime? endTime = null) + { + endTime ??= DateTime.UtcNow; + DateTime startTime = endTime.Value.Subtract(range); + + return this.Entries + .Where(entry => entry.EventTime >= startTime && entry.EventTime <= endTime) + .OrderByDescending(x => x.ElapsedMilliseconds) + .FirstOrDefault(); + } + + /// Get the last entry added to the list. + public PerformanceCounterEntry? GetLastEntry() + { + if (this.Entries.Count == 0) + return null; + + return this.Entries.Peek(); + } + + /// Get the average over a given time span. + /// The time range to search. + /// The end time for the , or null for the current time. + public double GetAverage(TimeSpan range, DateTime? endTime = null) + { + endTime ??= DateTime.UtcNow; + DateTime startTime = endTime.Value.Subtract(range); + + double[] entries = this.Entries + .Where(entry => entry.EventTime >= startTime && entry.EventTime <= endTime) + .Select(p => p.ElapsedMilliseconds) + .ToArray(); + + return entries.Length > 0 + ? entries.Average() + : 0; + } + } +} -- cgit