1 /*
2 * Copyright © 2020 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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "anv_measure.h"
25
26 #include <fcntl.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #include "common/intel_measure.h"
31 #include "util/debug.h"
32
33 struct anv_measure_batch {
34 struct anv_bo *bo;
35 struct intel_measure_batch base;
36 };
37
38 void
anv_measure_device_init(struct anv_physical_device * device)39 anv_measure_device_init(struct anv_physical_device *device)
40 {
41 switch (device->info.verx10) {
42 case 125:
43 device->cmd_emit_timestamp = &gfx125_cmd_emit_timestamp;
44 break;
45 case 120:
46 device->cmd_emit_timestamp = &gfx12_cmd_emit_timestamp;
47 break;
48 case 110:
49 device->cmd_emit_timestamp = &gfx11_cmd_emit_timestamp;
50 break;
51 case 90:
52 device->cmd_emit_timestamp = &gfx9_cmd_emit_timestamp;
53 break;
54 case 80:
55 device->cmd_emit_timestamp = &gfx8_cmd_emit_timestamp;
56 break;
57 case 75:
58 device->cmd_emit_timestamp = &gfx75_cmd_emit_timestamp;
59 break;
60 case 70:
61 device->cmd_emit_timestamp = &gfx7_cmd_emit_timestamp;
62 break;
63 default:
64 assert(false);
65 }
66
67 /* initialise list of measure structures that await rendering */
68 struct intel_measure_device *measure_device = &device->measure_device;
69 intel_measure_init(measure_device);
70 struct intel_measure_config *config = measure_device->config;
71 if (config == NULL)
72 return;
73
74 /* the final member of intel_measure_ringbuffer is a zero-length array of
75 * intel_measure_buffered_result objects. Allocate additional space for
76 * the buffered objects based on the run-time configurable buffer_size
77 */
78 const size_t rb_bytes = sizeof(struct intel_measure_ringbuffer) +
79 config->buffer_size * sizeof(struct intel_measure_buffered_result);
80 struct intel_measure_ringbuffer * rb =
81 vk_zalloc(&device->instance->vk.alloc,
82 rb_bytes, 8,
83 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
84 measure_device->ringbuffer = rb;
85 }
86
87 static struct intel_measure_config*
config_from_command_buffer(struct anv_cmd_buffer * cmd_buffer)88 config_from_command_buffer(struct anv_cmd_buffer *cmd_buffer)
89 {
90 return cmd_buffer->device->physical->measure_device.config;
91 }
92
93 void
anv_measure_init(struct anv_cmd_buffer * cmd_buffer)94 anv_measure_init(struct anv_cmd_buffer *cmd_buffer)
95 {
96 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
97 struct anv_device *device = cmd_buffer->device;
98
99 if (!config || !config->enabled) {
100 cmd_buffer->measure = NULL;
101 return;
102 }
103
104 /* the final member of anv_measure is a zero-length array of
105 * intel_measure_snapshot objects. Create additional space for the
106 * snapshot objects based on the run-time configurable batch_size
107 */
108 const size_t batch_bytes = sizeof(struct anv_measure_batch) +
109 config->batch_size * sizeof(struct intel_measure_snapshot);
110 struct anv_measure_batch * measure =
111 vk_alloc(&cmd_buffer->vk.pool->alloc,
112 batch_bytes, 8,
113 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
114
115 memset(measure, 0, batch_bytes);
116 ASSERTED VkResult result =
117 anv_device_alloc_bo(device, "measure data",
118 config->batch_size * sizeof(uint64_t),
119 ANV_BO_ALLOC_MAPPED,
120 0,
121 (struct anv_bo**)&measure->bo);
122 measure->base.timestamps = measure->bo->map;
123 assert(result == VK_SUCCESS);
124
125 cmd_buffer->measure = measure;
126 }
127
128 static void
anv_measure_start_snapshot(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type,const char * event_name,uint32_t count)129 anv_measure_start_snapshot(struct anv_cmd_buffer *cmd_buffer,
130 enum intel_measure_snapshot_type type,
131 const char *event_name,
132 uint32_t count)
133 {
134 struct anv_batch *batch = &cmd_buffer->batch;
135 struct anv_measure_batch *measure = cmd_buffer->measure;
136 struct anv_physical_device *device = cmd_buffer->device->physical;
137 struct intel_measure_device *measure_device = &device->measure_device;
138
139 const unsigned device_frame = measure_device->frame;
140
141 /* if the command buffer is not associated with a frame, associate it with
142 * the most recent acquired frame
143 */
144 if (measure->base.frame == 0)
145 measure->base.frame = device_frame;
146
147 // uintptr_t framebuffer = (uintptr_t)cmd_buffer->state.framebuffer;
148 //
149 // if (!measure->base.framebuffer &&
150 // cmd_buffer->vk.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)
151 // /* secondary command buffer inherited the framebuffer from the primary */
152 // measure->base.framebuffer = framebuffer;
153 //
154 // /* verify framebuffer has been properly tracked */
155 // assert(type == INTEL_SNAPSHOT_END ||
156 // framebuffer == measure->base.framebuffer ||
157 // framebuffer == 0 ); /* compute has no framebuffer */
158
159 unsigned index = measure->base.index++;
160
161 (*device->cmd_emit_timestamp)(batch, cmd_buffer->device,
162 (struct anv_address) {
163 .bo = measure->bo,
164 .offset = index * sizeof(uint64_t) },
165 true /* end_of_pipe */);
166
167 if (event_name == NULL)
168 event_name = intel_measure_snapshot_string(type);
169
170 struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);
171 memset(snapshot, 0, sizeof(*snapshot));
172 snapshot->type = type;
173 snapshot->count = (unsigned) count;
174 snapshot->event_count = measure->base.event_count;
175 snapshot->event_name = event_name;
176 // snapshot->framebuffer = framebuffer;
177
178 if (type == INTEL_SNAPSHOT_COMPUTE && cmd_buffer->state.compute.pipeline) {
179 snapshot->cs = (uintptr_t) cmd_buffer->state.compute.pipeline->cs;
180 } else if (cmd_buffer->state.gfx.pipeline) {
181 const struct anv_graphics_pipeline *pipeline =
182 cmd_buffer->state.gfx.pipeline;
183 snapshot->vs = (uintptr_t) pipeline->shaders[MESA_SHADER_VERTEX];
184 snapshot->tcs = (uintptr_t) pipeline->shaders[MESA_SHADER_TESS_CTRL];
185 snapshot->tes = (uintptr_t) pipeline->shaders[MESA_SHADER_TESS_EVAL];
186 snapshot->gs = (uintptr_t) pipeline->shaders[MESA_SHADER_GEOMETRY];
187 snapshot->fs = (uintptr_t) pipeline->shaders[MESA_SHADER_FRAGMENT];
188 }
189 }
190
191 static void
anv_measure_end_snapshot(struct anv_cmd_buffer * cmd_buffer,uint32_t event_count)192 anv_measure_end_snapshot(struct anv_cmd_buffer *cmd_buffer,
193 uint32_t event_count)
194 {
195 struct anv_batch *batch = &cmd_buffer->batch;
196 struct anv_measure_batch *measure = cmd_buffer->measure;
197 struct anv_physical_device *device = cmd_buffer->device->physical;
198
199 unsigned index = measure->base.index++;
200 assert(index % 2 == 1);
201
202 (*device->cmd_emit_timestamp)(batch, cmd_buffer->device,
203 (struct anv_address) {
204 .bo = measure->bo,
205 .offset = index * sizeof(uint64_t) },
206 true /* end_of_pipe */);
207
208 struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);
209 memset(snapshot, 0, sizeof(*snapshot));
210 snapshot->type = INTEL_SNAPSHOT_END;
211 snapshot->event_count = event_count;
212 }
213
214 static bool
state_changed(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type)215 state_changed(struct anv_cmd_buffer *cmd_buffer,
216 enum intel_measure_snapshot_type type)
217 {
218 uintptr_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0;
219
220 if (cmd_buffer->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)
221 /* can't record timestamps in this mode */
222 return false;
223
224 if (type == INTEL_SNAPSHOT_COMPUTE) {
225 const struct anv_compute_pipeline *cs_pipe =
226 cmd_buffer->state.compute.pipeline;
227 assert(cs_pipe);
228 cs = (uintptr_t)cs_pipe->cs;
229 } else if (type == INTEL_SNAPSHOT_DRAW) {
230 const struct anv_graphics_pipeline *gfx = cmd_buffer->state.gfx.pipeline;
231 assert(gfx);
232 vs = (uintptr_t) gfx->shaders[MESA_SHADER_VERTEX];
233 tcs = (uintptr_t) gfx->shaders[MESA_SHADER_TESS_CTRL];
234 tes = (uintptr_t) gfx->shaders[MESA_SHADER_TESS_EVAL];
235 gs = (uintptr_t) gfx->shaders[MESA_SHADER_GEOMETRY];
236 fs = (uintptr_t) gfx->shaders[MESA_SHADER_FRAGMENT];
237 }
238 /* else blorp, all programs NULL */
239
240 return intel_measure_state_changed(&cmd_buffer->measure->base,
241 vs, tcs, tes, gs, fs, cs);
242 }
243
244 void
_anv_measure_snapshot(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type,const char * event_name,uint32_t count)245 _anv_measure_snapshot(struct anv_cmd_buffer *cmd_buffer,
246 enum intel_measure_snapshot_type type,
247 const char *event_name,
248 uint32_t count)
249 {
250 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
251 struct anv_measure_batch *measure = cmd_buffer->measure;
252
253 assert(config);
254 if (measure == NULL)
255 return;
256
257 assert(type != INTEL_SNAPSHOT_END);
258 if (!state_changed(cmd_buffer, type)) {
259 /* filter out this event */
260 return;
261 }
262
263 /* increment event count */
264 ++measure->base.event_count;
265 if (measure->base.event_count == 1 ||
266 measure->base.event_count == config->event_interval + 1) {
267 /* the first event of an interval */
268
269 if (measure->base.index % 2) {
270 /* end the previous event */
271 anv_measure_end_snapshot(cmd_buffer, measure->base.event_count - 1);
272 }
273 measure->base.event_count = 1;
274
275 if (measure->base.index == config->batch_size) {
276 /* Snapshot buffer is full. The batch must be flushed before
277 * additional snapshots can be taken.
278 */
279 static bool warned = false;
280 if (unlikely(!warned)) {
281 fprintf(config->file,
282 "WARNING: batch size exceeds INTEL_MEASURE limit: %d. "
283 "Data has been dropped. "
284 "Increase setting with INTEL_MEASURE=batch_size={count}\n",
285 config->batch_size);
286 }
287
288 warned = true;
289 return;
290 }
291
292 anv_measure_start_snapshot(cmd_buffer, type, event_name, count);
293 }
294 }
295
296 /**
297 * Called when a command buffer is reset. Re-initializes existing anv_measure
298 * data structures.
299 */
300 void
anv_measure_reset(struct anv_cmd_buffer * cmd_buffer)301 anv_measure_reset(struct anv_cmd_buffer *cmd_buffer)
302 {
303 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
304 struct anv_device *device = cmd_buffer->device;
305 struct anv_measure_batch *measure = cmd_buffer->measure;
306
307 if (!config)
308 return;
309
310 if (!config->enabled) {
311 cmd_buffer->measure = NULL;
312 return;
313 }
314
315 if (!measure) {
316 /* Capture has recently been enabled. Instead of resetting, a new data
317 * structure must be allocated and initialized.
318 */
319 return anv_measure_init(cmd_buffer);
320 }
321
322 /* it is possible that the command buffer contains snapshots that have not
323 * yet been processed
324 */
325 intel_measure_gather(&device->physical->measure_device,
326 &device->info);
327
328 assert(cmd_buffer->device != NULL);
329
330 measure->base.index = 0;
331 // measure->base.framebuffer = 0;
332 measure->base.frame = 0;
333 measure->base.event_count = 0;
334 list_inithead(&measure->base.link);
335 }
336
337 void
anv_measure_destroy(struct anv_cmd_buffer * cmd_buffer)338 anv_measure_destroy(struct anv_cmd_buffer *cmd_buffer)
339 {
340 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
341 struct anv_measure_batch *measure = cmd_buffer->measure;
342 struct anv_device *device = cmd_buffer->device;
343 struct anv_physical_device *physical = device->physical;
344
345 if (!config)
346 return;
347 if (measure == NULL)
348 return;
349
350 /* it is possible that the command buffer contains snapshots that have not
351 * yet been processed
352 */
353 intel_measure_gather(&physical->measure_device, &physical->info);
354
355 anv_device_release_bo(device, measure->bo);
356 vk_free(&cmd_buffer->vk.pool->alloc, measure);
357 cmd_buffer->measure = NULL;
358 }
359
360 static struct intel_measure_config*
config_from_device(struct anv_device * device)361 config_from_device(struct anv_device *device)
362 {
363 return device->physical->measure_device.config;
364 }
365
366 void
anv_measure_device_destroy(struct anv_physical_device * device)367 anv_measure_device_destroy(struct anv_physical_device *device)
368 {
369 struct intel_measure_device *measure_device = &device->measure_device;
370 struct intel_measure_config *config = measure_device->config;
371
372 if (!config)
373 return;
374
375 if (measure_device->ringbuffer != NULL) {
376 vk_free(&device->instance->vk.alloc, measure_device->ringbuffer);
377 measure_device->ringbuffer = NULL;
378 }
379 }
380
381 /**
382 * Hook for command buffer submission.
383 */
384 void
_anv_measure_submit(struct anv_cmd_buffer * cmd_buffer)385 _anv_measure_submit(struct anv_cmd_buffer *cmd_buffer)
386 {
387 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
388 struct anv_measure_batch *measure = cmd_buffer->measure;
389 struct intel_measure_device *measure_device = &cmd_buffer->device->physical->measure_device;
390
391 if (!config)
392 return;
393 if (measure == NULL)
394 return;
395
396 struct intel_measure_batch *base = &measure->base;
397 if (base->index == 0)
398 /* no snapshots were started */
399 return;
400
401 /* finalize snapshots and enqueue them */
402 static unsigned cmd_buffer_count = 0;
403 base->batch_count = p_atomic_inc_return(&cmd_buffer_count);
404
405 if (base->index %2 == 1) {
406 anv_measure_end_snapshot(cmd_buffer, base->event_count);
407 base->event_count = 0;
408 }
409
410 /* Mark the final timestamp as 'not completed'. This marker will be used
411 * to verify that rendering is complete.
412 */
413 base->timestamps[base->index - 1] = 0;
414
415 /* add to the list of submitted snapshots */
416 pthread_mutex_lock(&measure_device->mutex);
417 list_addtail(&measure->base.link, &measure_device->queued_snapshots);
418 pthread_mutex_unlock(&measure_device->mutex);
419 }
420
421 /**
422 * Hook for the start of a frame.
423 */
424 void
_anv_measure_acquire(struct anv_device * device)425 _anv_measure_acquire(struct anv_device *device)
426 {
427 struct intel_measure_config *config = config_from_device(device);
428 struct intel_measure_device *measure_device = &device->physical->measure_device;
429
430 if (!config)
431 return;
432 if (measure_device == NULL)
433 return;
434
435 intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame));
436
437 /* iterate the queued snapshots and publish those that finished */
438 intel_measure_gather(measure_device, &device->physical->info);
439 }
440
441 void
_anv_measure_endcommandbuffer(struct anv_cmd_buffer * cmd_buffer)442 _anv_measure_endcommandbuffer(struct anv_cmd_buffer *cmd_buffer)
443 {
444 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
445 struct anv_measure_batch *measure = cmd_buffer->measure;
446
447 if (!config)
448 return;
449 if (measure == NULL)
450 return;
451 if (measure->base.index % 2 == 0)
452 return;
453
454 anv_measure_end_snapshot(cmd_buffer, measure->base.event_count);
455 measure->base.event_count = 0;
456 }
457
458 void
_anv_measure_beginrenderpass(struct anv_cmd_buffer * cmd_buffer)459 _anv_measure_beginrenderpass(struct anv_cmd_buffer *cmd_buffer)
460 {
461 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
462 struct anv_measure_batch *measure = cmd_buffer->measure;
463
464 if (!config)
465 return;
466 if (measure == NULL)
467 return;
468
469 // if (measure->base.framebuffer == (uintptr_t) cmd_buffer->state.framebuffer)
470 // /* no change */
471 // return;
472
473 bool filtering = (config->flags & (INTEL_MEASURE_RENDERPASS |
474 INTEL_MEASURE_SHADER));
475 if (filtering && measure->base.index % 2 == 1) {
476 /* snapshot for previous renderpass was not ended */
477 anv_measure_end_snapshot(cmd_buffer,
478 measure->base.event_count);
479 measure->base.event_count = 0;
480 }
481
482 // measure->base.framebuffer = (uintptr_t) cmd_buffer->state.framebuffer;
483 }
484
485 void
_anv_measure_add_secondary(struct anv_cmd_buffer * primary,struct anv_cmd_buffer * secondary)486 _anv_measure_add_secondary(struct anv_cmd_buffer *primary,
487 struct anv_cmd_buffer *secondary)
488 {
489 struct intel_measure_config *config = config_from_command_buffer(primary);
490 struct anv_measure_batch *measure = primary->measure;
491 if (!config)
492 return;
493 if (measure == NULL)
494 return;
495 if (config->flags & (INTEL_MEASURE_BATCH | INTEL_MEASURE_FRAME))
496 /* secondary timing will be contained within the primary */
497 return;
498 if (secondary->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
499 static bool warned = false;
500 if (unlikely(!warned)) {
501 fprintf(config->file,
502 "WARNING: INTEL_MEASURE cannot capture timings of commands "
503 "in secondary command buffers with "
504 "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.\n");
505 }
506 return;
507 }
508
509 if (measure->base.index % 2 == 1)
510 anv_measure_end_snapshot(primary, measure->base.event_count);
511
512 struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[measure->base.index]);
513 _anv_measure_snapshot(primary, INTEL_SNAPSHOT_SECONDARY_BATCH, NULL, 0);
514
515 snapshot->secondary = &secondary->measure->base;
516 }
517