• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->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->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, measure->bo, index * sizeof(uint64_t));
162 
163    if (event_name == NULL)
164       event_name = intel_measure_snapshot_string(type);
165 
166    struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);
167    memset(snapshot, 0, sizeof(*snapshot));
168    snapshot->type = type;
169    snapshot->count = (unsigned) count;
170    snapshot->event_count = measure->base.event_count;
171    snapshot->event_name = event_name;
172    snapshot->framebuffer = framebuffer;
173 
174    if (type == INTEL_SNAPSHOT_COMPUTE && cmd_buffer->state.compute.pipeline) {
175       snapshot->cs = (uintptr_t) cmd_buffer->state.compute.pipeline->cs;
176    } else if (cmd_buffer->state.gfx.pipeline) {
177       const struct anv_graphics_pipeline *pipeline =
178          cmd_buffer->state.gfx.pipeline;
179       snapshot->vs = (uintptr_t) pipeline->shaders[MESA_SHADER_VERTEX];
180       snapshot->tcs = (uintptr_t) pipeline->shaders[MESA_SHADER_TESS_CTRL];
181       snapshot->tes = (uintptr_t) pipeline->shaders[MESA_SHADER_TESS_EVAL];
182       snapshot->gs = (uintptr_t) pipeline->shaders[MESA_SHADER_GEOMETRY];
183       snapshot->fs = (uintptr_t) pipeline->shaders[MESA_SHADER_FRAGMENT];
184    }
185 }
186 
187 static void
anv_measure_end_snapshot(struct anv_cmd_buffer * cmd_buffer,uint32_t event_count)188 anv_measure_end_snapshot(struct anv_cmd_buffer *cmd_buffer,
189                          uint32_t event_count)
190 {
191    struct anv_batch *batch = &cmd_buffer->batch;
192    struct anv_measure_batch *measure = cmd_buffer->measure;
193    struct anv_physical_device *device = cmd_buffer->device->physical;
194 
195    unsigned index = measure->base.index++;
196    assert(index % 2 == 1);
197 
198    (*device->cmd_emit_timestamp)(batch, measure->bo, index * sizeof(uint64_t));
199 
200    struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);
201    memset(snapshot, 0, sizeof(*snapshot));
202    snapshot->type = INTEL_SNAPSHOT_END;
203    snapshot->event_count = event_count;
204 }
205 
206 static bool
state_changed(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type)207 state_changed(struct anv_cmd_buffer *cmd_buffer,
208               enum intel_measure_snapshot_type type)
209 {
210    uintptr_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0;
211 
212    if (cmd_buffer->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)
213       /* can't record timestamps in this mode */
214       return false;
215 
216    if (type == INTEL_SNAPSHOT_COMPUTE) {
217       const struct anv_compute_pipeline *cs_pipe =
218          cmd_buffer->state.compute.pipeline;
219       assert(cs_pipe);
220       cs = (uintptr_t)cs_pipe->cs;
221    } else if (type == INTEL_SNAPSHOT_DRAW) {
222       const struct anv_graphics_pipeline *gfx = cmd_buffer->state.gfx.pipeline;
223       assert(gfx);
224       vs = (uintptr_t) gfx->shaders[MESA_SHADER_VERTEX];
225       tcs = (uintptr_t) gfx->shaders[MESA_SHADER_TESS_CTRL];
226       tes = (uintptr_t) gfx->shaders[MESA_SHADER_TESS_EVAL];
227       gs = (uintptr_t) gfx->shaders[MESA_SHADER_GEOMETRY];
228       fs = (uintptr_t) gfx->shaders[MESA_SHADER_FRAGMENT];
229    }
230    /* else blorp, all programs NULL */
231 
232    return intel_measure_state_changed(&cmd_buffer->measure->base,
233                                       vs, tcs, tes, gs, fs, cs);
234 }
235 
236 void
_anv_measure_snapshot(struct anv_cmd_buffer * cmd_buffer,enum intel_measure_snapshot_type type,const char * event_name,uint32_t count)237 _anv_measure_snapshot(struct anv_cmd_buffer *cmd_buffer,
238                      enum intel_measure_snapshot_type type,
239                      const char *event_name,
240                      uint32_t count)
241 {
242    struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
243    struct anv_measure_batch *measure = cmd_buffer->measure;
244 
245    assert(config);
246    if (measure == NULL)
247       return;
248 
249    assert(type != INTEL_SNAPSHOT_END);
250    if (!state_changed(cmd_buffer, type)) {
251       /* filter out this event */
252       return;
253    }
254 
255    /* increment event count */
256    ++measure->base.event_count;
257    if (measure->base.event_count == 1 ||
258        measure->base.event_count == config->event_interval + 1) {
259       /* the first event of an interval */
260 
261       if (measure->base.index % 2) {
262          /* end the previous event */
263          anv_measure_end_snapshot(cmd_buffer, measure->base.event_count - 1);
264       }
265       measure->base.event_count = 1;
266 
267       if (measure->base.index == config->batch_size) {
268          /* Snapshot buffer is full.  The batch must be flushed before
269           * additional snapshots can be taken.
270           */
271          static bool warned = false;
272          if (unlikely(!warned)) {
273             fprintf(config->file,
274                     "WARNING: batch size exceeds INTEL_MEASURE limit: %d. "
275                     "Data has been dropped. "
276                     "Increase setting with INTEL_MEASURE=batch_size={count}\n",
277                     config->batch_size);
278          }
279 
280          warned = true;
281          return;
282       }
283 
284       anv_measure_start_snapshot(cmd_buffer, type, event_name, count);
285    }
286 }
287 
288 /**
289  * Called when a command buffer is reset.  Re-initializes existing anv_measure
290  * data structures.
291  */
292 void
anv_measure_reset(struct anv_cmd_buffer * cmd_buffer)293 anv_measure_reset(struct anv_cmd_buffer *cmd_buffer)
294 {
295    struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
296    struct anv_device *device = cmd_buffer->device;
297    struct anv_measure_batch *measure = cmd_buffer->measure;
298 
299    if (!config)
300       return;
301 
302    if (!config->enabled) {
303       cmd_buffer->measure = NULL;
304       return;
305    }
306 
307    if (!measure) {
308       /* Capture has recently been enabled. Instead of resetting, a new data
309        * structure must be allocated and initialized.
310        */
311       return anv_measure_init(cmd_buffer);
312    }
313 
314    /* it is possible that the command buffer contains snapshots that have not
315     * yet been processed
316     */
317    intel_measure_gather(&device->physical->measure_device,
318                         &device->info);
319 
320    assert(cmd_buffer->device != NULL);
321 
322    measure->base.index = 0;
323    measure->base.framebuffer = 0;
324    measure->base.frame = 0;
325    measure->base.event_count = 0;
326    list_inithead(&measure->base.link);
327 
328    anv_device_release_bo(device, measure->bo);
329    ASSERTED VkResult result =
330       anv_device_alloc_bo(device, "measure data",
331                           config->batch_size * sizeof(uint64_t),
332                           ANV_BO_ALLOC_MAPPED,
333                           0,
334                           (struct anv_bo**)&measure->bo);
335    measure->base.timestamps = measure->bo->map;
336    assert(result == VK_SUCCESS);
337 }
338 
339 void
anv_measure_destroy(struct anv_cmd_buffer * cmd_buffer)340 anv_measure_destroy(struct anv_cmd_buffer *cmd_buffer)
341 {
342    struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
343    struct anv_measure_batch *measure = cmd_buffer->measure;
344    struct anv_device *device = cmd_buffer->device;
345    struct anv_physical_device *physical = device->physical;
346 
347    if (!config)
348       return;
349    if (measure == NULL)
350       return;
351 
352    /* it is possible that the command buffer contains snapshots that have not
353     * yet been processed
354     */
355    intel_measure_gather(&physical->measure_device, &physical->info);
356 
357    anv_device_release_bo(device, measure->bo);
358    vk_free(&cmd_buffer->pool->alloc, measure);
359    cmd_buffer->measure = NULL;
360 }
361 
362 static struct intel_measure_config*
config_from_device(struct anv_device * device)363 config_from_device(struct anv_device *device)
364 {
365    return device->physical->measure_device.config;
366 }
367 
368 void
anv_measure_device_destroy(struct anv_physical_device * device)369 anv_measure_device_destroy(struct anv_physical_device *device)
370 {
371    struct intel_measure_device *measure_device = &device->measure_device;
372    struct intel_measure_config *config = measure_device->config;
373 
374    if (!config)
375       return;
376 
377    if (measure_device->ringbuffer != NULL) {
378       vk_free(&device->instance->vk.alloc, measure_device->ringbuffer);
379       measure_device->ringbuffer = NULL;
380    }
381 }
382 
383 /**
384  *  Hook for command buffer submission.
385  */
386 void
_anv_measure_submit(struct anv_cmd_buffer * cmd_buffer)387 _anv_measure_submit(struct anv_cmd_buffer *cmd_buffer)
388 {
389    struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
390    struct anv_measure_batch *measure = cmd_buffer->measure;
391    struct intel_measure_device *measure_device = &cmd_buffer->device->physical->measure_device;
392 
393    if (!config)
394       return;
395    if (measure == NULL)
396       return;
397 
398    if (measure->base.index == 0)
399       /* no snapshots were started */
400       return;
401 
402    /* finalize snapshots and enqueue them */
403    static unsigned cmd_buffer_count = 0;
404    measure->base.batch_count = p_atomic_inc_return(&cmd_buffer_count);
405 
406    if (measure->base.index %2 == 1) {
407       anv_measure_end_snapshot(cmd_buffer, measure->base.event_count);
408       measure->base.event_count = 0;
409    }
410 
411    /* add to the list of submitted snapshots */
412    pthread_mutex_lock(&measure_device->mutex);
413    list_addtail(&measure->base.link, &measure_device->queued_snapshots);
414    pthread_mutex_unlock(&measure_device->mutex);
415 }
416 
417 /**
418  *  Hook for the start of a frame.
419  */
420 void
anv_measure_acquire(struct anv_device * device)421 anv_measure_acquire(struct anv_device *device)
422 {
423    struct intel_measure_config *config = config_from_device(device);
424    struct intel_measure_device *measure_device = &device->physical->measure_device;
425 
426    if (!config)
427       return;
428    if (measure_device == NULL)
429       return;
430 
431    intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame));
432 
433    /* iterate the queued snapshots and publish those that finished */
434    intel_measure_gather(measure_device, &device->physical->info);
435 }
436 
437 void
_anv_measure_endcommandbuffer(struct anv_cmd_buffer * cmd_buffer)438 _anv_measure_endcommandbuffer(struct anv_cmd_buffer *cmd_buffer)
439 {
440    struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
441    struct anv_measure_batch *measure = cmd_buffer->measure;
442 
443    if (!config)
444       return;
445    if (measure == NULL)
446       return;
447    if (measure->base.index % 2 == 0)
448       return;
449 
450    anv_measure_end_snapshot(cmd_buffer, measure->base.event_count);
451    measure->base.event_count = 0;
452 }
453 
454 void
_anv_measure_beginrenderpass(struct anv_cmd_buffer * cmd_buffer)455 _anv_measure_beginrenderpass(struct anv_cmd_buffer *cmd_buffer)
456 {
457    struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);
458    struct anv_measure_batch *measure = cmd_buffer->measure;
459 
460    if (!config)
461       return;
462    if (measure == NULL)
463       return;
464 
465    if (measure->base.framebuffer == (uintptr_t) cmd_buffer->state.framebuffer)
466       /* no change */
467       return;
468 
469    bool filtering = (config->flags & (INTEL_MEASURE_RENDERPASS |
470                                       INTEL_MEASURE_SHADER));
471    if (filtering && measure->base.index % 2 == 1) {
472       /* snapshot for previous renderpass was not ended */
473       anv_measure_end_snapshot(cmd_buffer,
474                                measure->base.event_count);
475       measure->base.event_count = 0;
476    }
477 
478    measure->base.framebuffer = (uintptr_t) cmd_buffer->state.framebuffer;
479 }
480 
481 void
_anv_measure_add_secondary(struct anv_cmd_buffer * primary,struct anv_cmd_buffer * secondary)482 _anv_measure_add_secondary(struct anv_cmd_buffer *primary,
483                            struct anv_cmd_buffer *secondary)
484 {
485    struct intel_measure_config *config = config_from_command_buffer(primary);
486    struct anv_measure_batch *measure = primary->measure;
487    if (!config)
488       return;
489    if (measure == NULL)
490       return;
491    if (config->flags & (INTEL_MEASURE_BATCH | INTEL_MEASURE_FRAME))
492       /* secondary timing will be contained within the primary */
493       return;
494    if (secondary->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
495          static bool warned = false;
496          if (unlikely(!warned)) {
497             fprintf(config->file,
498                     "WARNING: INTEL_MEASURE cannot capture timings of commands "
499                     "in secondary command buffers with "
500                     "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.\n");
501          }
502       return;
503    }
504 
505    if (measure->base.index % 2 == 1)
506       anv_measure_end_snapshot(primary, measure->base.event_count);
507 
508    struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[measure->base.index]);
509    _anv_measure_snapshot(primary, INTEL_SNAPSHOT_SECONDARY_BATCH, NULL, 0);
510 
511    snapshot->secondary = &secondary->measure->base;
512 }
513