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 const struct gen_perf_config
*perf_cfg
= screen
->perf_cfg
;
52 /* return the number of metrics */
53 return perf_cfg
->n_counters
;
56 struct gen_perf_query_counter_info
*counter_info
= &perf_cfg
->counter_infos
[index
];
57 struct gen_perf_query_counter
*counter
= counter_info
->counter
;
59 info
->group_id
= counter_info
->location
.group_idx
;
60 info
->name
= counter
->name
;
61 info
->query_type
= PIPE_QUERY_DRIVER_SPECIFIC
+ index
;
63 if (counter
->type
== GEN_PERF_COUNTER_TYPE_THROUGHPUT
)
64 info
->result_type
= PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE
;
66 info
->result_type
= PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE
;
67 switch (counter
->data_type
) {
68 case GEN_PERF_COUNTER_DATA_TYPE_BOOL32
:
69 case GEN_PERF_COUNTER_DATA_TYPE_UINT32
:
70 info
->type
= PIPE_DRIVER_QUERY_TYPE_UINT
;
71 assert(counter
->raw_max
<= UINT32_MAX
);
72 info
->max_value
.u32
= (uint32_t)counter
->raw_max
;
74 case GEN_PERF_COUNTER_DATA_TYPE_UINT64
:
75 info
->type
= PIPE_DRIVER_QUERY_TYPE_UINT64
;
76 info
->max_value
.u64
= counter
->raw_max
;
78 case GEN_PERF_COUNTER_DATA_TYPE_FLOAT
:
79 case GEN_PERF_COUNTER_DATA_TYPE_DOUBLE
:
80 info
->type
= PIPE_DRIVER_QUERY_TYPE_FLOAT
;
81 info
->max_value
.f
= counter
->raw_max
;
88 /* indicates that this is an OA query, not a pipeline statistics query */
89 info
->flags
= PIPE_DRIVER_QUERY_FLAG_BATCH
;
94 iris_monitor_init_metrics(struct iris_screen
*screen
)
96 struct gen_perf_config
*perf_cfg
= gen_perf_new(screen
);
97 if (unlikely(!perf_cfg
))
100 screen
->perf_cfg
= perf_cfg
;
102 iris_perf_init_vtbl(perf_cfg
);
104 gen_perf_init_metrics(perf_cfg
, &screen
->devinfo
, screen
->fd
,
105 true /* pipeline stats*/);
107 return perf_cfg
->n_counters
> 0;
111 iris_get_monitor_group_info(struct pipe_screen
*pscreen
,
112 unsigned group_index
,
113 struct pipe_driver_query_group_info
*info
)
115 struct iris_screen
*screen
= (struct iris_screen
*)pscreen
;
116 if (!screen
->perf_cfg
) {
117 if (!iris_monitor_init_metrics(screen
))
121 const struct gen_perf_config
*perf_cfg
= screen
->perf_cfg
;
124 /* return the count that can be queried */
125 return perf_cfg
->n_queries
;
128 if (group_index
>= perf_cfg
->n_queries
) {
133 struct gen_perf_query_info
*query
= &perf_cfg
->queries
[group_index
];
135 info
->name
= query
->name
;
136 info
->max_active_queries
= query
->n_counters
;
137 info
->num_queries
= query
->n_counters
;
143 iris_init_monitor_ctx(struct iris_context
*ice
)
145 struct iris_screen
*screen
= (struct iris_screen
*) ice
->ctx
.screen
;
147 ice
->perf_ctx
= gen_perf_new_context(ice
);
148 if (unlikely(!ice
->perf_ctx
))
151 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
152 struct gen_perf_config
*perf_cfg
= screen
->perf_cfg
;
153 gen_perf_init_context(perf_ctx
,
158 ice
->batches
[IRIS_BATCH_RENDER
].hw_ctx_id
,
162 /* entry point for GenPerfMonitorsAMD */
163 struct iris_monitor_object
*
164 iris_create_monitor_object(struct iris_context
*ice
,
165 unsigned num_queries
,
166 unsigned *query_types
)
168 struct iris_screen
*screen
= (struct iris_screen
*) ice
->ctx
.screen
;
169 struct gen_perf_config
*perf_cfg
= screen
->perf_cfg
;
170 struct gen_perf_query_object
*query_obj
= NULL
;
172 /* initialize perf context if this has not already been done. This
173 * function is the first entry point that carries the gl context.
175 if (ice
->perf_ctx
== NULL
) {
176 iris_init_monitor_ctx(ice
);
178 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
180 assert(num_queries
> 0);
181 int query_index
= query_types
[0] - PIPE_QUERY_DRIVER_SPECIFIC
;
182 assert(query_index
<= perf_cfg
->n_counters
);
183 const int group
= perf_cfg
->counter_infos
[query_index
].location
.group_idx
;
185 struct iris_monitor_object
*monitor
=
186 calloc(1, sizeof(struct iris_monitor_object
));
187 if (unlikely(!monitor
))
188 goto allocation_failure
;
190 monitor
->num_active_counters
= num_queries
;
191 monitor
->active_counters
= calloc(num_queries
, sizeof(int));
192 if (unlikely(!monitor
->active_counters
))
193 goto allocation_failure
;
195 for (int i
= 0; i
< num_queries
; ++i
) {
196 unsigned current_query
= query_types
[i
];
197 unsigned current_query_index
= current_query
- PIPE_QUERY_DRIVER_SPECIFIC
;
199 /* all queries must be in the same group */
200 assert(current_query_index
<= perf_cfg
->n_counters
);
201 assert(perf_cfg
->counter_infos
[current_query_index
].location
.group_idx
== group
);
202 monitor
->active_counters
[i
] =
203 perf_cfg
->counter_infos
[current_query_index
].location
.counter_idx
;
206 /* create the gen_perf_query */
207 query_obj
= gen_perf_new_query(perf_ctx
, group
);
208 if (unlikely(!query_obj
))
209 goto allocation_failure
;
211 monitor
->query
= query_obj
;
212 monitor
->result_size
= perf_cfg
->queries
[group
].data_size
;
213 monitor
->result_buffer
= calloc(1, monitor
->result_size
);
214 if (unlikely(!monitor
->result_buffer
))
215 goto allocation_failure
;
221 free(monitor
->active_counters
);
222 free(monitor
->result_buffer
);
230 iris_destroy_monitor_object(struct pipe_context
*ctx
,
231 struct iris_monitor_object
*monitor
)
233 struct iris_context
*ice
= (struct iris_context
*)ctx
;
235 gen_perf_delete_query(ice
->perf_ctx
, monitor
->query
);
236 free(monitor
->result_buffer
);
237 monitor
->result_buffer
= NULL
;
238 free(monitor
->active_counters
);
239 monitor
->active_counters
= NULL
;
244 iris_begin_monitor(struct pipe_context
*ctx
,
245 struct iris_monitor_object
*monitor
)
247 struct iris_context
*ice
= (void *) ctx
;
248 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
250 return gen_perf_begin_query(perf_ctx
, monitor
->query
);
254 iris_end_monitor(struct pipe_context
*ctx
,
255 struct iris_monitor_object
*monitor
)
257 struct iris_context
*ice
= (void *) ctx
;
258 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
260 gen_perf_end_query(perf_ctx
, monitor
->query
);
265 iris_get_monitor_result(struct pipe_context
*ctx
,
266 struct iris_monitor_object
*monitor
,
268 union pipe_numeric_type_union
*result
)
270 struct iris_context
*ice
= (void *) ctx
;
271 struct gen_perf_context
*perf_ctx
= ice
->perf_ctx
;
272 struct iris_batch
*batch
= &ice
->batches
[IRIS_BATCH_RENDER
];
275 gen_perf_is_query_ready(perf_ctx
, monitor
->query
, batch
);
277 if (!monitor_ready
) {
280 gen_perf_wait_query(perf_ctx
, monitor
->query
, batch
);
283 assert(gen_perf_is_query_ready(perf_ctx
, monitor
->query
, batch
));
285 unsigned bytes_written
;
286 gen_perf_get_query_data(perf_ctx
, monitor
->query
,
287 monitor
->result_size
,
288 (unsigned*) monitor
->result_buffer
,
290 if (bytes_written
!= monitor
->result_size
)
293 /* copy metrics into the batch result */
294 for (int i
= 0; i
< monitor
->num_active_counters
; ++i
) {
295 int current_counter
= monitor
->active_counters
[i
];
296 const struct gen_perf_query_info
*info
=
297 gen_perf_query_info(monitor
->query
);
298 const struct gen_perf_query_counter
*counter
=
299 &info
->counters
[current_counter
];
300 assert(gen_perf_query_counter_get_size(counter
));
301 switch (counter
->data_type
) {
302 case GEN_PERF_COUNTER_DATA_TYPE_UINT64
:
303 result
[i
].u64
= *(uint64_t*)(monitor
->result_buffer
+ counter
->offset
);
305 case GEN_PERF_COUNTER_DATA_TYPE_FLOAT
:
306 result
[i
].f
= *(float*)(monitor
->result_buffer
+ counter
->offset
);
308 case GEN_PERF_COUNTER_DATA_TYPE_UINT32
:
309 case GEN_PERF_COUNTER_DATA_TYPE_BOOL32
:
310 result
[i
].u64
= *(uint32_t*)(monitor
->result_buffer
+ counter
->offset
);
312 case GEN_PERF_COUNTER_DATA_TYPE_DOUBLE
: {
313 double v
= *(double*)(monitor
->result_buffer
+ counter
->offset
);
318 unreachable("unexpected counter data type");