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 intel_perf_query_object *query;
39 };
40
41 int
iris_get_monitor_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_info * info)42 iris_get_monitor_info(struct pipe_screen *pscreen, unsigned index,
43 struct pipe_driver_query_info *info)
44 {
45 struct iris_screen *screen = (struct iris_screen *)pscreen;
46 struct intel_perf_config *perf_cfg = screen->perf_cfg;
47 assert(perf_cfg);
48 if (!perf_cfg)
49 return 0;
50
51 if (!info) {
52 /* return the number of metrics */
53 return perf_cfg->n_counters;
54 }
55
56 struct intel_perf_query_counter_info *counter_info = &perf_cfg->counter_infos[index];
57 struct intel_perf_query_info *query_info =
58 &perf_cfg->queries[intel_perf_query_counter_info_first_query(counter_info)];
59 struct intel_perf_query_counter *counter = counter_info->counter;
60 struct intel_perf_query_result results;
61
62 intel_perf_query_result_clear(&results);
63
64 info->group_id = counter_info->location.group_idx;
65 info->name = INTEL_DEBUG(DEBUG_PERF_SYMBOL_NAMES) ?
66 counter->symbol_name : counter->name;
67 info->query_type = PIPE_QUERY_DRIVER_SPECIFIC + index;
68
69 if (counter->type == INTEL_PERF_COUNTER_TYPE_THROUGHPUT)
70 info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE;
71 else
72 info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE;
73 switch (counter->data_type) {
74 case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
75 case INTEL_PERF_COUNTER_DATA_TYPE_UINT32: {
76 info->type = PIPE_DRIVER_QUERY_TYPE_UINT;
77 uint64_t val =
78 counter->oa_counter_max_uint64 ?
79 counter->oa_counter_max_uint64(perf_cfg, query_info, &results) : 0;
80 assert(val <= UINT32_MAX);
81 info->max_value.u32 = (uint32_t)val;
82 break;
83 }
84 case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
85 info->type = PIPE_DRIVER_QUERY_TYPE_UINT64;
86 info->max_value.u64 =
87 counter->oa_counter_max_uint64 ?
88 counter->oa_counter_max_uint64(perf_cfg, query_info, &results) : 0;
89 break;
90 case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
91 case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE:
92 info->type = PIPE_DRIVER_QUERY_TYPE_FLOAT;
93 info->max_value.f =
94 counter->oa_counter_max_float ?
95 counter->oa_counter_max_float(perf_cfg, query_info, &results) : 0.0f;
96 break;
97 default:
98 assert(false);
99 break;
100 }
101
102 /* indicates that this is an OA query, not a pipeline statistics query */
103 info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
104 return 1;
105 }
106
107 static bool
iris_monitor_init_metrics(struct iris_screen * screen)108 iris_monitor_init_metrics(struct iris_screen *screen)
109 {
110 struct intel_perf_config *perf_cfg = intel_perf_new(screen);
111 if (unlikely(!perf_cfg))
112 return false;
113
114 screen->perf_cfg = perf_cfg;
115
116 iris_perf_init_vtbl(perf_cfg);
117
118 intel_perf_init_metrics(perf_cfg, screen->devinfo, screen->fd,
119 true /* pipeline stats*/,
120 true /* register snapshots */);
121
122 return perf_cfg->n_counters > 0;
123 }
124
125 int
iris_get_monitor_group_info(struct pipe_screen * pscreen,unsigned group_index,struct pipe_driver_query_group_info * info)126 iris_get_monitor_group_info(struct pipe_screen *pscreen,
127 unsigned group_index,
128 struct pipe_driver_query_group_info *info)
129 {
130 struct iris_screen *screen = (struct iris_screen *)pscreen;
131 if (!screen->perf_cfg) {
132 if (!iris_monitor_init_metrics(screen))
133 return 0;
134 }
135
136 const struct intel_perf_config *perf_cfg = screen->perf_cfg;
137
138 if (!info) {
139 /* return the count that can be queried */
140 return perf_cfg->n_queries;
141 }
142
143 if (group_index >= perf_cfg->n_queries) {
144 /* out of range */
145 return 0;
146 }
147
148 struct intel_perf_query_info *query = &perf_cfg->queries[group_index];
149
150 info->name = query->name;
151 info->max_active_queries = query->n_counters;
152 info->num_queries = query->n_counters;
153
154 return 1;
155 }
156
157 static void
iris_init_monitor_ctx(struct iris_context * ice)158 iris_init_monitor_ctx(struct iris_context *ice)
159 {
160 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
161
162 ice->perf_ctx = intel_perf_new_context(ice);
163 if (unlikely(!ice->perf_ctx))
164 return;
165
166 struct intel_perf_context *perf_ctx = ice->perf_ctx;
167 struct intel_perf_config *perf_cfg = screen->perf_cfg;
168 intel_perf_init_context(perf_ctx,
169 perf_cfg,
170 ice,
171 ice,
172 screen->bufmgr,
173 screen->devinfo,
174 ice->batches[IRIS_BATCH_RENDER].i915.ctx_id,
175 screen->fd);
176 }
177
178 /* entry point for GenPerfMonitorsAMD */
179 struct iris_monitor_object *
iris_create_monitor_object(struct iris_context * ice,unsigned num_queries,unsigned * query_types)180 iris_create_monitor_object(struct iris_context *ice,
181 unsigned num_queries,
182 unsigned *query_types)
183 {
184 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
185 struct intel_perf_config *perf_cfg = screen->perf_cfg;
186 struct intel_perf_query_object *query_obj = NULL;
187
188 /* initialize perf context if this has not already been done. This
189 * function is the first entry point that carries the gl context.
190 */
191 if (ice->perf_ctx == NULL) {
192 iris_init_monitor_ctx(ice);
193 }
194 struct intel_perf_context *perf_ctx = ice->perf_ctx;
195
196 assert(num_queries > 0);
197 int query_index = query_types[0] - PIPE_QUERY_DRIVER_SPECIFIC;
198 assert(query_index <= perf_cfg->n_counters);
199 const int group = perf_cfg->counter_infos[query_index].location.group_idx;
200
201 struct iris_monitor_object *monitor =
202 calloc(1, sizeof(struct iris_monitor_object));
203 if (unlikely(!monitor))
204 goto allocation_failure;
205
206 monitor->num_active_counters = num_queries;
207 monitor->active_counters = calloc(num_queries, sizeof(int));
208 if (unlikely(!monitor->active_counters))
209 goto allocation_failure;
210
211 for (int i = 0; i < num_queries; ++i) {
212 unsigned current_query = query_types[i];
213 unsigned current_query_index = current_query - PIPE_QUERY_DRIVER_SPECIFIC;
214
215 /* all queries must be in the same group */
216 assert(current_query_index <= perf_cfg->n_counters);
217 assert(perf_cfg->counter_infos[current_query_index].location.group_idx == group);
218 monitor->active_counters[i] =
219 perf_cfg->counter_infos[current_query_index].location.counter_idx;
220 }
221
222 /* create the intel_perf_query */
223 query_obj = intel_perf_new_query(perf_ctx, group);
224 if (unlikely(!query_obj))
225 goto allocation_failure;
226
227 monitor->query = query_obj;
228 monitor->result_size = perf_cfg->queries[group].data_size;
229 monitor->result_buffer = calloc(1, monitor->result_size);
230 if (unlikely(!monitor->result_buffer))
231 goto allocation_failure;
232
233 return monitor;
234
235 allocation_failure:
236 if (monitor) {
237 free(monitor->active_counters);
238 free(monitor->result_buffer);
239 }
240 free(query_obj);
241 free(monitor);
242 return NULL;
243 }
244
245 void
iris_destroy_monitor_object(struct pipe_context * ctx,struct iris_monitor_object * monitor)246 iris_destroy_monitor_object(struct pipe_context *ctx,
247 struct iris_monitor_object *monitor)
248 {
249 struct iris_context *ice = (struct iris_context *)ctx;
250
251 intel_perf_delete_query(ice->perf_ctx, monitor->query);
252 free(monitor->result_buffer);
253 monitor->result_buffer = NULL;
254 free(monitor->active_counters);
255 monitor->active_counters = NULL;
256 free(monitor);
257 }
258
259 bool
iris_begin_monitor(struct pipe_context * ctx,struct iris_monitor_object * monitor)260 iris_begin_monitor(struct pipe_context *ctx,
261 struct iris_monitor_object *monitor)
262 {
263 struct iris_context *ice = (void *) ctx;
264 struct intel_perf_context *perf_ctx = ice->perf_ctx;
265
266 return intel_perf_begin_query(perf_ctx, monitor->query);
267 }
268
269 bool
iris_end_monitor(struct pipe_context * ctx,struct iris_monitor_object * monitor)270 iris_end_monitor(struct pipe_context *ctx,
271 struct iris_monitor_object *monitor)
272 {
273 struct iris_context *ice = (void *) ctx;
274 struct intel_perf_context *perf_ctx = ice->perf_ctx;
275
276 intel_perf_end_query(perf_ctx, monitor->query);
277 return true;
278 }
279
280 bool
iris_get_monitor_result(struct pipe_context * ctx,struct iris_monitor_object * monitor,bool wait,union pipe_numeric_type_union * result)281 iris_get_monitor_result(struct pipe_context *ctx,
282 struct iris_monitor_object *monitor,
283 bool wait,
284 union pipe_numeric_type_union *result)
285 {
286 struct iris_context *ice = (void *) ctx;
287 struct intel_perf_context *perf_ctx = ice->perf_ctx;
288 struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
289
290 bool monitor_ready =
291 intel_perf_is_query_ready(perf_ctx, monitor->query, batch);
292
293 if (!monitor_ready) {
294 if (!wait)
295 return false;
296 intel_perf_wait_query(perf_ctx, monitor->query, batch);
297 }
298
299 assert(intel_perf_is_query_ready(perf_ctx, monitor->query, batch));
300
301 unsigned bytes_written;
302 intel_perf_get_query_data(perf_ctx, monitor->query, batch,
303 monitor->result_size,
304 (unsigned*) monitor->result_buffer,
305 &bytes_written);
306 if (bytes_written != monitor->result_size)
307 return false;
308
309 /* copy metrics into the batch result */
310 for (int i = 0; i < monitor->num_active_counters; ++i) {
311 int current_counter = monitor->active_counters[i];
312 const struct intel_perf_query_info *info =
313 intel_perf_query_info(monitor->query);
314 const struct intel_perf_query_counter *counter =
315 &info->counters[current_counter];
316 assert(intel_perf_query_counter_get_size(counter));
317 switch (counter->data_type) {
318 case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
319 result[i].u64 = *(uint64_t*)(monitor->result_buffer + counter->offset);
320 break;
321 case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
322 result[i].f = *(float*)(monitor->result_buffer + counter->offset);
323 break;
324 case INTEL_PERF_COUNTER_DATA_TYPE_UINT32:
325 case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
326 result[i].u64 = *(uint32_t*)(monitor->result_buffer + counter->offset);
327 break;
328 case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE: {
329 double v = *(double*)(monitor->result_buffer + counter->offset);
330 result[i].f = v;
331 break;
332 }
333 default:
334 unreachable("unexpected counter data type");
335 }
336 }
337 return true;
338 }
339