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