xref: /aosp_15_r20/external/mesa3d/src/intel/vulkan/anv_measure.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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