• 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/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