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/u_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 /* initialise list of measure structures that await rendering */
42 struct intel_measure_device *measure_device = &device->measure_device;
43 intel_measure_init(measure_device);
44 struct intel_measure_config *config = measure_device->config;
45 if (config == NULL)
46 return;
47
48 /* the final member of intel_measure_ringbuffer is a zero-length array of
49 * intel_measure_buffered_result objects. Allocate additional space for
50 * the buffered objects based on the run-time configurable buffer_size
51 */
52 const size_t rb_bytes = sizeof(struct intel_measure_ringbuffer) +
53 config->buffer_size * sizeof(struct intel_measure_buffered_result);
54 struct intel_measure_ringbuffer * rb =
55 vk_zalloc(&device->instance->vk.alloc,
56 rb_bytes, 8,
57 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
58 measure_device->ringbuffer = rb;
59 }
60
61 static struct intel_measure_config*
config_from_command_buffer(struct anv_cmd_buffer * cmd_buffer)62 config_from_command_buffer(struct anv_cmd_buffer *cmd_buffer)
63 {
64 return cmd_buffer->device->physical->measure_device.config;
65 }
66
67 void
anv_measure_init(struct anv_cmd_buffer * cmd_buffer)68 anv_measure_init(struct anv_cmd_buffer *cmd_buffer)
69 {
70 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
71 struct anv_device *device = cmd_buffer->device;
72
73 if (!config || !config->enabled) {
74 cmd_buffer->measure = NULL;
75 return;
76 }
77
78 /* the final member of anv_measure is a zero-length array of
79 * intel_measure_snapshot objects. Create additional space for the
80 * snapshot objects based on the run-time configurable batch_size
81 */
82 const size_t batch_bytes = sizeof(struct anv_measure_batch) +
83 config->batch_size * sizeof(struct intel_measure_snapshot);
84 struct anv_measure_batch * measure =
85 vk_alloc(&cmd_buffer->vk.pool->alloc,
86 batch_bytes, 8,
87 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
88
89 memset(measure, 0, batch_bytes);
90 cmd_buffer->measure = measure;
91 if(config->cpu_measure)
92 return;
93
94 ASSERTED VkResult result =
95 anv_device_alloc_bo(device, "measure data",
96 config->batch_size * sizeof(uint64_t),
97 ANV_BO_ALLOC_MAPPED |
98 ANV_BO_ALLOC_HOST_CACHED_COHERENT |
99 ANV_BO_ALLOC_INTERNAL,
100 0,
101 (struct anv_bo**)&measure->bo);
102 measure->base.timestamps = measure->bo->map;
103 assert(result == VK_SUCCESS);
104 }
105
106 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)107 anv_measure_start_snapshot(struct anv_cmd_buffer *cmd_buffer,
108 enum intel_measure_snapshot_type type,
109 const char *event_name,
110 uint32_t count)
111 {
112 struct anv_batch *batch = &cmd_buffer->batch;
113 struct anv_measure_batch *measure = cmd_buffer->measure;
114 struct anv_physical_device *device = cmd_buffer->device->physical;
115 struct intel_measure_device *measure_device = &device->measure_device;
116 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
117 enum anv_timestamp_capture_type capture_type;
118 unsigned index = measure->base.index++;
119
120 if (event_name == NULL)
121 event_name = intel_measure_snapshot_string(type);
122
123 if (config->cpu_measure) {
124 intel_measure_print_cpu_result(measure_device->frame,
125 measure->base.batch_count,
126 measure->base.batch_size,
127 index/2,
128 measure->base.event_count,
129 count,
130 event_name);
131 return;
132 }
133
134
135 if ((batch->engine_class == INTEL_ENGINE_CLASS_COPY) ||
136 (batch->engine_class == INTEL_ENGINE_CLASS_VIDEO))
137 capture_type = ANV_TIMESTAMP_CAPTURE_TOP_OF_PIPE;
138 else
139 capture_type = ANV_TIMESTAMP_CAPTURE_AT_CS_STALL;
140
141 (*device->cmd_emit_timestamp)(batch, cmd_buffer->device,
142 (struct anv_address) {
143 .bo = measure->bo,
144 .offset = index * sizeof(uint64_t) },
145 capture_type,
146 NULL);
147
148 struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);
149 memset(snapshot, 0, sizeof(*snapshot));
150 snapshot->type = type;
151 snapshot->count = (unsigned) count;
152 snapshot->event_count = measure->base.event_count;
153 snapshot->event_name = event_name;
154 snapshot->renderpass = (type == INTEL_SNAPSHOT_COMPUTE) ? 0
155 : measure->base.renderpass;
156
157 if (type == INTEL_SNAPSHOT_COMPUTE && cmd_buffer->state.compute.base.pipeline) {
158 const struct anv_compute_pipeline *pipeline =
159 anv_pipeline_to_compute(cmd_buffer->state.compute.base.pipeline);
160 snapshot->cs = pipeline->source_hash;
161 } else if (type == INTEL_SNAPSHOT_DRAW && cmd_buffer->state.gfx.base.pipeline) {
162 const struct anv_graphics_pipeline *pipeline =
163 anv_pipeline_to_graphics(cmd_buffer->state.gfx.base.pipeline);
164 snapshot->vs = pipeline->base.source_hashes[MESA_SHADER_VERTEX];
165 snapshot->tcs = pipeline->base.source_hashes[MESA_SHADER_TESS_CTRL];
166 snapshot->tes = pipeline->base.source_hashes[MESA_SHADER_TESS_EVAL];
167 snapshot->gs = pipeline->base.source_hashes[MESA_SHADER_GEOMETRY];
168 snapshot->fs = pipeline->base.source_hashes[MESA_SHADER_FRAGMENT];
169 snapshot->ms = pipeline->base.source_hashes[MESA_SHADER_MESH];
170 snapshot->ts = pipeline->base.source_hashes[MESA_SHADER_TASK];
171 }
172 }
173
174 static void
anv_measure_end_snapshot(struct anv_cmd_buffer * cmd_buffer,uint32_t event_count)175 anv_measure_end_snapshot(struct anv_cmd_buffer *cmd_buffer,
176 uint32_t event_count)
177 {
178 struct anv_batch *batch = &cmd_buffer->batch;
179 struct anv_measure_batch *measure = cmd_buffer->measure;
180 struct anv_physical_device *device = cmd_buffer->device->physical;
181 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
182 enum anv_timestamp_capture_type capture_type;
183 unsigned index = measure->base.index++;
184 assert(index % 2 == 1);
185
186 if (config->cpu_measure)
187 return;
188
189 if ((batch->engine_class == INTEL_ENGINE_CLASS_COPY) ||
190 (batch->engine_class == INTEL_ENGINE_CLASS_VIDEO))
191 capture_type = ANV_TIMESTAMP_CAPTURE_END_OF_PIPE;
192 else
193 capture_type = ANV_TIMESTAMP_CAPTURE_AT_CS_STALL;
194
195 (*device->cmd_emit_timestamp)(batch, cmd_buffer->device,
196 (struct anv_address) {
197 .bo = measure->bo,
198 .offset = index * sizeof(uint64_t) },
199 capture_type,
200 NULL);
201
202 struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);
203 memset(snapshot, 0, sizeof(*snapshot));
204 snapshot->type = INTEL_SNAPSHOT_END;
205 snapshot->event_count = event_count;
206 }
207
208 static bool
state_changed(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type)209 state_changed(struct anv_cmd_buffer *cmd_buffer,
210 enum intel_measure_snapshot_type type)
211 {
212 uint32_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0, ms=0, ts=0;
213
214 if (cmd_buffer->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)
215 /* can't record timestamps in this mode */
216 return false;
217
218 if (type == INTEL_SNAPSHOT_COMPUTE) {
219 const struct anv_compute_pipeline *cs_pipe =
220 anv_pipeline_to_compute(cmd_buffer->state.compute.base.pipeline);
221 assert(cs_pipe);
222 cs = cs_pipe->source_hash;
223 } else if (type == INTEL_SNAPSHOT_DRAW) {
224 const struct anv_graphics_pipeline *gfx =
225 anv_pipeline_to_graphics(cmd_buffer->state.gfx.base.pipeline);
226 assert(gfx);
227 vs = gfx->base.source_hashes[MESA_SHADER_VERTEX];
228 tcs = gfx->base.source_hashes[MESA_SHADER_TESS_CTRL];
229 tes = gfx->base.source_hashes[MESA_SHADER_TESS_EVAL];
230 gs = gfx->base.source_hashes[MESA_SHADER_GEOMETRY];
231 fs = gfx->base.source_hashes[MESA_SHADER_FRAGMENT];
232 ms = gfx->base.source_hashes[MESA_SHADER_MESH];
233 ts = gfx->base.source_hashes[MESA_SHADER_TASK];
234 }
235 /* else blorp, all programs NULL */
236
237 return intel_measure_state_changed(&cmd_buffer->measure->base,
238 vs, tcs, tes, gs, fs, cs, ms, ts);
239 }
240
241 void
_anv_measure_snapshot(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type,const char * event_name,uint32_t count)242 _anv_measure_snapshot(struct anv_cmd_buffer *cmd_buffer,
243 enum intel_measure_snapshot_type type,
244 const char *event_name,
245 uint32_t count)
246 {
247 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
248 struct anv_measure_batch *measure = cmd_buffer->measure;
249
250 assert(config);
251 if (measure == NULL)
252 return;
253
254 assert(type != INTEL_SNAPSHOT_END);
255 if (!state_changed(cmd_buffer, type)) {
256 /* filter out this event */
257 return;
258 }
259
260 /* increment event count */
261 ++measure->base.event_count;
262 if (measure->base.event_count == 1 ||
263 measure->base.event_count == config->event_interval + 1) {
264 /* the first event of an interval */
265
266 if (measure->base.index % 2) {
267 /* end the previous event */
268 anv_measure_end_snapshot(cmd_buffer, measure->base.event_count - 1);
269 }
270 measure->base.event_count = 1;
271
272 if (measure->base.index == config->batch_size) {
273 /* Snapshot buffer is full. The batch must be flushed before
274 * additional snapshots can be taken.
275 */
276 static bool warned = false;
277 if (unlikely(!warned)) {
278 fprintf(config->file,
279 "WARNING: batch size exceeds INTEL_MEASURE limit: %d. "
280 "Data has been dropped. "
281 "Increase setting with INTEL_MEASURE=batch_size={count}\n",
282 config->batch_size);
283 }
284
285 warned = true;
286 return;
287 }
288
289 anv_measure_start_snapshot(cmd_buffer, type, event_name, count);
290 }
291 }
292
293 /**
294 * Called when a command buffer is reset. Re-initializes existing anv_measure
295 * data structures.
296 */
297 void
anv_measure_reset(struct anv_cmd_buffer * cmd_buffer)298 anv_measure_reset(struct anv_cmd_buffer *cmd_buffer)
299 {
300 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
301 struct anv_device *device = cmd_buffer->device;
302 struct anv_measure_batch *measure = cmd_buffer->measure;
303
304 if (!config)
305 return;
306
307 if (!config->enabled) {
308 cmd_buffer->measure = NULL;
309 return;
310 }
311
312 if (!measure) {
313 /* Capture has recently been enabled. Instead of resetting, a new data
314 * structure must be allocated and initialized.
315 */
316 return anv_measure_init(cmd_buffer);
317 }
318
319 /* it is possible that the command buffer contains snapshots that have not
320 * yet been processed
321 */
322 intel_measure_gather(&device->physical->measure_device,
323 device->info);
324
325 assert(cmd_buffer->device != NULL);
326
327 measure->base.index = 0;
328 measure->base.renderpass = 0;
329 measure->base.frame = 0;
330 measure->base.event_count = 0;
331 list_inithead(&measure->base.link);
332 }
333
334 void
anv_measure_destroy(struct anv_cmd_buffer * cmd_buffer)335 anv_measure_destroy(struct anv_cmd_buffer *cmd_buffer)
336 {
337 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
338 struct anv_measure_batch *measure = cmd_buffer->measure;
339 struct anv_device *device = cmd_buffer->device;
340 struct anv_physical_device *physical = device->physical;
341
342 if (!config)
343 return;
344 if (measure == NULL)
345 return;
346
347 /* it is possible that the command buffer contains snapshots that have not
348 * yet been processed
349 */
350 intel_measure_gather(&physical->measure_device, &physical->info);
351
352 if (measure->bo != NULL)
353 anv_device_release_bo(device, measure->bo);
354 vk_free(&cmd_buffer->vk.pool->alloc, measure);
355 cmd_buffer->measure = NULL;
356 }
357
358 static struct intel_measure_config*
config_from_device(struct anv_device * device)359 config_from_device(struct anv_device *device)
360 {
361 return device->physical->measure_device.config;
362 }
363
364 void
anv_measure_device_destroy(struct anv_physical_device * device)365 anv_measure_device_destroy(struct anv_physical_device *device)
366 {
367 struct intel_measure_device *measure_device = &device->measure_device;
368 struct intel_measure_config *config = measure_device->config;
369
370 if (!config)
371 return;
372
373 if (measure_device->ringbuffer != NULL) {
374 vk_free(&device->instance->vk.alloc, measure_device->ringbuffer);
375 measure_device->ringbuffer = NULL;
376 }
377 }
378
379 /**
380 * Hook for command buffer submission.
381 */
382 void
_anv_measure_submit(struct anv_cmd_buffer * cmd_buffer)383 _anv_measure_submit(struct anv_cmd_buffer *cmd_buffer)
384 {
385 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
386 struct anv_measure_batch *measure = cmd_buffer->measure;
387 struct intel_measure_device *measure_device = &cmd_buffer->device->physical->measure_device;
388 struct intel_measure_batch *base = &measure->base;
389
390 if (!config ||
391 measure == NULL ||
392 base->index == 0 /* no snapshots were started */ )
393 return;
394
395 if (measure->base.link.next->prev != measure->base.link.next->next) {
396 fprintf(stderr, "INTEL_MEASURE: not tracking events from reused"
397 "command buffer without reset. Not supported.\n");
398 return;
399 }
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 base->batch_size = cmd_buffer->total_batch_size;
405 base->frame = measure_device->frame;
406
407 if (base->index %2 == 1) {
408 anv_measure_end_snapshot(cmd_buffer, base->event_count);
409 base->event_count = 0;
410 }
411
412 if (config->cpu_measure)
413 return;
414
415 /* Mark the final timestamp as 'not completed'. This marker will be used
416 * to verify that rendering is complete.
417 */
418 base->timestamps[base->index - 1] = 0;
419
420 /* add to the list of submitted snapshots */
421 pthread_mutex_lock(&measure_device->mutex);
422 list_addtail(&measure->base.link, &measure_device->queued_snapshots);
423 pthread_mutex_unlock(&measure_device->mutex);
424 }
425
426 /**
427 * Hook for the start of a frame.
428 */
429 void
_anv_measure_acquire(struct anv_device * device)430 _anv_measure_acquire(struct anv_device *device)
431 {
432 struct intel_measure_config *config = config_from_device(device);
433 struct intel_measure_device *measure_device = &device->physical->measure_device;
434
435 if (!config)
436 return;
437 if (measure_device == NULL)
438 return;
439
440 intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame));
441
442 /* iterate the queued snapshots and publish those that finished */
443 intel_measure_gather(measure_device, &device->physical->info);
444 }
445
446 void
_anv_measure_endcommandbuffer(struct anv_cmd_buffer * cmd_buffer)447 _anv_measure_endcommandbuffer(struct anv_cmd_buffer *cmd_buffer)
448 {
449 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
450 struct anv_measure_batch *measure = cmd_buffer->measure;
451
452 if (!config)
453 return;
454 if (measure == NULL)
455 return;
456 if (measure->base.index % 2 == 0)
457 return;
458
459 anv_measure_end_snapshot(cmd_buffer, measure->base.event_count);
460 measure->base.event_count = 0;
461 }
462
463 void
_anv_measure_beginrenderpass(struct anv_cmd_buffer * cmd_buffer)464 _anv_measure_beginrenderpass(struct anv_cmd_buffer *cmd_buffer)
465 {
466 struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
467 struct anv_measure_batch *measure = cmd_buffer->measure;
468 struct anv_physical_device *device = cmd_buffer->device->physical;
469 struct intel_measure_device *measure_device = &device->measure_device;
470
471 if (!config || !measure)
472 return;
473
474 bool filtering = (config->flags & (INTEL_MEASURE_RENDERPASS |
475 INTEL_MEASURE_SHADER));
476 if (filtering && measure->base.index % 2 == 1) {
477 /* snapshot for previous renderpass was not ended */
478 anv_measure_end_snapshot(cmd_buffer,
479 measure->base.event_count);
480 measure->base.event_count = 0;
481 }
482
483 measure->base.renderpass =
484 (uintptr_t) p_atomic_inc_return(&measure_device->render_pass_count);
485 }
486
487 void
_anv_measure_add_secondary(struct anv_cmd_buffer * primary,struct anv_cmd_buffer * secondary)488 _anv_measure_add_secondary(struct anv_cmd_buffer *primary,
489 struct anv_cmd_buffer *secondary)
490 {
491 struct intel_measure_config *config = config_from_command_buffer(primary);
492 struct anv_measure_batch *measure = primary->measure;
493 if (!config)
494 return;
495 if (measure == NULL)
496 return;
497 if (config->flags & (INTEL_MEASURE_BATCH | INTEL_MEASURE_FRAME))
498 /* secondary timing will be contained within the primary */
499 return;
500 if (secondary->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
501 static bool warned = false;
502 if (unlikely(!warned)) {
503 fprintf(config->file,
504 "WARNING: INTEL_MEASURE cannot capture timings of commands "
505 "in secondary command buffers with "
506 "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.\n");
507 }
508 return;
509 }
510
511 if (measure->base.index % 2 == 1)
512 anv_measure_end_snapshot(primary, measure->base.event_count);
513
514 struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[measure->base.index]);
515 _anv_measure_snapshot(primary, INTEL_SNAPSHOT_SECONDARY_BATCH, NULL, 0);
516
517 snapshot->secondary = &secondary->measure->base;
518 }
519