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 true /* pipeline stats*/);
114 screen
->monitor_cfg
= monitor_cfg
;
116 /* a gallium "group" is equivalent to a gen "query"
117 * a gallium "query" is equivalent to a gen "query_counter"
119 * Each gen_query supports a specific number of query_counters. To
120 * allocate the array of iris_monitor_counter, we need an upper bound
121 * (ignoring duplicate query_counters).
123 int gen_query_counters_count
= 0;
124 for (int gen_query_id
= 0;
125 gen_query_id
< perf_cfg
->n_queries
;
127 gen_query_counters_count
+= perf_cfg
->queries
[gen_query_id
].n_counters
;
130 monitor_cfg
->counters
= rzalloc_size(monitor_cfg
,
131 sizeof(struct iris_monitor_counter
) *
132 gen_query_counters_count
);
133 if (unlikely(!monitor_cfg
->counters
))
134 goto allocation_error
;
136 int iris_monitor_id
= 0;
137 for (int group
= 0; group
< perf_cfg
->n_queries
; ++group
) {
138 for (int counter
= 0;
139 counter
< perf_cfg
->queries
[group
].n_counters
;
141 /* Check previously identified metrics to filter out duplicates. The
142 * user is not helped by having the same metric available in several
143 * groups. (n^2 algorithm).
145 bool duplicate
= false;
146 for (int existing_group
= 0;
147 existing_group
< group
&& !duplicate
;
149 for (int existing_counter
= 0;
150 existing_counter
< perf_cfg
->queries
[existing_group
].n_counters
&& !duplicate
;
151 ++existing_counter
) {
152 const char *current_name
=
153 perf_cfg
->queries
[group
].counters
[counter
].name
;
154 const char *existing_name
=
155 perf_cfg
->queries
[existing_group
].counters
[existing_counter
].name
;
156 if (strcmp(current_name
, existing_name
) == 0) {
163 monitor_cfg
->counters
[iris_monitor_id
].group
= group
;
164 monitor_cfg
->counters
[iris_monitor_id
].counter
= counter
;
168 monitor_cfg
->num_counters
= iris_monitor_id
;
169 return monitor_cfg
->num_counters
;
173 free(monitor_cfg
->counters
);
180 iris_get_monitor_group_info(struct pipe_screen
*pscreen
,
181 unsigned group_index
,
182 struct pipe_driver_query_group_info
*info
)
184 struct iris_screen
*screen
= (struct iris_screen
*)pscreen
;
185 if (!screen
->monitor_cfg
) {
186 if (!iris_monitor_init_metrics(screen
))
190 const struct iris_monitor_config
*monitor_cfg
= screen
->monitor_cfg
;
191 const struct gen_perf_config
*perf_cfg
= monitor_cfg
->perf_cfg
;
194 /* return the count that can be queried */
195 return perf_cfg
->n_queries
;
198 if (group_index
>= perf_cfg
->n_queries
) {
203 struct gen_perf_query_info
*query
= &perf_cfg
->queries
[group_index
];
205 info
->name
= query
->name
;
206 info
->max_active_queries
= query
->n_counters
;
207 info
->num_queries
= query
->n_counters
;
213 iris_init_monitor_ctx(struct iris_context
*ice
)
215 struct iris_screen
*screen
= (struct iris_screen
*) ice
->ctx
.screen
;
216 struct iris_monitor_config
*monitor_cfg
= screen
->monitor_cfg
;
218 ice
->perf_ctx
= gen_perf_new_context(ice
);
219 if (unlikely(!ice
->perf_ctx
))
222 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
223 struct gen_perf_config
*perf_cfg
= monitor_cfg
->perf_cfg
;
224 gen_perf_init_context(perf_ctx
,
229 ice
->batches
[IRIS_BATCH_RENDER
].hw_ctx_id
,
233 /* entry point for GenPerfMonitorsAMD */
234 struct iris_monitor_object
*
235 iris_create_monitor_object(struct iris_context
*ice
,
236 unsigned num_queries
,
237 unsigned *query_types
)
239 struct iris_screen
*screen
= (struct iris_screen
*) ice
->ctx
.screen
;
240 struct iris_monitor_config
*monitor_cfg
= screen
->monitor_cfg
;
241 struct gen_perf_config
*perf_cfg
= monitor_cfg
->perf_cfg
;
242 struct gen_perf_query_object
*query_obj
= NULL
;
244 /* initialize perf context if this has not already been done. This
245 * function is the first entry point that carries the gl context.
247 if (ice
->perf_ctx
== NULL
) {
248 iris_init_monitor_ctx(ice
);
250 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
252 assert(num_queries
> 0);
253 int query_index
= query_types
[0] - PIPE_QUERY_DRIVER_SPECIFIC
;
254 assert(query_index
<= monitor_cfg
->num_counters
);
255 const int group
= monitor_cfg
->counters
[query_index
].group
;
257 struct iris_monitor_object
*monitor
=
258 calloc(1, sizeof(struct iris_monitor_object
));
259 if (unlikely(!monitor
))
260 goto allocation_failure
;
262 monitor
->num_active_counters
= num_queries
;
263 monitor
->active_counters
= calloc(num_queries
, sizeof(int));
264 if (unlikely(!monitor
->active_counters
))
265 goto allocation_failure
;
267 for (int i
= 0; i
< num_queries
; ++i
) {
268 unsigned current_query
= query_types
[i
];
269 unsigned current_query_index
= current_query
- PIPE_QUERY_DRIVER_SPECIFIC
;
271 /* all queries must be in the same group */
272 assert(current_query_index
<= monitor_cfg
->num_counters
);
273 assert(monitor_cfg
->counters
[current_query_index
].group
== group
);
274 monitor
->active_counters
[i
] =
275 monitor_cfg
->counters
[current_query_index
].counter
;
278 /* create the gen_perf_query */
279 query_obj
= gen_perf_new_query(perf_ctx
, group
);
280 if (unlikely(!query_obj
))
281 goto allocation_failure
;
283 monitor
->query
= query_obj
;
284 monitor
->result_size
= perf_cfg
->queries
[group
].data_size
;
285 monitor
->result_buffer
= calloc(1, monitor
->result_size
);
286 if (unlikely(!monitor
->result_buffer
))
287 goto allocation_failure
;
293 free(monitor
->active_counters
);
294 free(monitor
->result_buffer
);
302 iris_destroy_monitor_object(struct pipe_context
*ctx
,
303 struct iris_monitor_object
*monitor
)
305 struct iris_context
*ice
= (struct iris_context
*)ctx
;
307 gen_perf_delete_query(ice
->perf_ctx
, monitor
->query
);
308 free(monitor
->result_buffer
);
309 monitor
->result_buffer
= NULL
;
310 free(monitor
->active_counters
);
311 monitor
->active_counters
= NULL
;
316 iris_begin_monitor(struct pipe_context
*ctx
,
317 struct iris_monitor_object
*monitor
)
319 struct iris_context
*ice
= (void *) ctx
;
320 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
322 return gen_perf_begin_query(perf_ctx
, monitor
->query
);
326 iris_end_monitor(struct pipe_context
*ctx
,
327 struct iris_monitor_object
*monitor
)
329 struct iris_context
*ice
= (void *) ctx
;
330 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
332 gen_perf_end_query(perf_ctx
, monitor
->query
);
337 iris_get_monitor_result(struct pipe_context
*ctx
,
338 struct iris_monitor_object
*monitor
,
340 union pipe_numeric_type_union
*result
)
342 struct iris_context
*ice
= (void *) ctx
;
343 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
344 struct iris_batch
*batch
= &ice
->batches
[IRIS_BATCH_RENDER
];
347 gen_perf_is_query_ready(perf_ctx
, monitor
->query
, batch
);
349 if (!monitor_ready
) {
352 gen_perf_wait_query(perf_ctx
, monitor
->query
, batch
);
355 assert(gen_perf_is_query_ready(perf_ctx
, monitor
->query
, batch
));
357 unsigned bytes_written
;
358 gen_perf_get_query_data(perf_ctx
, monitor
->query
,
359 monitor
->result_size
,
360 (unsigned*) monitor
->result_buffer
,
362 if (bytes_written
!= monitor
->result_size
)
365 /* copy metrics into the batch result */
366 for (int i
= 0; i
< monitor
->num_active_counters
; ++i
) {
367 int current_counter
= monitor
->active_counters
[i
];
368 const struct gen_perf_query_info
*info
=
369 gen_perf_query_info(monitor
->query
);
370 const struct gen_perf_query_counter
*counter
=
371 &info
->counters
[current_counter
];
372 assert(gen_perf_query_counter_get_size(counter
));
373 switch (counter
->data_type
) {
374 case GEN_PERF_COUNTER_DATA_TYPE_UINT64
:
375 result
[i
].u64
= *(uint64_t*)(monitor
->result_buffer
+ counter
->offset
);
377 case GEN_PERF_COUNTER_DATA_TYPE_FLOAT
:
378 result
[i
].f
= *(float*)(monitor
->result_buffer
+ counter
->offset
);
380 case GEN_PERF_COUNTER_DATA_TYPE_UINT32
:
381 case GEN_PERF_COUNTER_DATA_TYPE_BOOL32
:
382 result
[i
].u64
= *(uint32_t*)(monitor
->result_buffer
+ counter
->offset
);
384 case GEN_PERF_COUNTER_DATA_TYPE_DOUBLE
: {
385 double v
= *(double*)(monitor
->result_buffer
+ counter
->offset
);
390 unreachable("unexpected counter data type");