2 * Copyright © 2019 Intel Corporation
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:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
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.
23 #include "iris_monitor.h"
27 #include "iris_screen.h"
28 #include "iris_context.h"
29 #include "iris_perf.h"
31 struct iris_monitor_object
{
32 int num_active_counters
;
36 unsigned char *result_buffer
;
38 struct gen_perf_query_object
*query
;
42 iris_get_monitor_info(struct pipe_screen
*pscreen
, unsigned index
,
43 struct pipe_driver_query_info
*info
)
45 const struct iris_screen
*screen
= (struct iris_screen
*)pscreen
;
46 assert(screen
->monitor_cfg
);
47 if (!screen
->monitor_cfg
)
50 const struct iris_monitor_config
*monitor_cfg
= screen
->monitor_cfg
;
53 /* return the number of metrics */
54 return monitor_cfg
->num_counters
;
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
];
63 info
->group_id
= group
;
64 info
->name
= counter
->name
;
65 info
->query_type
= PIPE_QUERY_DRIVER_SPECIFIC
+ index
;
67 if (counter
->type
== GEN_PERF_COUNTER_TYPE_THROUGHPUT
)
68 info
->result_type
= PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE
;
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;
77 case GEN_PERF_COUNTER_DATA_TYPE_UINT64
:
78 info
->type
= PIPE_DRIVER_QUERY_TYPE_UINT64
;
79 info
->max_value
.u64
= 0;
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;
91 /* indicates that this is an OA query, not a pipeline statistics query */
92 info
->flags
= PIPE_DRIVER_QUERY_FLAG_BATCH
;
97 iris_monitor_init_metrics(struct iris_screen
*screen
)
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
;
108 monitor_cfg
->perf_cfg
= perf_cfg
;
110 iris_perf_init_vtbl(perf_cfg
);
112 gen_perf_init_metrics(perf_cfg
, &screen
->devinfo
, screen
->fd
);
113 screen
->monitor_cfg
= monitor_cfg
;
115 /* a gallium "group" is equivalent to a gen "query"
116 * a gallium "query" is equivalent to a gen "query_counter"
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).
122 int gen_query_counters_count
= 0;
123 for (int gen_query_id
= 0;
124 gen_query_id
< perf_cfg
->n_queries
;
126 gen_query_counters_count
+= perf_cfg
->queries
[gen_query_id
].n_counters
;
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
;
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
;
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).
144 bool duplicate
= false;
145 for (int existing_group
= 0;
146 existing_group
< group
&& !duplicate
;
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) {
162 monitor_cfg
->counters
[iris_monitor_id
].group
= group
;
163 monitor_cfg
->counters
[iris_monitor_id
].counter
= counter
;
167 monitor_cfg
->num_counters
= iris_monitor_id
;
168 return monitor_cfg
->num_counters
;
172 free(monitor_cfg
->counters
);
179 iris_get_monitor_group_info(struct pipe_screen
*pscreen
,
180 unsigned group_index
,
181 struct pipe_driver_query_group_info
*info
)
183 struct iris_screen
*screen
= (struct iris_screen
*)pscreen
;
184 if (!screen
->monitor_cfg
) {
185 if (!iris_monitor_init_metrics(screen
))
189 const struct iris_monitor_config
*monitor_cfg
= screen
->monitor_cfg
;
190 const struct gen_perf_config
*perf_cfg
= monitor_cfg
->perf_cfg
;
193 /* return the count that can be queried */
194 return perf_cfg
->n_queries
;
197 if (group_index
>= perf_cfg
->n_queries
) {
202 struct gen_perf_query_info
*query
= &perf_cfg
->queries
[group_index
];
204 info
->name
= query
->name
;
205 info
->max_active_queries
= query
->n_counters
;
206 info
->num_queries
= query
->n_counters
;
212 iris_init_monitor_ctx(struct iris_context
*ice
)
214 struct iris_screen
*screen
= (struct iris_screen
*) ice
->ctx
.screen
;
215 struct iris_monitor_config
*monitor_cfg
= screen
->monitor_cfg
;
217 ice
->perf_ctx
= gen_perf_new_context(ice
);
218 if (unlikely(!ice
->perf_ctx
))
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
,
228 ice
->batches
[IRIS_BATCH_RENDER
].hw_ctx_id
,
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
)
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
;
243 /* initialize perf context if this has not already been done. This
244 * function is the first entry point that carries the gl context.
246 if (ice
->perf_ctx
== NULL
) {
247 iris_init_monitor_ctx(ice
);
249 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
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
;
256 struct iris_monitor_object
*monitor
=
257 calloc(1, sizeof(struct iris_monitor_object
));
258 if (unlikely(!monitor
))
259 goto allocation_failure
;
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
;
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
;
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
;
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
;
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
;
292 free(monitor
->active_counters
);
293 free(monitor
->result_buffer
);
301 iris_destroy_monitor_object(struct pipe_context
*ctx
,
302 struct iris_monitor_object
*monitor
)
304 struct iris_context
*ice
= (struct iris_context
*)ctx
;
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
;
315 iris_begin_monitor(struct pipe_context
*ctx
,
316 struct iris_monitor_object
*monitor
)
318 struct iris_context
*ice
= (void *) ctx
;
319 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
321 return gen_perf_begin_query(perf_ctx
, monitor
->query
);
325 iris_end_monitor(struct pipe_context
*ctx
,
326 struct iris_monitor_object
*monitor
)
328 struct iris_context
*ice
= (void *) ctx
;
329 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
331 gen_perf_end_query(perf_ctx
, monitor
->query
);
336 iris_get_monitor_result(struct pipe_context
*ctx
,
337 struct iris_monitor_object
*monitor
,
339 union pipe_numeric_type_union
*result
)
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
];
346 gen_perf_is_query_ready(perf_ctx
, monitor
->query
, batch
);
348 if (!monitor_ready
) {
351 gen_perf_wait_query(perf_ctx
, monitor
->query
, batch
);
354 assert(gen_perf_is_query_ready(perf_ctx
, monitor
->query
, batch
));
356 unsigned bytes_written
;
357 gen_perf_get_query_data(perf_ctx
, monitor
->query
,
358 monitor
->result_size
,
359 (unsigned*) monitor
->result_buffer
,
361 if (bytes_written
!= monitor
->result_size
)
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
);
376 case GEN_PERF_COUNTER_DATA_TYPE_FLOAT
:
377 result
[i
].f
= *(float*)(monitor
->result_buffer
+ counter
->offset
);
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
);
383 case GEN_PERF_COUNTER_DATA_TYPE_DOUBLE
: {
384 double v
= *(double*)(monitor
->result_buffer
+ counter
->offset
);
389 unreachable("unexpected counter data type");