blob: 6058ddbd81907f53230330590fe450625001bc9b (
plain) (
blame)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
using System;
using System.Collections.Generic;
namespace Ryujinx.Profiler
{
public struct Timestamp
{
public long BeginTime;
public long EndTime;
}
public class TimingInfo
{
// Timestamps
public long TotalTime { get; set; }
public long Instant { get; set; }
// Measurement counts
public int Count { get; set; }
public int InstantCount { get; set; }
// Work out average
public long AverageTime => (Count == 0) ? -1 : TotalTime / Count;
// Intentionally not locked as it's only a get count
public bool IsActive => _timestamps.Count > 0;
public long BeginTime
{
get
{
lock (_timestampLock)
{
if (_depth > 0)
{
return _currentTimestamp.BeginTime;
}
return -1;
}
}
}
// Timestamp collection
private List<Timestamp> _timestamps;
private readonly object _timestampLock = new object();
private readonly object _timestampListLock = new object();
private Timestamp _currentTimestamp;
// Depth of current timer,
// each begin call increments and each end call decrements
private int _depth;
public TimingInfo()
{
_timestamps = new List<Timestamp>();
_depth = 0;
}
public void Begin(long beginTime)
{
lock (_timestampLock)
{
// Finish current timestamp if already running
if (_depth > 0)
{
EndUnsafe(beginTime);
}
BeginUnsafe(beginTime);
_depth++;
}
}
private void BeginUnsafe(long beginTime)
{
_currentTimestamp.BeginTime = beginTime;
_currentTimestamp.EndTime = -1;
}
public void End(long endTime)
{
lock (_timestampLock)
{
_depth--;
if (_depth < 0)
{
throw new Exception("Timing info end called without corresponding begin");
}
EndUnsafe(endTime);
// Still have others using this timing info so recreate start for them
if (_depth > 0)
{
BeginUnsafe(endTime);
}
}
}
private void EndUnsafe(long endTime)
{
_currentTimestamp.EndTime = endTime;
lock (_timestampListLock)
{
_timestamps.Add(_currentTimestamp);
}
long delta = _currentTimestamp.EndTime - _currentTimestamp.BeginTime;
TotalTime += delta;
Instant += delta;
Count++;
InstantCount++;
}
// Remove any timestamps before given timestamp to free memory
public void Cleanup(long before, long preserveStart, long preserveEnd)
{
lock (_timestampListLock)
{
int toRemove = 0;
int toPreserveStart = 0;
int toPreserveLen = 0;
for (int i = 0; i < _timestamps.Count; i++)
{
if (_timestamps[i].EndTime < preserveStart)
{
toPreserveStart++;
InstantCount--;
Instant -= _timestamps[i].EndTime - _timestamps[i].BeginTime;
}
else if (_timestamps[i].EndTime < preserveEnd)
{
toPreserveLen++;
}
else if (_timestamps[i].EndTime < before)
{
toRemove++;
InstantCount--;
Instant -= _timestamps[i].EndTime - _timestamps[i].BeginTime;
}
else
{
// Assume timestamps are in chronological order so no more need to be removed
break;
}
}
if (toPreserveStart > 0)
{
_timestamps.RemoveRange(0, toPreserveStart);
}
if (toRemove > 0)
{
_timestamps.RemoveRange(toPreserveLen, toRemove);
}
}
}
public Timestamp[] GetAllTimestamps()
{
lock (_timestampListLock)
{
Timestamp[] returnTimestamps = new Timestamp[_timestamps.Count];
_timestamps.CopyTo(returnTimestamps);
return returnTimestamps;
}
}
}
}
|