summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorDrachenkaetzchen <felicia@drachenkatze.org>2020-01-15 16:01:35 +0100
committerDrachenkaetzchen <felicia@drachenkatze.org>2020-01-15 16:01:35 +0100
commit694cca4b21878850ba6131105a0c560fdfbc5f10 (patch)
tree016aadbd247f72e352fc341f3ce944980dc70c90 /src/SMAPI
parent280dc911839f8996cddd9804f3f545cc38d20243 (diff)
downloadSMAPI-694cca4b21878850ba6131105a0c560fdfbc5f10.tar.gz
SMAPI-694cca4b21878850ba6131105a0c560fdfbc5f10.tar.bz2
SMAPI-694cca4b21878850ba6131105a0c560fdfbc5f10.zip
Added documentation for all performance counter methods and members. Refactored the naming of several members and methods to reflect their actual intention.
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/AlertContext.cs18
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/AlertEntry.cs25
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/EventPerformanceCounterCollection.cs5
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/IPerformanceCounterEvent.cs15
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs99
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/PerformanceCounterCollection.cs123
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/PerformanceCounterEntry.cs10
-rw-r--r--src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs157
-rw-r--r--src/SMAPI/Framework/SCore.cs2
-rw-r--r--src/SMAPI/Framework/SGame.cs2
10 files changed, 261 insertions, 195 deletions
diff --git a/src/SMAPI/Framework/PerformanceCounter/AlertContext.cs b/src/SMAPI/Framework/PerformanceCounter/AlertContext.cs
index c4a57a49..63f0a5ed 100644
--- a/src/SMAPI/Framework/PerformanceCounter/AlertContext.cs
+++ b/src/SMAPI/Framework/PerformanceCounter/AlertContext.cs
@@ -1,14 +1,26 @@
namespace StardewModdingAPI.Framework.PerformanceCounter
{
- public struct AlertContext
+ /// <summary>The context for an alert.</summary>
+ internal struct AlertContext
{
- public string Source;
- public double Elapsed;
+ /// <summary>The source which triggered the alert.</summary>
+ public readonly string Source;
+ /// <summary>The elapsed milliseconds.</summary>
+ public readonly double Elapsed;
+
+ /// <summary>Creates a new alert context.</summary>
+ /// <param name="source">The source which triggered the alert.</param>
+ /// <param name="elapsed">The elapsed milliseconds.</param>
public AlertContext(string source, double elapsed)
{
this.Source = source;
this.Elapsed = elapsed;
}
+
+ public override string ToString()
+ {
+ return $"{this.Source}: {this.Elapsed:F2}ms";
+ }
}
}
diff --git a/src/SMAPI/Framework/PerformanceCounter/AlertEntry.cs b/src/SMAPI/Framework/PerformanceCounter/AlertEntry.cs
index 284af1ce..b87d8642 100644
--- a/src/SMAPI/Framework/PerformanceCounter/AlertEntry.cs
+++ b/src/SMAPI/Framework/PerformanceCounter/AlertEntry.cs
@@ -2,18 +2,31 @@ using System.Collections.Generic;
namespace StardewModdingAPI.Framework.PerformanceCounter
{
+ /// <summary>A single alert entry.</summary>
internal struct AlertEntry
{
- public PerformanceCounterCollection Collection;
- public double ExecutionTimeMilliseconds;
- public double Threshold;
- public List<AlertContext> Context;
+ /// <summary>The collection in which the alert occurred.</summary>
+ public readonly PerformanceCounterCollection Collection;
- public AlertEntry(PerformanceCounterCollection collection, double executionTimeMilliseconds, double threshold, List<AlertContext> context)
+ /// <summary>The actual execution time in milliseconds.</summary>
+ public readonly double ExecutionTimeMilliseconds;
+
+ /// <summary>The configured alert threshold. </summary>
+ public readonly double ThresholdMilliseconds;
+
+ /// <summary>The context list, which records all sources involved in exceeding the threshold.</summary>
+ public readonly List<AlertContext> Context;
+
+ /// <summary>Creates a new alert entry.</summary>
+ /// <param name="collection">The source collection in which the alert occurred.</param>
+ /// <param name="executionTimeMilliseconds">The actual execution time in milliseconds.</param>
+ /// <param name="thresholdMilliseconds">The configured threshold in milliseconds.</param>
+ /// <param name="context">A list of AlertContext to record which sources were involved</param>
+ public AlertEntry(PerformanceCounterCollection collection, double executionTimeMilliseconds, double thresholdMilliseconds, List<AlertContext> context)
{
this.Collection = collection;
this.ExecutionTimeMilliseconds = executionTimeMilliseconds;
- this.Threshold = threshold;
+ this.ThresholdMilliseconds = thresholdMilliseconds;
this.Context = context;
}
}
diff --git a/src/SMAPI/Framework/PerformanceCounter/EventPerformanceCounterCollection.cs b/src/SMAPI/Framework/PerformanceCounter/EventPerformanceCounterCollection.cs
index 1aec28f3..4690c512 100644
--- a/src/SMAPI/Framework/PerformanceCounter/EventPerformanceCounterCollection.cs
+++ b/src/SMAPI/Framework/PerformanceCounter/EventPerformanceCounterCollection.cs
@@ -2,8 +2,13 @@ using StardewModdingAPI.Framework.Events;
namespace StardewModdingAPI.Framework.PerformanceCounter
{
+ /// <summary>Represents a performance counter collection specific to game events.</summary>
internal class EventPerformanceCounterCollection: PerformanceCounterCollection
{
+ /// <summary>Creates a new event performance counter collection.</summary>
+ /// <param name="manager">The performance counter manager.</param>
+ /// <param name="event">The ManagedEvent.</param>
+ /// <param name="isImportant">If the event is flagged as important.</param>
public EventPerformanceCounterCollection(PerformanceCounterManager manager, IManagedEvent @event, bool isImportant) : base(manager, @event.GetName(), isImportant)
{
}
diff --git a/src/SMAPI/Framework/PerformanceCounter/IPerformanceCounterEvent.cs b/src/SMAPI/Framework/PerformanceCounter/IPerformanceCounterEvent.cs
deleted file mode 100644
index 1bcf4fa0..00000000
--- a/src/SMAPI/Framework/PerformanceCounter/IPerformanceCounterEvent.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace StardewModdingAPI.Framework.Utilities
-{
- public interface IPerformanceCounterEvent
- {
- string GetEventName();
- long GetAverageCallsPerSecond();
-
- double GetGameAverageExecutionTime();
- double GetModsAverageExecutionTime();
- double GetAverageExecutionTime();
- }
-}
diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs
index 3dbc693a..b2ec4c90 100644
--- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs
+++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounter.cs
@@ -1,26 +1,32 @@
using System;
-using System.Diagnostics;
using System.Linq;
using Cyotek.Collections.Generic;
-using StardewModdingAPI.Framework.Utilities;
namespace StardewModdingAPI.Framework.PerformanceCounter
{
internal class PerformanceCounter
{
+ /// <summary>The size of the ring buffer.</summary>
private const int MAX_ENTRIES = 16384;
- public string Source { get; }
- public static Stopwatch Stopwatch = new Stopwatch();
- public static long TotalNumEventsLogged;
- public double MonitorThresholdMilliseconds { get; set; }
- public bool Monitor { get; set; }
+ /// <summary>The collection to which this performance counter belongs.</summary>
private readonly PerformanceCounterCollection ParentCollection;
+ /// <summary>The circular buffer which stores all performance counter entries</summary>
private readonly CircularBuffer<PerformanceCounterEntry> _counter;
+ /// <summary>The peak execution time</summary>
private PerformanceCounterEntry? PeakPerformanceCounterEntry;
+ /// <summary>The name of the source.</summary>
+ public string Source { 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 PerformanceCounter(PerformanceCounterCollection parentCollection, string source)
{
this.ParentCollection = parentCollection;
@@ -28,90 +34,87 @@ namespace StardewModdingAPI.Framework.PerformanceCounter
this._counter = new CircularBuffer<PerformanceCounterEntry>(PerformanceCounter.MAX_ENTRIES);
}
- public void Reset()
- {
- this._counter.Clear();
- this.PeakPerformanceCounterEntry = null;
- }
-
- public int GetAverageCallsPerSecond()
- {
- var x = this._counter.GroupBy(
- p =>
- (int) p.EventTime.Subtract(
- new DateTime(1970, 1, 1)
- ).TotalSeconds);
-
- return x.Last().Count();
- }
-
+ /// <summary>Adds a new performance counter entry to the list. Updates the peak entry and adds an alert if
+ /// monitoring is enabled and the execution time exceeds the threshold.</summary>
+ /// <param name="entry">The entry to add.</param>
public void Add(PerformanceCounterEntry entry)
{
- PerformanceCounter.Stopwatch.Start();
this._counter.Put(entry);
- if (this.Monitor && entry.Elapsed.TotalMilliseconds > this.MonitorThresholdMilliseconds)
- {
- this.ParentCollection.AddAlert(entry.Elapsed.TotalMilliseconds, this.MonitorThresholdMilliseconds, new AlertContext(this.Source, entry.Elapsed.TotalMilliseconds));
- }
+ if (this.EnableAlerts && entry.ElapsedMilliseconds > this.AlertThresholdMilliseconds)
+ this.ParentCollection.AddAlert(entry.ElapsedMilliseconds, this.AlertThresholdMilliseconds,
+ new AlertContext(this.Source, entry.ElapsedMilliseconds));
if (this.PeakPerformanceCounterEntry == null)
- {
this.PeakPerformanceCounterEntry = entry;
- }
else
{
- if (entry.Elapsed.TotalMilliseconds > this.PeakPerformanceCounterEntry.Value.Elapsed.TotalMilliseconds)
- {
+ if (entry.ElapsedMilliseconds > this.PeakPerformanceCounterEntry.Value.ElapsedMilliseconds)
this.PeakPerformanceCounterEntry = entry;
- }
}
+ }
- PerformanceCounter.Stopwatch.Stop();
- PerformanceCounter.TotalNumEventsLogged++;
+ /// <summary>Clears all performance counter entries and resets the peak entry.</summary>
+ public void Reset()
+ {
+ this._counter.Clear();
+ this.PeakPerformanceCounterEntry = null;
}
+ /// <summary>Returns the peak entry.</summary>
+ /// <returns>The peak entry.</returns>
public PerformanceCounterEntry? GetPeak()
{
return this.PeakPerformanceCounterEntry;
}
+ /// <summary>Resets the peak entry.</summary>
public void ResetPeak()
{
this.PeakPerformanceCounterEntry = null;
}
+ /// <summary>Returns the last entry added to the list.</summary>
+ /// <returns>The last entry</returns>
public PerformanceCounterEntry? GetLastEntry()
{
if (this._counter.IsEmpty)
- {
return null;
- }
+
return this._counter.PeekLast();
}
+ /// <summary>Returns the average execution time of all entries.</summary>
+ /// <returns>The average execution time in milliseconds.</returns>
public double GetAverage()
{
if (this._counter.IsEmpty)
- {
return 0;
- }
- return this._counter.Average(p => p.Elapsed.TotalMilliseconds);
+ return this._counter.Average(p => p.ElapsedMilliseconds);
}
- public double GetAverage(TimeSpan range)
+ /// <summary>Returns the average over a given time span.</summary>
+ /// <param name="range">The time range to retrieve.</param>
+ /// <param name="relativeTo">The DateTime from which to start the average. Defaults to DateTime.UtcNow if null</param>
+ /// <returns>The average execution time in milliseconds.</returns>
+ /// <remarks>
+ /// The relativeTo parameter specifies from which point in time the range is subtracted. Example:
+ /// If DateTime is set to 60 seconds ago, and the range is set to 60 seconds, the method would return
+ /// the average between all entries between 120s ago and 60s ago.
+ /// </remarks>
+ public double GetAverage(TimeSpan range, DateTime? relativeTo = null)
{
if (this._counter.IsEmpty)
- {
return 0;
- }
- var lastTime = this._counter.Max(x => x.EventTime);
- var start = lastTime.Subtract(range);
+ if (relativeTo == null)
+ relativeTo = DateTime.UtcNow;
+
+ DateTime start = relativeTo.Value.Subtract(range);
- var entries = this._counter.Where(x => (x.EventTime >= start) && (x.EventTime <= lastTime));
- return entries.Average(x => x.Elapsed.TotalMilliseconds);
+ var entries = this._counter.Where(x => (x.EventTime >= start) && (x.EventTime <= relativeTo));
+ return entries.Average(x => x.ElapsedMilliseconds);
}
}
}
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;
}
diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterEntry.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterEntry.cs
index 8e156a32..a50fce7d 100644
--- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterEntry.cs
+++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterEntry.cs
@@ -1,10 +1,14 @@
using System;
-namespace StardewModdingAPI.Framework.Utilities
+namespace StardewModdingAPI.Framework.PerformanceCounter
{
- public struct PerformanceCounterEntry
+ /// <summary>A single performance counter entry. Records the DateTime of the event and the elapsed millisecond.</summary>
+ internal struct PerformanceCounterEntry
{
+ /// <summary>The DateTime when the entry occured.</summary>
public DateTime EventTime;
- public TimeSpan Elapsed;
+
+ /// <summary>The elapsed milliseconds</summary>
+ public double ElapsedMilliseconds;
}
}
diff --git a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs
index 9e77e2fa..d8f1f172 100644
--- a/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs
+++ b/src/SMAPI/Framework/PerformanceCounter/PerformanceCounterManager.cs
@@ -4,72 +4,62 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using StardewModdingAPI.Framework.Events;
-using StardewModdingAPI.Framework.Utilities;
namespace StardewModdingAPI.Framework.PerformanceCounter
{
internal class PerformanceCounterManager
{
public HashSet<PerformanceCounterCollection> PerformanceCounterCollections = new HashSet<PerformanceCounterCollection>();
- public List<AlertEntry> Alerts = new List<AlertEntry>();
+
+ /// <summary>The recorded alerts.</summary>
+ private readonly List<AlertEntry> Alerts = new List<AlertEntry>();
+
+ /// <summary>The monitor for output logging.</summary>
private readonly IMonitor Monitor;
- private readonly Stopwatch Stopwatch = new Stopwatch();
+ /// <summary>The invocation stopwatch.</summary>
+ private readonly Stopwatch InvocationStopwatch = new Stopwatch();
+
+ /// <summary>Constructs a performance counter manager.</summary>
+ /// <param name="monitor">The monitor for output logging.</param>
public PerformanceCounterManager(IMonitor monitor)
{
this.Monitor = monitor;
}
+ /// <summary>Resets all performance counters in all collections.</summary>
public void Reset()
{
- foreach (var performanceCounter in this.PerformanceCounterCollections)
- {
- foreach (var eventPerformanceCounter in performanceCounter.PerformanceCounters)
- {
- eventPerformanceCounter.Value.Reset();
- }
- }
- }
-
- /// <summary>Print any queued messages.</summary>
- public void PrintQueued()
- {
- if (this.Alerts.Count == 0)
+ foreach (var eventPerformanceCounter in
+ this.PerformanceCounterCollections.SelectMany(performanceCounter => performanceCounter.PerformanceCounters))
{
- return;
+ eventPerformanceCounter.Value.Reset();
}
- StringBuilder sb = new StringBuilder();
-
- foreach (var alert in this.Alerts)
- {
- sb.AppendLine($"{alert.Collection.Name} took {alert.ExecutionTimeMilliseconds:F2}ms (exceeded threshold of {alert.Threshold:F2}ms)");
-
- foreach (var context in alert.Context)
- {
- sb.AppendLine($"{context.Source}: {context.Elapsed:F2}ms");
- }
- }
-
- this.Alerts.Clear();
-
- this.Monitor.Log(sb.ToString(), LogLevel.Error);
}
+ /// <summary>Begins tracking the invocation for a collection.</summary>
+ /// <param name="collectionName">The collection name</param>
public void BeginTrackInvocation(string collectionName)
{
this.GetOrCreateCollectionByName(collectionName).BeginTrackInvocation();
}
+ /// <summary>Ends tracking the invocation for a collection.</summary>
+ /// <param name="collectionName"></param>
public void EndTrackInvocation(string collectionName)
{
this.GetOrCreateCollectionByName(collectionName).EndTrackInvocation();
}
- public void Track(string collectionName, string modName, Action action)
+ /// <summary>Tracks a single performance counter invocation in a specific collection.</summary>
+ /// <param name="collectionName">The name of the collection.</param>
+ /// <param name="sourceName">The name of the source.</param>
+ /// <param name="action">The action to execute and track invocation time for.</param>
+ public void Track(string collectionName, string sourceName, Action action)
{
DateTime eventTime = DateTime.UtcNow;
- this.Stopwatch.Reset();
- this.Stopwatch.Start();
+ this.InvocationStopwatch.Reset();
+ this.InvocationStopwatch.Start();
try
{
@@ -77,75 +67,102 @@ namespace StardewModdingAPI.Framework.PerformanceCounter
}
finally
{
- this.Stopwatch.Stop();
+ this.InvocationStopwatch.Stop();
- this.GetOrCreateCollectionByName(collectionName).Track(modName, new PerformanceCounterEntry
+ this.GetOrCreateCollectionByName(collectionName).Track(sourceName, new PerformanceCounterEntry
{
EventTime = eventTime,
- Elapsed = this.Stopwatch.Elapsed
+ ElapsedMilliseconds = this.InvocationStopwatch.Elapsed.TotalMilliseconds
});
}
}
- public PerformanceCounterCollection GetCollectionByName(string name)
+ /// <summary>Gets a collection by name.</summary>
+ /// <param name="name">The name of the collection.</param>
+ /// <returns>The collection or null if none was found.</returns>
+ private PerformanceCounterCollection GetCollectionByName(string name)
{
return this.PerformanceCounterCollections.FirstOrDefault(collection => collection.Name == name);
}
- public PerformanceCounterCollection GetOrCreateCollectionByName(string name)
+ /// <summary>Gets a collection by name and creates it if it doesn't exist.</summary>
+ /// <param name="name">The name of the collection.</param>
+ /// <returns>The collection.</returns>
+ private PerformanceCounterCollection GetOrCreateCollectionByName(string name)
{
PerformanceCounterCollection collection = this.GetCollectionByName(name);
- if (collection == null)
- {
- collection = new PerformanceCounterCollection(this, name);
- this.PerformanceCounterCollections.Add(collection);
- }
+ if (collection != null) return collection;
+
+ collection = new PerformanceCounterCollection(this, name);
+ this.PerformanceCounterCollections.Add(collection);
return collection;
}
- public void ResetCategory(string name)
+ /// <summary>Resets the performance counters for a specific collection.</summary>
+ /// <param name="name">The collection name.</param>
+ public void ResetCollection(string name)
{
- foreach (var performanceCounterCollection in this.PerformanceCounterCollections)
+ foreach (PerformanceCounterCollection performanceCounterCollection in
+ this.PerformanceCounterCollections.Where(performanceCounterCollection =>
+ performanceCounterCollection.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)))
{
- if (performanceCounterCollection.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
- {
- performanceCounterCollection.ResetCallsPerSecond();
- performanceCounterCollection.Reset();
- }
+ performanceCounterCollection.ResetCallsPerSecond();
+ performanceCounterCollection.Reset();
}
}
+ /// <summary>Resets performance counters for a specific source.</summary>
+ /// <param name="name">The name of the source.</param>
public void ResetSource(string name)
{
- foreach (var performanceCounterCollection in this.PerformanceCounterCollections)
- {
+ foreach (PerformanceCounterCollection performanceCounterCollection in this.PerformanceCounterCollections)
performanceCounterCollection.ResetSource(name);
- }
}
+ /// <summary>Print any queued alerts.</summary>
+ public void PrintQueuedAlerts()
+ {
+ if (this.Alerts.Count == 0) return;
+
+ StringBuilder sb = new StringBuilder();
+
+ foreach (AlertEntry alert in this.Alerts)
+ {
+ sb.AppendLine($"{alert.Collection.Name} took {alert.ExecutionTimeMilliseconds:F2}ms (exceeded threshold of {alert.ThresholdMilliseconds:F2}ms)");
+ foreach (AlertContext context in alert.Context.OrderByDescending(p => p.Elapsed))
+ sb.AppendLine(context.ToString());
+ }
+
+ this.Alerts.Clear();
+ this.Monitor.Log(sb.ToString(), LogLevel.Error);
+ }
+
+ /// <summary>Adds an alert to the queue.</summary>
+ /// <param name="entry">The alert to add.</param>
public void AddAlert(AlertEntry entry)
{
this.Alerts.Add(entry);
}
- public void InitializePerformanceCounterEvents(EventManager eventManager)
+ /// <summary>Initialized the default performance counter collections.</summary>
+ /// <param name="eventManager">The event manager.</param>
+ public void InitializePerformanceCounterCollections(EventManager eventManager)
{
this.PerformanceCounterCollections = new HashSet<PerformanceCounterCollection>()
{
new EventPerformanceCounterCollection(this, eventManager.MenuChanged, false),
-
// Rendering Events
- new EventPerformanceCounterCollection(this, eventManager.Rendering, true),
+ new EventPerformanceCounterCollection(this, eventManager.Rendering, false),
new EventPerformanceCounterCollection(this, eventManager.Rendered, true),
- new EventPerformanceCounterCollection(this, eventManager.RenderingWorld, true),
+ new EventPerformanceCounterCollection(this, eventManager.RenderingWorld, false),
new EventPerformanceCounterCollection(this, eventManager.RenderedWorld, true),
- new EventPerformanceCounterCollection(this, eventManager.RenderingActiveMenu, true),
+ new EventPerformanceCounterCollection(this, eventManager.RenderingActiveMenu, false),
new EventPerformanceCounterCollection(this, eventManager.RenderedActiveMenu, true),
- new EventPerformanceCounterCollection(this, eventManager.RenderingHud, true),
+ new EventPerformanceCounterCollection(this, eventManager.RenderingHud, false),
new EventPerformanceCounterCollection(this, eventManager.RenderedHud, true),
new EventPerformanceCounterCollection(this, eventManager.WindowResized, false),
@@ -172,19 +189,19 @@ namespace StardewModdingAPI.Framework.PerformanceCounter
new EventPerformanceCounterCollection(this, eventManager.CursorMoved, true),
new EventPerformanceCounterCollection(this, eventManager.MouseWheelScrolled, true),
- new EventPerformanceCounterCollection(this, eventManager.PeerContextReceived, true),
- new EventPerformanceCounterCollection(this, eventManager.ModMessageReceived, true),
- new EventPerformanceCounterCollection(this, eventManager.PeerDisconnected, true),
+ new EventPerformanceCounterCollection(this, eventManager.PeerContextReceived, false),
+ new EventPerformanceCounterCollection(this, eventManager.ModMessageReceived, false),
+ new EventPerformanceCounterCollection(this, eventManager.PeerDisconnected, false),
new EventPerformanceCounterCollection(this, eventManager.InventoryChanged, true),
- new EventPerformanceCounterCollection(this, eventManager.LevelChanged, true),
- new EventPerformanceCounterCollection(this, eventManager.Warped, true),
+ new EventPerformanceCounterCollection(this, eventManager.LevelChanged, false),
+ new EventPerformanceCounterCollection(this, eventManager.Warped, false),
- new EventPerformanceCounterCollection(this, eventManager.LocationListChanged, true),
- new EventPerformanceCounterCollection(this, eventManager.BuildingListChanged, true),
- new EventPerformanceCounterCollection(this, eventManager.LocationListChanged, true),
+ new EventPerformanceCounterCollection(this, eventManager.LocationListChanged, false),
+ new EventPerformanceCounterCollection(this, eventManager.BuildingListChanged, false),
+ new EventPerformanceCounterCollection(this, eventManager.LocationListChanged, false),
new EventPerformanceCounterCollection(this, eventManager.DebrisListChanged, true),
new EventPerformanceCounterCollection(this, eventManager.LargeTerrainFeatureListChanged, true),
- new EventPerformanceCounterCollection(this, eventManager.NpcListChanged, true),
+ new EventPerformanceCounterCollection(this, eventManager.NpcListChanged, false),
new EventPerformanceCounterCollection(this, eventManager.ObjectListChanged, true),
new EventPerformanceCounterCollection(this, eventManager.ChestInventoryChanged, true),
new EventPerformanceCounterCollection(this, eventManager.TerrainFeatureListChanged, true),
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 5b0c6691..af7513e3 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -169,7 +169,7 @@ namespace StardewModdingAPI.Framework
SCore.PerformanceCounterManager = new PerformanceCounterManager(this.Monitor);
this.EventManager = new EventManager(this.Monitor, this.ModRegistry, SCore.PerformanceCounterManager);
- SCore.PerformanceCounterManager.InitializePerformanceCounterEvents(this.EventManager);
+ SCore.PerformanceCounterManager.InitializePerformanceCounterCollections(this.EventManager);
SCore.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry);
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 8aba9b57..266e2e6f 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -312,7 +312,7 @@ namespace StardewModdingAPI.Framework
try
{
this.DeprecationManager.PrintQueued();
- this.PerformanceCounterManager.PrintQueued();
+ this.PerformanceCounterManager.PrintQueuedAlerts();
/*********
** First-tick initialization