Added peak execution time over the last 60 seconds
This commit is contained in:
parent
238b5db4f7
commit
84973ce572
|
@ -118,17 +118,20 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Other
|
|||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
TimeSpan peakSpan = TimeSpan.FromSeconds(60);
|
||||
|
||||
sb.AppendLine("Summary:");
|
||||
sb.AppendLine(this.GetTableString(
|
||||
data: data,
|
||||
header: new[] {"Collection", "Avg Calls/s", "Avg Execution Time (Game)", "Avg Execution Time (Mods)", "Avg Execution Time (Game+Mods)"},
|
||||
header: new[] {"Collection", "Avg Calls/s", "Avg Exec Time (Game)", "Avg Exec Time (Mods)", "Avg Exec Time (Game+Mods)", "Peak Exec Time (60s)"},
|
||||
getRow: item => new[]
|
||||
{
|
||||
item.Name,
|
||||
item.GetAverageCallsPerSecond().ToString(),
|
||||
this.FormatMilliseconds(item.GetGameAverageExecutionTime(), threshold),
|
||||
this.FormatMilliseconds(item.GetModsAverageExecutionTime(), threshold),
|
||||
this.FormatMilliseconds(item.GetAverageExecutionTime(), threshold)
|
||||
this.FormatMilliseconds(item.GetAverageExecutionTime(), threshold),
|
||||
this.FormatMilliseconds(item.GetPeakExecutionTime(peakSpan), threshold)
|
||||
},
|
||||
true
|
||||
));
|
||||
|
@ -459,13 +462,14 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Other
|
|||
{
|
||||
sb.AppendLine(this.GetTableString(
|
||||
data: data,
|
||||
header: new[] {"Mod", $"Avg Execution Time (last {(int) averageInterval.TotalSeconds}s)", "Last Execution Time", "Peak Execution Time"},
|
||||
header: new[] {"Mod", $"Avg Exec Time (last {(int) averageInterval.TotalSeconds}s)", "Last Exec Time", "Peak Exec Time", $"Peak Exec Time (last {(int) averageInterval.TotalSeconds}s)"},
|
||||
getRow: item => new[]
|
||||
{
|
||||
item.Key,
|
||||
this.FormatMilliseconds(item.Value.GetAverage(averageInterval), thresholdMilliseconds),
|
||||
this.FormatMilliseconds(item.Value.GetLastEntry()?.ElapsedMilliseconds),
|
||||
this.FormatMilliseconds(item.Value.GetPeak()?.ElapsedMilliseconds)
|
||||
this.FormatMilliseconds(item.Value.GetPeak()?.ElapsedMilliseconds),
|
||||
this.FormatMilliseconds(item.Value.GetPeak(averageInterval)?.ElapsedMilliseconds)
|
||||
},
|
||||
true
|
||||
));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue