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/** 24 * @file iris_measure.c 25 */ 26 27#include <stdio.h> 28#include "util/debug.h" 29#include "util/list.h" 30#include "util/crc32.h" 31#include "iris_context.h" 32#include "iris_defines.h" 33#include "compiler/shader_info.h" 34 35/** 36 * This callback is registered with intel_measure. It will be called when 37 * snapshot data has been fully collected, so iris can release the associated 38 * resources. 39 */ 40static void 41measure_batch_free(struct intel_measure_batch *base) 42{ 43 struct iris_measure_batch *batch = 44 container_of(base, struct iris_measure_batch, base); 45 iris_destroy_batch_measure(batch); 46} 47 48void 49iris_init_screen_measure(struct iris_screen *screen) 50{ 51 struct intel_measure_device *measure_device = &screen->measure; 52 53 memset(measure_device, 0, sizeof(*measure_device)); 54 intel_measure_init(measure_device); 55 measure_device->release_batch = &measure_batch_free; 56 struct intel_measure_config *config = measure_device->config; 57 if (config == NULL) 58 return; 59 60 /* the final member of intel_measure_ringbuffer is a zero-length array of 61 * intel_measure_buffered_result objects. Allocate additional space for 62 * the buffered objects based on the run-time configurable buffer_size 63 */ 64 const size_t rb_bytes = sizeof(struct intel_measure_ringbuffer) + 65 config->buffer_size * sizeof(struct intel_measure_buffered_result); 66 struct intel_measure_ringbuffer *rb = rzalloc_size(screen, rb_bytes); 67 measure_device->ringbuffer = rb; 68} 69 70static struct intel_measure_config * 71config_from_screen(struct iris_screen *screen) 72{ 73 return screen->measure.config; 74} 75 76static struct intel_measure_config * 77config_from_context(struct iris_context *ice) 78{ 79 return ((struct iris_screen *) ice->ctx.screen)->measure.config; 80} 81 82void 83iris_destroy_screen_measure(struct iris_screen *screen) 84{ 85 if (!config_from_screen(screen)) 86 return; 87 88 struct intel_measure_device *measure_device = &screen->measure; 89 90 if (measure_device->config->file && 91 measure_device->config->file != stderr) 92 fclose(screen->measure.config->file); 93 94 ralloc_free(measure_device->ringbuffer); 95 measure_device->ringbuffer = NULL; 96} 97 98 99void 100iris_init_batch_measure(struct iris_context *ice, struct iris_batch *batch) 101{ 102 const struct intel_measure_config *config = config_from_context(ice); 103 struct iris_screen *screen = batch->screen; 104 struct iris_bufmgr *bufmgr = screen->bufmgr; 105 106 if (!config) 107 return; 108 109 /* the final member of iris_measure_batch is a zero-length array of 110 * intel_measure_snapshot objects. Create additional space for the 111 * snapshot objects based on the run-time configurable batch_size 112 */ 113 const size_t batch_bytes = sizeof(struct iris_measure_batch) + 114 config->batch_size * sizeof(struct intel_measure_snapshot); 115 assert(batch->measure == NULL); 116 batch->measure = malloc(batch_bytes); 117 memset(batch->measure, 0, batch_bytes); 118 struct iris_measure_batch *measure = batch->measure; 119 120 measure->bo = iris_bo_alloc(bufmgr, "measure", 121 config->batch_size * sizeof(uint64_t), 8, 122 IRIS_MEMZONE_OTHER, BO_ALLOC_ZEROED); 123 measure->base.timestamps = iris_bo_map(NULL, measure->bo, MAP_READ); 124 measure->base.framebuffer = 125 (uintptr_t)util_hash_crc32(&ice->state.framebuffer, 126 sizeof(ice->state.framebuffer)); 127} 128 129void 130iris_destroy_batch_measure(struct iris_measure_batch *batch) 131{ 132 if (!batch) 133 return; 134 iris_bo_unmap(batch->bo); 135 iris_bo_unreference(batch->bo); 136 batch->bo = NULL; 137 free(batch); 138} 139 140static void 141measure_start_snapshot(struct iris_context *ice, 142 struct iris_batch *batch, 143 enum intel_measure_snapshot_type type, 144 const char *event_name, 145 uint32_t count) 146{ 147 struct intel_measure_batch *measure_batch = &batch->measure->base; 148 const struct intel_measure_config *config = config_from_context(ice); 149 const struct iris_screen *screen = (void *) ice->ctx.screen; 150 const unsigned screen_frame = screen->measure.frame; 151 152 /* if the command buffer is not associated with a frame, associate it with 153 * the most recent acquired frame 154 */ 155 if (measure_batch->frame == 0) 156 measure_batch->frame = screen_frame; 157 158 uintptr_t framebuffer = measure_batch->framebuffer; 159 160 if (measure_batch->index == config->batch_size) { 161 /* Snapshot buffer is full. The batch must be flushed before additional 162 * snapshots can be taken. 163 */ 164 static bool warned = false; 165 if (unlikely(!warned)) { 166 fprintf(config->file, 167 "WARNING: batch size exceeds INTEL_MEASURE limit: %d. " 168 "Data has been dropped. " 169 "Increase setting with INTEL_MEASURE=batch_size={count}\n", 170 config->batch_size); 171 warned = true; 172 } 173 return; 174 } 175 176 unsigned index = measure_batch->index++; 177 assert(index < config->batch_size); 178 iris_emit_pipe_control_write(batch, "measurement snapshot", 179 PIPE_CONTROL_WRITE_TIMESTAMP | 180 PIPE_CONTROL_CS_STALL, 181 batch->measure->bo, index * sizeof(uint64_t), 0ull); 182 if (event_name == NULL) 183 event_name = intel_measure_snapshot_string(type); 184 185 struct intel_measure_snapshot *snapshot = &(measure_batch->snapshots[index]); 186 memset(snapshot, 0, sizeof(*snapshot)); 187 snapshot->type = type; 188 snapshot->count = (unsigned) count; 189 snapshot->event_count = measure_batch->event_count; 190 snapshot->event_name = event_name; 191 snapshot->framebuffer = framebuffer; 192 193 if (type == INTEL_SNAPSHOT_COMPUTE) { 194 snapshot->cs = (uintptr_t) ice->shaders.prog[MESA_SHADER_COMPUTE]; 195 } else { 196 snapshot->vs = (uintptr_t) ice->shaders.prog[MESA_SHADER_VERTEX]; 197 snapshot->tcs = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_CTRL]; 198 snapshot->tes = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_EVAL]; 199 snapshot->gs = (uintptr_t) ice->shaders.prog[MESA_SHADER_GEOMETRY]; 200 snapshot->fs = (uintptr_t) ice->shaders.prog[MESA_SHADER_FRAGMENT]; 201 } 202} 203 204static void 205measure_end_snapshot(struct iris_batch *batch, 206 uint32_t event_count) 207{ 208 struct intel_measure_batch *measure_batch = &batch->measure->base; 209 210 unsigned index = measure_batch->index++; 211 assert(index % 2 == 1); 212 213 iris_emit_pipe_control_write(batch, "measurement snapshot", 214 PIPE_CONTROL_WRITE_TIMESTAMP | 215 PIPE_CONTROL_CS_STALL, 216 batch->measure->bo, 217 index * sizeof(uint64_t), 0ull); 218 219 struct intel_measure_snapshot *snapshot = &(measure_batch->snapshots[index]); 220 memset(snapshot, 0, sizeof(*snapshot)); 221 snapshot->type = INTEL_SNAPSHOT_END; 222 snapshot->event_count = event_count; 223} 224 225static bool 226state_changed(const struct iris_context *ice, 227 const struct iris_batch *batch, 228 enum intel_measure_snapshot_type type) 229{ 230 uintptr_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0; 231 232 if (type == INTEL_SNAPSHOT_COMPUTE) { 233 cs = (uintptr_t) ice->shaders.prog[MESA_SHADER_COMPUTE]; 234 } else if (type == INTEL_SNAPSHOT_DRAW) { 235 vs = (uintptr_t) ice->shaders.prog[MESA_SHADER_VERTEX]; 236 tcs = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_CTRL]; 237 tes = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_EVAL]; 238 gs = (uintptr_t) ice->shaders.prog[MESA_SHADER_GEOMETRY]; 239 fs = (uintptr_t) ice->shaders.prog[MESA_SHADER_FRAGMENT]; 240 } 241 /* else blorp, all programs NULL */ 242 243 return intel_measure_state_changed(&batch->measure->base, 244 vs, tcs, tes, gs, fs, cs); 245} 246 247static void 248iris_measure_renderpass(struct iris_context *ice) 249{ 250 const struct intel_measure_config *config = config_from_context(ice); 251 struct intel_measure_batch *batch = 252 &ice->batches[IRIS_BATCH_RENDER].measure->base; 253 254 if (!config) 255 return; 256 uint32_t framebuffer_crc = util_hash_crc32(&ice->state.framebuffer, 257 sizeof(ice->state.framebuffer)); 258 if (framebuffer_crc == batch->framebuffer) 259 return; 260 bool filtering = config->flags & INTEL_MEASURE_RENDERPASS; 261 if (filtering && batch->index % 2 == 1) { 262 /* snapshot for previous renderpass was not ended */ 263 measure_end_snapshot(&ice->batches[IRIS_BATCH_RENDER], 264 batch->event_count); 265 batch->event_count = 0; 266 } 267 268 batch->framebuffer = framebuffer_crc; 269} 270 271void 272_iris_measure_snapshot(struct iris_context *ice, 273 struct iris_batch *batch, 274 enum intel_measure_snapshot_type type, 275 const struct pipe_draw_info *draw, 276 const struct pipe_draw_indirect_info *indirect, 277 const struct pipe_draw_start_count_bias *sc) 278{ 279 280 const struct intel_measure_config *config = config_from_context(ice); 281 struct intel_measure_batch* measure_batch = &batch->measure->base; 282 283 assert(config); 284 if (!config->enabled) 285 return; 286 if (measure_batch == NULL) 287 return; 288 289 assert(type != INTEL_SNAPSHOT_END); 290 iris_measure_renderpass(ice); 291 292 if (!state_changed(ice, batch, type)) { 293 /* filter out this event */ 294 return; 295 } 296 297 /* increment event count */ 298 ++measure_batch->event_count; 299 if (measure_batch->event_count == 1 || 300 measure_batch->event_count == config->event_interval + 1) { 301 /* the first event of an interval */ 302 if (measure_batch->index % 2) { 303 /* end the previous event */ 304 measure_end_snapshot(batch, measure_batch->event_count - 1); 305 } 306 measure_batch->event_count = 1; 307 308 const char *event_name = NULL; 309 int count = 0; 310 if (sc) 311 count = sc->count; 312 313 if (draw != NULL) { 314 const struct shader_info *fs_info = 315 iris_get_shader_info(ice, MESA_SHADER_FRAGMENT); 316 if (fs_info && fs_info->name && strncmp(fs_info->name, "st/", 2) == 0) { 317 event_name = fs_info->name; 318 } else if (indirect) { 319 event_name = "DrawIndirect"; 320 if (indirect->count_from_stream_output) { 321 event_name = "DrawTransformFeedback"; 322 } 323 } 324 else if (draw->index_size) 325 event_name = "DrawElements"; 326 else 327 event_name = "DrawArrays"; 328 count = count * (draw->instance_count ? draw->instance_count : 1); 329 } 330 331 measure_start_snapshot(ice, batch, type, event_name, count); 332 return; 333 } 334} 335 336void 337iris_destroy_ctx_measure(struct iris_context *ice) 338{ 339 /* All outstanding snapshots must be collected before the context is 340 * destroyed. 341 */ 342 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen; 343 intel_measure_gather(&screen->measure, &screen->devinfo); 344} 345 346void 347iris_measure_batch_end(struct iris_context *ice, struct iris_batch *batch) 348{ 349 const struct intel_measure_config *config = config_from_context(ice); 350 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen; 351 struct iris_measure_batch *iris_measure_batch = batch->measure; 352 struct intel_measure_batch *measure_batch = &iris_measure_batch->base; 353 struct intel_measure_device *measure_device = &screen->measure; 354 355 if (!config) 356 return; 357 if (!config->enabled) 358 return; 359 360 assert(measure_batch); 361 assert(measure_device); 362 363 static unsigned batch_count = 0; 364 measure_batch->batch_count = p_atomic_inc_return(&batch_count); 365 366 if (measure_batch->index % 2) { 367 /* We hit the end of the batch, but never terminated our section of 368 * drawing with the same render target or shaders. End it now. 369 */ 370 measure_end_snapshot(batch, measure_batch->event_count); 371 } 372 373 if (measure_batch->index == 0) 374 return; 375 376 /* enqueue snapshot for gathering */ 377 pthread_mutex_lock(&measure_device->mutex); 378 list_addtail(&iris_measure_batch->base.link, &measure_device->queued_snapshots); 379 batch->measure = NULL; 380 pthread_mutex_unlock(&measure_device->mutex); 381 /* init new measure_batch */ 382 iris_init_batch_measure(ice, batch); 383 384 static int interval = 0; 385 if (++interval > 10) { 386 intel_measure_gather(measure_device, &screen->devinfo); 387 interval = 0; 388 } 389} 390 391void 392iris_measure_frame_end(struct iris_context *ice) 393{ 394 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen; 395 struct intel_measure_device *measure_device = &screen->measure; 396 const struct intel_measure_config *config = measure_device->config; 397 398 if (!config) 399 return; 400 401 /* increment frame counter */ 402 intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame)); 403 404 intel_measure_gather(measure_device, &screen->devinfo); 405} 406