Path: blob/21.2-virgl/src/intel/vulkan/anv_measure.c
4547 views
/*1* Copyright © 2020 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*/2223#include "anv_measure.h"2425#include <fcntl.h>26#include <sys/stat.h>27#include <sys/types.h>2829#include "common/intel_measure.h"30#include "util/debug.h"3132struct anv_measure_batch {33struct anv_bo *bo;34struct intel_measure_batch base;35};3637void38anv_measure_device_init(struct anv_physical_device *device)39{40switch (device->info.verx10) {41case 125:42device->cmd_emit_timestamp = &gfx125_cmd_emit_timestamp;43break;44case 120:45device->cmd_emit_timestamp = &gfx12_cmd_emit_timestamp;46break;47case 110:48device->cmd_emit_timestamp = &gfx11_cmd_emit_timestamp;49break;50case 90:51device->cmd_emit_timestamp = &gfx9_cmd_emit_timestamp;52break;53case 80:54device->cmd_emit_timestamp = &gfx8_cmd_emit_timestamp;55break;56case 75:57device->cmd_emit_timestamp = &gfx75_cmd_emit_timestamp;58break;59case 70:60device->cmd_emit_timestamp = &gfx7_cmd_emit_timestamp;61break;62default:63assert(false);64}6566/* initialise list of measure structures that await rendering */67struct intel_measure_device *measure_device = &device->measure_device;68intel_measure_init(measure_device);69struct intel_measure_config *config = measure_device->config;70if (config == NULL)71return;7273/* the final member of intel_measure_ringbuffer is a zero-length array of74* intel_measure_buffered_result objects. Allocate additional space for75* the buffered objects based on the run-time configurable buffer_size76*/77const size_t rb_bytes = sizeof(struct intel_measure_ringbuffer) +78config->buffer_size * sizeof(struct intel_measure_buffered_result);79struct intel_measure_ringbuffer * rb =80vk_zalloc(&device->instance->vk.alloc,81rb_bytes, 8,82VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);83measure_device->ringbuffer = rb;84}8586static struct intel_measure_config*87config_from_command_buffer(struct anv_cmd_buffer *cmd_buffer)88{89return cmd_buffer->device->physical->measure_device.config;90}9192void93anv_measure_init(struct anv_cmd_buffer *cmd_buffer)94{95struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);96struct anv_device *device = cmd_buffer->device;9798if (!config || !config->enabled) {99cmd_buffer->measure = NULL;100return;101}102103/* the final member of anv_measure is a zero-length array of104* intel_measure_snapshot objects. Create additional space for the105* snapshot objects based on the run-time configurable batch_size106*/107const size_t batch_bytes = sizeof(struct anv_measure_batch) +108config->batch_size * sizeof(struct intel_measure_snapshot);109struct anv_measure_batch * measure =110vk_alloc(&cmd_buffer->pool->alloc,111batch_bytes, 8,112VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);113114memset(measure, 0, batch_bytes);115ASSERTED VkResult result =116anv_device_alloc_bo(device, "measure data",117config->batch_size * sizeof(uint64_t),118ANV_BO_ALLOC_MAPPED,1190,120(struct anv_bo**)&measure->bo);121measure->base.timestamps = measure->bo->map;122assert(result == VK_SUCCESS);123124cmd_buffer->measure = measure;125}126127static void128anv_measure_start_snapshot(struct anv_cmd_buffer *cmd_buffer,129enum intel_measure_snapshot_type type,130const char *event_name,131uint32_t count)132{133struct anv_batch *batch = &cmd_buffer->batch;134struct anv_measure_batch *measure = cmd_buffer->measure;135struct anv_physical_device *device = cmd_buffer->device->physical;136struct intel_measure_device *measure_device = &device->measure_device;137138const unsigned device_frame = measure_device->frame;139140/* if the command buffer is not associated with a frame, associate it with141* the most recent acquired frame142*/143if (measure->base.frame == 0)144measure->base.frame = device_frame;145146uintptr_t framebuffer = (uintptr_t)cmd_buffer->state.framebuffer;147148if (!measure->base.framebuffer &&149cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)150/* secondary command buffer inherited the framebuffer from the primary */151measure->base.framebuffer = framebuffer;152153/* verify framebuffer has been properly tracked */154assert(type == INTEL_SNAPSHOT_END ||155framebuffer == measure->base.framebuffer ||156framebuffer == 0 ); /* compute has no framebuffer */157158unsigned index = measure->base.index++;159160(*device->cmd_emit_timestamp)(batch, measure->bo, index * sizeof(uint64_t));161162if (event_name == NULL)163event_name = intel_measure_snapshot_string(type);164165struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);166memset(snapshot, 0, sizeof(*snapshot));167snapshot->type = type;168snapshot->count = (unsigned) count;169snapshot->event_count = measure->base.event_count;170snapshot->event_name = event_name;171snapshot->framebuffer = framebuffer;172173if (type == INTEL_SNAPSHOT_COMPUTE && cmd_buffer->state.compute.pipeline) {174snapshot->cs = (uintptr_t) cmd_buffer->state.compute.pipeline->cs;175} else if (cmd_buffer->state.gfx.pipeline) {176const struct anv_graphics_pipeline *pipeline =177cmd_buffer->state.gfx.pipeline;178snapshot->vs = (uintptr_t) pipeline->shaders[MESA_SHADER_VERTEX];179snapshot->tcs = (uintptr_t) pipeline->shaders[MESA_SHADER_TESS_CTRL];180snapshot->tes = (uintptr_t) pipeline->shaders[MESA_SHADER_TESS_EVAL];181snapshot->gs = (uintptr_t) pipeline->shaders[MESA_SHADER_GEOMETRY];182snapshot->fs = (uintptr_t) pipeline->shaders[MESA_SHADER_FRAGMENT];183}184}185186static void187anv_measure_end_snapshot(struct anv_cmd_buffer *cmd_buffer,188uint32_t event_count)189{190struct anv_batch *batch = &cmd_buffer->batch;191struct anv_measure_batch *measure = cmd_buffer->measure;192struct anv_physical_device *device = cmd_buffer->device->physical;193194unsigned index = measure->base.index++;195assert(index % 2 == 1);196197(*device->cmd_emit_timestamp)(batch, measure->bo, index * sizeof(uint64_t));198199struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[index]);200memset(snapshot, 0, sizeof(*snapshot));201snapshot->type = INTEL_SNAPSHOT_END;202snapshot->event_count = event_count;203}204205static bool206state_changed(struct anv_cmd_buffer *cmd_buffer,207enum intel_measure_snapshot_type type)208{209uintptr_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0;210211if (cmd_buffer->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)212/* can't record timestamps in this mode */213return false;214215if (type == INTEL_SNAPSHOT_COMPUTE) {216const struct anv_compute_pipeline *cs_pipe =217cmd_buffer->state.compute.pipeline;218assert(cs_pipe);219cs = (uintptr_t)cs_pipe->cs;220} else if (type == INTEL_SNAPSHOT_DRAW) {221const struct anv_graphics_pipeline *gfx = cmd_buffer->state.gfx.pipeline;222assert(gfx);223vs = (uintptr_t) gfx->shaders[MESA_SHADER_VERTEX];224tcs = (uintptr_t) gfx->shaders[MESA_SHADER_TESS_CTRL];225tes = (uintptr_t) gfx->shaders[MESA_SHADER_TESS_EVAL];226gs = (uintptr_t) gfx->shaders[MESA_SHADER_GEOMETRY];227fs = (uintptr_t) gfx->shaders[MESA_SHADER_FRAGMENT];228}229/* else blorp, all programs NULL */230231return intel_measure_state_changed(&cmd_buffer->measure->base,232vs, tcs, tes, gs, fs, cs);233}234235void236_anv_measure_snapshot(struct anv_cmd_buffer *cmd_buffer,237enum intel_measure_snapshot_type type,238const char *event_name,239uint32_t count)240{241struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);242struct anv_measure_batch *measure = cmd_buffer->measure;243244assert(config);245if (measure == NULL)246return;247248assert(type != INTEL_SNAPSHOT_END);249if (!state_changed(cmd_buffer, type)) {250/* filter out this event */251return;252}253254/* increment event count */255++measure->base.event_count;256if (measure->base.event_count == 1 ||257measure->base.event_count == config->event_interval + 1) {258/* the first event of an interval */259260if (measure->base.index % 2) {261/* end the previous event */262anv_measure_end_snapshot(cmd_buffer, measure->base.event_count - 1);263}264measure->base.event_count = 1;265266if (measure->base.index == config->batch_size) {267/* Snapshot buffer is full. The batch must be flushed before268* additional snapshots can be taken.269*/270static bool warned = false;271if (unlikely(!warned)) {272fprintf(config->file,273"WARNING: batch size exceeds INTEL_MEASURE limit: %d. "274"Data has been dropped. "275"Increase setting with INTEL_MEASURE=batch_size={count}\n",276config->batch_size);277}278279warned = true;280return;281}282283anv_measure_start_snapshot(cmd_buffer, type, event_name, count);284}285}286287/**288* Called when a command buffer is reset. Re-initializes existing anv_measure289* data structures.290*/291void292anv_measure_reset(struct anv_cmd_buffer *cmd_buffer)293{294struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);295struct anv_device *device = cmd_buffer->device;296struct anv_measure_batch *measure = cmd_buffer->measure;297298if (!config)299return;300301if (!config->enabled) {302cmd_buffer->measure = NULL;303return;304}305306if (!measure) {307/* Capture has recently been enabled. Instead of resetting, a new data308* structure must be allocated and initialized.309*/310return anv_measure_init(cmd_buffer);311}312313/* it is possible that the command buffer contains snapshots that have not314* yet been processed315*/316intel_measure_gather(&device->physical->measure_device,317&device->info);318319assert(cmd_buffer->device != NULL);320321measure->base.index = 0;322measure->base.framebuffer = 0;323measure->base.frame = 0;324measure->base.event_count = 0;325list_inithead(&measure->base.link);326327anv_device_release_bo(device, measure->bo);328ASSERTED VkResult result =329anv_device_alloc_bo(device, "measure data",330config->batch_size * sizeof(uint64_t),331ANV_BO_ALLOC_MAPPED,3320,333(struct anv_bo**)&measure->bo);334measure->base.timestamps = measure->bo->map;335assert(result == VK_SUCCESS);336}337338void339anv_measure_destroy(struct anv_cmd_buffer *cmd_buffer)340{341struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);342struct anv_measure_batch *measure = cmd_buffer->measure;343struct anv_device *device = cmd_buffer->device;344struct anv_physical_device *physical = device->physical;345346if (!config)347return;348if (measure == NULL)349return;350351/* it is possible that the command buffer contains snapshots that have not352* yet been processed353*/354intel_measure_gather(&physical->measure_device, &physical->info);355356anv_device_release_bo(device, measure->bo);357vk_free(&cmd_buffer->pool->alloc, measure);358cmd_buffer->measure = NULL;359}360361static struct intel_measure_config*362config_from_device(struct anv_device *device)363{364return device->physical->measure_device.config;365}366367void368anv_measure_device_destroy(struct anv_physical_device *device)369{370struct intel_measure_device *measure_device = &device->measure_device;371struct intel_measure_config *config = measure_device->config;372373if (!config)374return;375376if (measure_device->ringbuffer != NULL) {377vk_free(&device->instance->vk.alloc, measure_device->ringbuffer);378measure_device->ringbuffer = NULL;379}380}381382/**383* Hook for command buffer submission.384*/385void386_anv_measure_submit(struct anv_cmd_buffer *cmd_buffer)387{388struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);389struct anv_measure_batch *measure = cmd_buffer->measure;390struct intel_measure_device *measure_device = &cmd_buffer->device->physical->measure_device;391392if (!config)393return;394if (measure == NULL)395return;396397if (measure->base.index == 0)398/* no snapshots were started */399return;400401/* finalize snapshots and enqueue them */402static unsigned cmd_buffer_count = 0;403measure->base.batch_count = p_atomic_inc_return(&cmd_buffer_count);404405if (measure->base.index %2 == 1) {406anv_measure_end_snapshot(cmd_buffer, measure->base.event_count);407measure->base.event_count = 0;408}409410/* add to the list of submitted snapshots */411pthread_mutex_lock(&measure_device->mutex);412list_addtail(&measure->base.link, &measure_device->queued_snapshots);413pthread_mutex_unlock(&measure_device->mutex);414}415416/**417* Hook for the start of a frame.418*/419void420anv_measure_acquire(struct anv_device *device)421{422struct intel_measure_config *config = config_from_device(device);423struct intel_measure_device *measure_device = &device->physical->measure_device;424425if (!config)426return;427if (measure_device == NULL)428return;429430intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame));431432/* iterate the queued snapshots and publish those that finished */433intel_measure_gather(measure_device, &device->physical->info);434}435436void437_anv_measure_endcommandbuffer(struct anv_cmd_buffer *cmd_buffer)438{439struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);440struct anv_measure_batch *measure = cmd_buffer->measure;441442if (!config)443return;444if (measure == NULL)445return;446if (measure->base.index % 2 == 0)447return;448449anv_measure_end_snapshot(cmd_buffer, measure->base.event_count);450measure->base.event_count = 0;451}452453void454_anv_measure_beginrenderpass(struct anv_cmd_buffer *cmd_buffer)455{456struct intel_measure_config *config = config_from_command_buffer(cmd_buffer);457struct anv_measure_batch *measure = cmd_buffer->measure;458459if (!config)460return;461if (measure == NULL)462return;463464if (measure->base.framebuffer == (uintptr_t) cmd_buffer->state.framebuffer)465/* no change */466return;467468bool filtering = (config->flags & (INTEL_MEASURE_RENDERPASS |469INTEL_MEASURE_SHADER));470if (filtering && measure->base.index % 2 == 1) {471/* snapshot for previous renderpass was not ended */472anv_measure_end_snapshot(cmd_buffer,473measure->base.event_count);474measure->base.event_count = 0;475}476477measure->base.framebuffer = (uintptr_t) cmd_buffer->state.framebuffer;478}479480void481_anv_measure_add_secondary(struct anv_cmd_buffer *primary,482struct anv_cmd_buffer *secondary)483{484struct intel_measure_config *config = config_from_command_buffer(primary);485struct anv_measure_batch *measure = primary->measure;486if (!config)487return;488if (measure == NULL)489return;490if (config->flags & (INTEL_MEASURE_BATCH | INTEL_MEASURE_FRAME))491/* secondary timing will be contained within the primary */492return;493if (secondary->usage_flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {494static bool warned = false;495if (unlikely(!warned)) {496fprintf(config->file,497"WARNING: INTEL_MEASURE cannot capture timings of commands "498"in secondary command buffers with "499"VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.\n");500}501return;502}503504if (measure->base.index % 2 == 1)505anv_measure_end_snapshot(primary, measure->base.event_count);506507struct intel_measure_snapshot *snapshot = &(measure->base.snapshots[measure->base.index]);508_anv_measure_snapshot(primary, INTEL_SNAPSHOT_SECONDARY_BATCH, NULL, 0);509510snapshot->secondary = &secondary->measure->base;511}512513514