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