blob: b2ec4c90ae35d7bbf32708d89fefb62dc3a86a5f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
using System;
using System.Linq;
using Cyotek.Collections.Generic;
namespace StardewModdingAPI.Framework.PerformanceCounter
{
internal class PerformanceCounter
{
/// <summary>The size of the ring buffer.</summary>
private const int MAX_ENTRIES = 16384;
/// <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;
this.Source = source;
this._counter = new CircularBuffer<PerformanceCounterEntry>(PerformanceCounter.MAX_ENTRIES);
}
/// <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)
{
this._counter.Put(entry);
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.ElapsedMilliseconds > this.PeakPerformanceCounterEntry.Value.ElapsedMilliseconds)
this.PeakPerformanceCounterEntry = entry;
}
}
/// <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.ElapsedMilliseconds);
}
/// <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;
if (relativeTo == null)
relativeTo = DateTime.UtcNow;
DateTime start = relativeTo.Value.Subtract(range);
var entries = this._counter.Where(x => (x.EventTime >= start) && (x.EventTime <= relativeTo));
return entries.Average(x => x.ElapsedMilliseconds);
}
}
}
|