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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
|
/**************************************************************************
*
* Copyright 2015 Alexander Trukhin
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**************************************************************************/
#pragma once
#include <memory>
#include <string>
/**
* Profiling boundary.
*/
enum QueryBoundary {
QUERY_BOUNDARY_DRAWCALL = 0, /**< draw call boundary */
QUERY_BOUNDARY_FRAME, /**< frame boundary */
QUERY_BOUNDARY_CALL, /**< any call boundary */
QUERY_BOUNDARY_LIST_END
};
/**
* Numeric type of the metric.
*/
enum MetricNumType {
CNT_NUM_UINT = 0,
CNT_NUM_FLOAT,
CNT_NUM_UINT64,
CNT_NUM_DOUBLE,
CNT_NUM_BOOL,
CNT_NUM_INT64
};
/**
* Type of data metric represents.
*/
enum MetricType {
CNT_TYPE_GENERIC = 0, /**< generally a number, comparable type */
CNT_TYPE_NUM, /**< number, not necessarily comparable (e.g. event number) */
CNT_TYPE_DURATION, /**< duration */
CNT_TYPE_PERCENT, /**< percentage */
CNT_TYPE_TIMESTAMP, /**< timestamp (e.g. GL_TIMESTAMP in OpenGL) */
CNT_TYPE_OTHER /**< not listed above */
};
/**
* Metric interface.
*
* Each metric can be uniquely identified by a group id and a metric id.
* Each backend is assumed to implement its own version of Metric. It is also
* supposed to provide metric groups and corresponding metrics.
* This interface is used to communicate with backend and can be used
* to store internal data in backend.
*
* It is generally a good idea to cache some parameters (e.g. numeric type).
*/
class Metric
{
public:
virtual ~Metric() {}
/**
* Returns metric id
*/
virtual unsigned id() = 0;
/**
* Returns metric group id
*/
virtual unsigned groupId() = 0;
/**
* Returns metric name string
*/
virtual std::string name() = 0;
/**
* Returns metric description string (or an empty string if not available)
*/
virtual std::string description() = 0;
/**
* Returns metric numeric type
*/
virtual MetricNumType numType() = 0;
/**
* Returns data type metric represents
*/
virtual MetricType type() = 0;
};
/**
* Callbacks for use in backend interface.
* int error : error code (0 - no error)
* void* userData : arbitrary pointer
*/
typedef void (*enumGroupsCallback)(unsigned group, int error, void* userData);
typedef void (*enumMetricsCallback)(Metric* metric, int error, void* userData);
typedef void (*enumDataCallback)(Metric* metric, int event, void* data,
int error, void* userData);
/**
* Backend interface.
*
* Abstraction for metric-collection system.
* Such system is supposed to have its own version of MetricBackend.
* Backend can be used to query available metrics, to profile calls/frames and
* to collect metrics.
* Backend is responsible for storing metric data.
*
* Unfortunately, not all collection systems allow to collect all metrics
* at the same time. Therefore multiple passes are needed, this interface provides
* the mean to implement such behaviour.
*
*
* Typical workflow example:
* MetricBackend* backend;
* backend->enableMetric(...);
* ...
* backend->enableMetric(...);
* for (i=0; i < backend->generatePasses(); i++) {
* backend->beginPass();
*
* backend->beginQuery(QUERY_BOUNDARY_FRAME);
*
* backend->beginQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL);
* ... profiled call ...
* backend->endQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL);
*
* ...
*
* backend->beginQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL);
* ... profiled call ...
* backend->endQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL);
*
* backend->endQuery(QUERY_BOUNDARY_FRAME);
*
* ... following frames ...
*
* backend->endPass();
* }
* // collect data
*
*
* It is generally a good idea to implement MetricBackend as a singleton.
*/
class MetricBackend
{
public:
virtual ~MetricBackend() {}
/**
* Returns true if MetricBackend is supported on current HW.
*/
virtual bool isSupported() = 0;
/**
* Enumerates metric groups, calls callback for each group.
*/
virtual void enumGroups(enumGroupsCallback callback,
void* userData = nullptr) = 0;
/**
* Enumerates metrics in specified group, calls callback for each metric.
* Callback receives pointer to the metric object among other params.
* Metric object is an object of class derived from Metric.
*/
virtual void enumMetrics(unsigned group, enumMetricsCallback callback,
void* userData = nullptr) = 0;
/**
* Returns group name string (or an empty string if not available).
*/
virtual std::string getGroupName(unsigned group) = 0;
/**
* Returns pointer to the metric object with given group id, metric id.
* Metric object is an object of class derived from Metric.
*/
virtual std::unique_ptr<Metric> getMetricById(unsigned groupId, unsigned metricId) = 0;
/**
* Returns pointer to the metric object with given metric name string.
* Metric object is an object of class derived from Metric.
*/
virtual std::unique_ptr<Metric> getMetricByName(std::string metricName) = 0;
/**
* Adds given metric object to the internal list of metrics
* to be profiled.
* pollingRule sets the boundary for collecting metric
* Returns error code (0 - no error).
*/
virtual int enableMetric(Metric* metric, QueryBoundary pollingRule = QUERY_BOUNDARY_DRAWCALL) = 0;
/**
* Generates passes based on enabled metrics.
* Returns number of generated passes.
*/
virtual unsigned generatePasses() = 0;
/**
* Begins pass. Subsequent calls begin next passes.
* A pass needs to be ended before starting a new one.
*/
virtual void beginPass() = 0;
/**
* Ends pass.
*/
virtual void endPass() = 0;
/**
* Pause pass with all the queries in progress.
* Backend decides what to do with the data of interrupted
* query.
* Can be used before the context switch in OpenGl.
*/
virtual void pausePass() = 0;
/**
* Continue profiling the pass after pausePass().
* Backend decides whether to reprofile interrupted by pausePass() query.
* Can be used after the context switch in OpenGl.
*/
virtual void continuePass() = 0;
/**
* Begins query (profiles unit, i.e. frames or calls). Subsequent calls
* begin next queries.
* Parameter boundary should be set to the type of boundary beginQuery/endQuery
* constructions enclose.
* A query needs to be ended before starting a new one.
*/
virtual void beginQuery(QueryBoundary boundary = QUERY_BOUNDARY_DRAWCALL) = 0;
/**
* Ends query.
* Parameter boundary should be set to the type of boundary beginQuery/endQuery
* constructions enclose.
*/
virtual void endQuery(QueryBoundary boundary = QUERY_BOUNDARY_DRAWCALL) = 0;
/**
* Enumerates collected metrics data for a given query id and given
* type of boundary.
* Query ids begin with 0 for first query.
* Metric data is passed to callback.
*
* The order in which metrics are returned can differ from the one in which
* metrics were enabled (via enableMetric(...)) . However, it should be
* guaranteed that order is the same for every query.
*/
virtual void enumDataQueryId(unsigned id, enumDataCallback callback,
QueryBoundary boundary,
void* userData = nullptr) = 0;
/**
* Returns number of passes generated by generatePasses(...).
* If generatePasses(...) was not called returns 1.
*/
virtual unsigned getNumPasses() = 0;
};
|