f2c0774b1c3f387887895d025f45cfef79c387f1
[mesa.git] / src / gallium / drivers / iris / iris_monitor.c
1 /*
2 * Copyright © 2019 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 #include "iris_monitor.h"
24
25 #include <xf86drm.h>
26
27 #include "iris_screen.h"
28 #include "iris_context.h"
29 #include "iris_perf.h"
30
31 struct iris_monitor_object {
32 int num_active_counters;
33 int *active_counters;
34
35 size_t result_size;
36 unsigned char *result_buffer;
37
38 struct gen_perf_query_object *query;
39 };
40
41 int
42 iris_get_monitor_info(struct pipe_screen *pscreen, unsigned index,
43 struct pipe_driver_query_info *info)
44 {
45 const struct iris_screen *screen = (struct iris_screen *)pscreen;
46 assert(screen->monitor_cfg);
47 if (!screen->monitor_cfg)
48 return 0;
49
50 const struct iris_monitor_config *monitor_cfg = screen->monitor_cfg;
51
52 if (!info) {
53 /* return the number of metrics */
54 return monitor_cfg->num_counters;
55 }
56
57 const struct gen_perf_config *perf_cfg = monitor_cfg->perf_cfg;
58 const int group = monitor_cfg->counters[index].group;
59 const int counter_index = monitor_cfg->counters[index].counter;
60 struct gen_perf_query_counter *counter =
61 &perf_cfg->queries[group].counters[counter_index];
62
63 info->group_id = group;
64 info->name = counter->name;
65 info->query_type = PIPE_QUERY_DRIVER_SPECIFIC + index;
66
67 if (counter->type == GEN_PERF_COUNTER_TYPE_THROUGHPUT)
68 info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE;
69 else
70 info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE;
71 switch (counter->data_type) {
72 case GEN_PERF_COUNTER_DATA_TYPE_BOOL32:
73 case GEN_PERF_COUNTER_DATA_TYPE_UINT32:
74 info->type = PIPE_DRIVER_QUERY_TYPE_UINT;
75 info->max_value.u32 = 0;
76 break;
77 case GEN_PERF_COUNTER_DATA_TYPE_UINT64:
78 info->type = PIPE_DRIVER_QUERY_TYPE_UINT64;
79 info->max_value.u64 = 0;
80 break;
81 case GEN_PERF_COUNTER_DATA_TYPE_FLOAT:
82 case GEN_PERF_COUNTER_DATA_TYPE_DOUBLE:
83 info->type = PIPE_DRIVER_QUERY_TYPE_FLOAT;
84 info->max_value.u64 = -1;
85 break;
86 default:
87 assert(false);
88 break;
89 }
90
91 /* indicates that this is an OA query, not a pipeline statistics query */
92 info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
93 return 1;
94 }
95
96 static bool
97 iris_monitor_init_metrics(struct iris_screen *screen)
98 {
99 struct iris_monitor_config *monitor_cfg =
100 rzalloc(screen, struct iris_monitor_config);
101 struct gen_perf_config *perf_cfg = NULL;
102 if (unlikely(!monitor_cfg))
103 goto allocation_error;
104 perf_cfg = gen_perf_new(monitor_cfg);
105 if (unlikely(!perf_cfg))
106 goto allocation_error;
107
108 monitor_cfg->perf_cfg = perf_cfg;
109
110 iris_perf_init_vtbl(perf_cfg);
111
112 gen_perf_init_metrics(perf_cfg, &screen->devinfo, screen->fd);
113 screen->monitor_cfg = monitor_cfg;
114
115 /* a gallium "group" is equivalent to a gen "query"
116 * a gallium "query" is equivalent to a gen "query_counter"
117 *
118 * Each gen_query supports a specific number of query_counters. To
119 * allocate the array of iris_monitor_counter, we need an upper bound
120 * (ignoring duplicate query_counters).
121 */
122 int gen_query_counters_count = 0;
123 for (int gen_query_id = 0;
124 gen_query_id < perf_cfg->n_queries;
125 ++gen_query_id) {
126 gen_query_counters_count += perf_cfg->queries[gen_query_id].n_counters;
127 }
128
129 monitor_cfg->counters = rzalloc_size(monitor_cfg,
130 sizeof(struct iris_monitor_counter) *
131 gen_query_counters_count);
132 if (unlikely(!monitor_cfg->counters))
133 goto allocation_error;
134
135 int iris_monitor_id = 0;
136 for (int group = 0; group < perf_cfg->n_queries; ++group) {
137 for (int counter = 0;
138 counter < perf_cfg->queries[group].n_counters;
139 ++counter) {
140 /* Check previously identified metrics to filter out duplicates. The
141 * user is not helped by having the same metric available in several
142 * groups. (n^2 algorithm).
143 */
144 bool duplicate = false;
145 for (int existing_group = 0;
146 existing_group < group && !duplicate;
147 ++existing_group) {
148 for (int existing_counter = 0;
149 existing_counter < perf_cfg->queries[existing_group].n_counters && !duplicate;
150 ++existing_counter) {
151 const char *current_name =
152 perf_cfg->queries[group].counters[counter].name;
153 const char *existing_name =
154 perf_cfg->queries[existing_group].counters[existing_counter].name;
155 if (strcmp(current_name, existing_name) == 0) {
156 duplicate = true;
157 }
158 }
159 }
160 if (duplicate)
161 continue;
162 monitor_cfg->counters[iris_monitor_id].group = group;
163 monitor_cfg->counters[iris_monitor_id].counter = counter;
164 ++iris_monitor_id;
165 }
166 }
167 monitor_cfg->num_counters = iris_monitor_id;
168 return monitor_cfg->num_counters;
169
170 allocation_error:
171 if (monitor_cfg)
172 free(monitor_cfg->counters);
173 free(perf_cfg);
174 free(monitor_cfg);
175 return false;
176 }
177
178 int
179 iris_get_monitor_group_info(struct pipe_screen *pscreen,
180 unsigned group_index,
181 struct pipe_driver_query_group_info *info)
182 {
183 struct iris_screen *screen = (struct iris_screen *)pscreen;
184 if (!screen->monitor_cfg) {
185 if (!iris_monitor_init_metrics(screen))
186 return 0;
187 }
188
189 const struct iris_monitor_config *monitor_cfg = screen->monitor_cfg;
190 const struct gen_perf_config *perf_cfg = monitor_cfg->perf_cfg;
191
192 if (!info) {
193 /* return the count that can be queried */
194 return perf_cfg->n_queries;
195 }
196
197 if (group_index >= perf_cfg->n_queries) {
198 /* out of range */
199 return 0;
200 }
201
202 struct gen_perf_query_info *query = &perf_cfg->queries[group_index];
203
204 info->name = query->name;
205 info->max_active_queries = query->n_counters;
206 info->num_queries = query->n_counters;
207
208 return 1;
209 }
210
211 static void
212 iris_init_monitor_ctx(struct iris_context *ice)
213 {
214 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
215 struct iris_monitor_config *monitor_cfg = screen->monitor_cfg;
216
217 ice->perf_ctx = gen_perf_new_context(ice);
218 if (unlikely(!ice->perf_ctx))
219 return;
220
221 struct gen_perf_context *perf_ctx = ice->perf_ctx;
222 struct gen_perf_config *perf_cfg = monitor_cfg->perf_cfg;
223 gen_perf_init_context(perf_ctx,
224 perf_cfg,
225 ice,
226 screen->bufmgr,
227 &screen->devinfo,
228 ice->batches[IRIS_BATCH_RENDER].hw_ctx_id,
229 screen->fd);
230 }
231
232 /* entry point for GenPerfMonitorsAMD */
233 struct iris_monitor_object *
234 iris_create_monitor_object(struct iris_context *ice,
235 unsigned num_queries,
236 unsigned *query_types)
237 {
238 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
239 struct iris_monitor_config *monitor_cfg = screen->monitor_cfg;
240 struct gen_perf_config *perf_cfg = monitor_cfg->perf_cfg;
241 struct gen_perf_query_object *query_obj = NULL;
242
243 /* initialize perf context if this has not already been done. This
244 * function is the first entry point that carries the gl context.
245 */
246 if (ice->perf_ctx == NULL) {
247 iris_init_monitor_ctx(ice);
248 }
249 struct gen_perf_context *perf_ctx = ice->perf_ctx;
250
251 assert(num_queries > 0);
252 int query_index = query_types[0] - PIPE_QUERY_DRIVER_SPECIFIC;
253 assert(query_index <= monitor_cfg->num_counters);
254 const int group = monitor_cfg->counters[query_index].group;
255
256 struct iris_monitor_object *monitor =
257 calloc(1, sizeof(struct iris_monitor_object));
258 if (unlikely(!monitor))
259 goto allocation_failure;
260
261 monitor->num_active_counters = num_queries;
262 monitor->active_counters = calloc(num_queries, sizeof(int));
263 if (unlikely(!monitor->active_counters))
264 goto allocation_failure;
265
266 for (int i = 0; i < num_queries; ++i) {
267 unsigned current_query = query_types[i];
268 unsigned current_query_index = current_query - PIPE_QUERY_DRIVER_SPECIFIC;
269
270 /* all queries must be in the same group */
271 assert(current_query_index <= monitor_cfg->num_counters);
272 assert(monitor_cfg->counters[current_query_index].group == group);
273 monitor->active_counters[i] =
274 monitor_cfg->counters[current_query_index].counter;
275 }
276
277 /* create the gen_perf_query */
278 query_obj = gen_perf_new_query(perf_ctx, group);
279 if (unlikely(!query_obj))
280 goto allocation_failure;
281
282 monitor->query = query_obj;
283 monitor->result_size = perf_cfg->queries[group].data_size;
284 monitor->result_buffer = calloc(1, monitor->result_size);
285 if (unlikely(!monitor->result_buffer))
286 goto allocation_failure;
287
288 return monitor;
289
290 allocation_failure:
291 if (monitor) {
292 free(monitor->active_counters);
293 free(monitor->result_buffer);
294 }
295 free(query_obj);
296 free(monitor);
297 return NULL;
298 }
299
300 void
301 iris_destroy_monitor_object(struct pipe_context *ctx,
302 struct iris_monitor_object *monitor)
303 {
304 struct iris_context *ice = (struct iris_context *)ctx;
305
306 gen_perf_delete_query(ice->perf_ctx, monitor->query);
307 free(monitor->result_buffer);
308 monitor->result_buffer = NULL;
309 free(monitor->active_counters);
310 monitor->active_counters = NULL;
311 free(monitor);
312 }
313
314 bool
315 iris_begin_monitor(struct pipe_context *ctx,
316 struct iris_monitor_object *monitor)
317 {
318 struct iris_context *ice = (void *) ctx;
319 struct gen_perf_context *perf_ctx = ice->perf_ctx;
320
321 return gen_perf_begin_query(perf_ctx, monitor->query);
322 }
323
324 bool
325 iris_end_monitor(struct pipe_context *ctx,
326 struct iris_monitor_object *monitor)
327 {
328 struct iris_context *ice = (void *) ctx;
329 struct gen_perf_context *perf_ctx = ice->perf_ctx;
330
331 gen_perf_end_query(perf_ctx, monitor->query);
332 return true;
333 }
334
335 bool
336 iris_get_monitor_result(struct pipe_context *ctx,
337 struct iris_monitor_object *monitor,
338 bool wait,
339 union pipe_numeric_type_union *result)
340 {
341 struct iris_context *ice = (void *) ctx;
342 struct gen_perf_context *perf_ctx = ice->perf_ctx;
343 struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
344
345 bool monitor_ready =
346 gen_perf_is_query_ready(perf_ctx, monitor->query, batch);
347
348 if (!monitor_ready) {
349 if (!wait)
350 return false;
351 gen_perf_wait_query(perf_ctx, monitor->query, batch);
352 }
353
354 assert(gen_perf_is_query_ready(perf_ctx, monitor->query, batch));
355
356 unsigned bytes_written;
357 gen_perf_get_query_data(perf_ctx, monitor->query,
358 monitor->result_size,
359 (unsigned*) monitor->result_buffer,
360 &bytes_written);
361 if (bytes_written != monitor->result_size)
362 return false;
363
364 /* copy metrics into the batch result */
365 for (int i = 0; i < monitor->num_active_counters; ++i) {
366 int current_counter = monitor->active_counters[i];
367 const struct gen_perf_query_info *info =
368 gen_perf_query_info(monitor->query);
369 const struct gen_perf_query_counter *counter =
370 &info->counters[current_counter];
371 assert(gen_perf_query_counter_get_size(counter));
372 switch (counter->data_type) {
373 case GEN_PERF_COUNTER_DATA_TYPE_UINT64:
374 result[i].u64 = *(uint64_t*)(monitor->result_buffer + counter->offset);
375 break;
376 case GEN_PERF_COUNTER_DATA_TYPE_FLOAT:
377 result[i].f = *(float*)(monitor->result_buffer + counter->offset);
378 break;
379 case GEN_PERF_COUNTER_DATA_TYPE_UINT32:
380 case GEN_PERF_COUNTER_DATA_TYPE_BOOL32:
381 result[i].u64 = *(uint32_t*)(monitor->result_buffer + counter->offset);
382 break;
383 case GEN_PERF_COUNTER_DATA_TYPE_DOUBLE: {
384 double v = *(double*)(monitor->result_buffer + counter->offset);
385 result[i].f = v;
386 break;
387 }
388 default:
389 unreachable("unexpected counter data type");
390 }
391 }
392 return true;
393 }