This repository has been archived by the owner on Jul 17, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Profiler.cs
144 lines (116 loc) · 3.74 KB
/
Profiler.cs
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace HatlessEngine
{
/// <summary>
/// Profiling works on a current state (changes every second), while retrieving data works on the most recently finished state.
/// </summary>
public static class Profiler
{
private static Stopwatch _stopwatch = new Stopwatch();
private static long _lastSecond;
private static List<ProfilerItem> _previousState = new List<ProfilerItem>();
private static List<ProfilerItem> _currentState = new List<ProfilerItem>();
private static ProfilerItem _currentlyMeasuringItem;
static Profiler()
{
_stopwatch.Start();
}
public static void Start(string itemId)
{
EnsureUpdatedState();
//obtain a list of items to check in/add to
List<ProfilerItem> lookupList = _currentlyMeasuringItem == null ? _currentState : _currentlyMeasuringItem.Children;
//get an existing item
ProfilerItem item = lookupList.Find(lookupItem => lookupItem.Id == itemId);
//the collection does not yet contain this item -> create it
if (item == null)
{
//create a new item
item = new ProfilerItem(itemId, _stopwatch, _currentlyMeasuringItem);
//add reference to newly created child to parent (or state)
if (_currentlyMeasuringItem == null)
_currentState.Add(item);
else
_currentlyMeasuringItem.Children.Add(item);
}
//start measurement on item
item.Start();
//set is at last started measurement
_currentlyMeasuringItem = item;
}
/// <summary>
/// Stops the most recently initiated measurement.
/// </summary>
public static void Stop()
{
EnsureUpdatedState();
//stop the currently measuring item and ascend it (or set to null if top)
if (_currentlyMeasuringItem != null)
{
_currentlyMeasuringItem.Stop();
_currentlyMeasuringItem = _currentlyMeasuringItem.Parent;
}
}
/// <summary>
/// Will try to get an item from the most recently completed state (searches the state recursively).
/// </summary>
public static ProfilerItem GetItem(string itemId)
{
ProfilerItem directMatch = _previousState.Find(item => item.Id == itemId);
if (directMatch != null)
return directMatch;
//search recursively
foreach (ProfilerItem item in _previousState)
{
ProfilerItem indirectMatch = item.GetChildById(itemId, true);
if (indirectMatch != null)
return indirectMatch;
}
return null;
}
/// <summary>
/// Returns a (sort of) formatted string that shows info about the last completed state.
/// </summary>
public static string GetStateString()
{
//order by total duration (base profileritems)
_previousState = _previousState.OrderByDescending(item => item.GetTotalDuration()).ToList();
//start off with the previousstate profilers and the children will be rendered accordingly
return GetItemsString(_previousState, 0);
}
/// <summary>
/// Draw a part of the state string
/// </summary>
private static string GetItemsString(List<ProfilerItem> items, int depth)
{
string result = "";
items.ForEach(item =>
{
//indent by depth
for (int i = 0; i < depth; i++)
result += "\t";
result += item + "\n";
//draw children below this one with a depth level down
result += GetItemsString(item.Children, depth + 1);
});
return result;
}
private static void EnsureUpdatedState()
{
long elapsedSeconds = _stopwatch.ElapsedTicks / Stopwatch.Frequency;
if (elapsedSeconds <= _lastSecond)
return;
//do that update thing
UpdateState();
_lastSecond = elapsedSeconds;
}
private static void UpdateState()
{
//move currentstate to previousstate, and create a new state with new items
_previousState = _currentState;
_currentState = new List<ProfilerItem>();
}
}
}