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