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