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