turnip/trace: refactor creation and usage of trace flush data

Fixes the case when last cmd buffer in submission doesn't have
tracepoints leading to flush data not being freed.

Added a few comments, renamed things, refactored allocations - now
the data flow should be a bit more clean.

Extracted submission data creation into tu_u_trace_submission_data_create
which would be later used in in tu_kgsl.

Signed-off-by: Danylo Piliaiev <dpiliaiev@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14391>
This commit is contained in:
Danylo Piliaiev 2021-09-10 17:33:20 +03:00 committed by Marge Bot
parent 95896dee93
commit f2c53c2a9b
6 changed files with 150 additions and 84 deletions

View File

@ -1414,11 +1414,11 @@ tu_trace_read_ts(struct u_trace_context *utctx,
struct tu_device *device =
container_of(utctx, struct tu_device, trace_context);
struct tu_bo *bo = timestamps;
struct tu_u_trace_flush_data *trace_flush_data = flush_data;
struct tu_u_trace_submission_data *submission_data = flush_data;
/* Only need to stall on results for the first entry: */
if (idx == 0) {
tu_device_wait_u_trace(device, trace_flush_data->syncobj);
tu_device_wait_u_trace(device, submission_data->syncobj);
}
if (tu_bo_map(device, bo) != VK_SUCCESS) {
@ -1439,12 +1439,9 @@ tu_trace_delete_flush_data(struct u_trace_context *utctx, void *flush_data)
{
struct tu_device *device =
container_of(utctx, struct tu_device, trace_context);
struct tu_u_trace_flush_data *trace_flush_data = flush_data;
struct tu_u_trace_submission_data *submission_data = flush_data;
tu_u_trace_cmd_data_finish(device, trace_flush_data->cmd_trace_data,
trace_flush_data->trace_count);
vk_free(&device->vk.alloc, trace_flush_data->syncobj);
vk_free(&device->vk.alloc, trace_flush_data);
tu_u_trace_submission_data_finish(device, submission_data);
}
void
@ -1502,23 +1499,93 @@ tu_create_copy_timestamp_cs(struct tu_cmd_buffer *cmdbuf, struct tu_cs** cs,
return VK_SUCCESS;
}
void
tu_u_trace_cmd_data_finish(struct tu_device *device,
struct tu_u_trace_cmd_data *trace_data,
uint32_t entry_count)
VkResult
tu_u_trace_submission_data_create(
struct tu_device *device,
struct tu_cmd_buffer **cmd_buffers,
uint32_t cmd_buffer_count,
struct tu_u_trace_submission_data **submission_data)
{
for (uint32_t i = 0; i < entry_count; ++i) {
/* Only if we had to create a copy of trace we should free it */
if (trace_data[i].timestamp_copy_cs != NULL) {
tu_cs_finish(trace_data[i].timestamp_copy_cs);
vk_free(&device->vk.alloc, trace_data[i].timestamp_copy_cs);
*submission_data =
vk_zalloc(&device->vk.alloc,
sizeof(struct tu_u_trace_submission_data), 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
u_trace_fini(trace_data[i].trace);
vk_free(&device->vk.alloc, trace_data[i].trace);
if (!(*submission_data)) {
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
struct tu_u_trace_submission_data *data = *submission_data;
data->cmd_trace_data =
vk_zalloc(&device->vk.alloc,
cmd_buffer_count * sizeof(struct tu_u_trace_cmd_data), 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (!data->cmd_trace_data) {
goto fail;
}
data->cmd_buffer_count = cmd_buffer_count;
data->last_buffer_with_tracepoints = -1;
for (uint32_t i = 0; i < cmd_buffer_count; ++i) {
struct tu_cmd_buffer *cmdbuf = cmd_buffers[i];
if (!u_trace_has_points(&cmdbuf->trace))
continue;
data->last_buffer_with_tracepoints = i;
if (!(cmdbuf->usage_flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)) {
/* A single command buffer could be submitted several times, but we
* already baked timestamp iova addresses and trace points are
* single-use. Therefor we have to copy trace points and create
* a new timestamp buffer on every submit of reusable command buffer.
*/
if (tu_create_copy_timestamp_cs(cmdbuf,
&data->cmd_trace_data[i].timestamp_copy_cs,
&data->cmd_trace_data[i].trace) != VK_SUCCESS) {
goto fail;
}
assert(data->cmd_trace_data[i].timestamp_copy_cs->entry_count == 1);
} else {
data->cmd_trace_data[i].trace = &cmdbuf->trace;
}
}
vk_free(&device->vk.alloc, trace_data);
assert(data->last_buffer_with_tracepoints != -1);
return VK_SUCCESS;
fail:
tu_u_trace_submission_data_finish(device, data);
*submission_data = NULL;
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
void
tu_u_trace_submission_data_finish(
struct tu_device *device,
struct tu_u_trace_submission_data *submission_data)
{
for (uint32_t i = 0; i < submission_data->cmd_buffer_count; ++i) {
/* Only if we had to create a copy of trace we should free it */
struct tu_u_trace_cmd_data *cmd_data = &submission_data->cmd_trace_data[i];
if (cmd_data->timestamp_copy_cs) {
tu_cs_finish(cmd_data->timestamp_copy_cs);
vk_free(&device->vk.alloc, cmd_data->timestamp_copy_cs);
u_trace_fini(cmd_data->trace);
vk_free(&device->vk.alloc, cmd_data->trace);
}
}
vk_free(&device->vk.alloc, submission_data->cmd_trace_data);
vk_free(&device->vk.alloc, submission_data->syncobj);
vk_free(&device->vk.alloc, submission_data);
}
VKAPI_ATTR VkResult VKAPI_CALL

View File

@ -43,7 +43,7 @@
struct tu_queue_submit
{
struct vk_queue_submit *vk_submit;
struct tu_u_trace_cmd_data *cmd_buffer_trace_data;
struct tu_u_trace_submission_data *u_trace_submission_data;
struct drm_msm_gem_submit_cmd *cmds;
struct drm_msm_gem_submit_syncobj *in_syncobjs;
@ -751,35 +751,14 @@ tu_queue_submit_create_locked(struct tu_queue *queue,
}
if (has_trace_points) {
new_submit->cmd_buffer_trace_data = vk_zalloc(&queue->device->vk.alloc,
vk_submit->command_buffer_count * sizeof(struct tu_u_trace_cmd_data),
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
result =
tu_u_trace_submission_data_create(
queue->device, cmd_buffers,
vk_submit->command_buffer_count,
&new_submit->u_trace_submission_data);
if (new_submit->cmd_buffer_trace_data == NULL) {
result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail_cmd_trace_data;
}
for (uint32_t i = 0; i < vk_submit->command_buffer_count; ++i) {
struct tu_cmd_buffer *cmdbuf = cmd_buffers[i];
if (!(cmdbuf->usage_flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
u_trace_has_points(&cmdbuf->trace)) {
/* A single command buffer could be submitted several times, but we
* already backed timestamp iova addresses and trace points are
* single-use. Therefor we have to copy trace points and create
* a new timestamp buffer on every submit of reusable command buffer.
*/
if (tu_create_copy_timestamp_cs(cmdbuf,
&new_submit->cmd_buffer_trace_data[i].timestamp_copy_cs,
&new_submit->cmd_buffer_trace_data[i].trace) != VK_SUCCESS) {
result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail_copy_timestamp_cs;
}
assert(new_submit->cmd_buffer_trace_data[i].timestamp_copy_cs->entry_count == 1);
} else {
new_submit->cmd_buffer_trace_data[i].trace = &cmdbuf->trace;
}
if (result != VK_SUCCESS) {
goto fail_u_trace_submission_data;
}
}
@ -814,12 +793,10 @@ tu_queue_submit_create_locked(struct tu_queue *queue,
fail_out_syncobjs:
vk_free(&queue->device->vk.alloc, new_submit->in_syncobjs);
fail_in_syncobjs:
if (new_submit->cmd_buffer_trace_data)
tu_u_trace_cmd_data_finish(queue->device, new_submit->cmd_buffer_trace_data,
new_submit->vk_submit->command_buffer_count);
fail_copy_timestamp_cs:
vk_free(&queue->device->vk.alloc, new_submit->cmd_buffer_trace_data);
fail_cmd_trace_data:
if (new_submit->u_trace_submission_data)
tu_u_trace_submission_data_finish(queue->device,
new_submit->u_trace_submission_data);
fail_u_trace_submission_data:
vk_free(&queue->device->vk.alloc, new_submit->cmds);
fail_cmds:
return result;
@ -873,8 +850,9 @@ tu_queue_build_msm_gem_submit_cmds(struct tu_queue *queue,
cmds[entry_idx].relocs = 0;
}
if (submit->cmd_buffer_trace_data) {
struct tu_cs *ts_cs = submit->cmd_buffer_trace_data[j].timestamp_copy_cs;
if (submit->u_trace_submission_data) {
struct tu_cs *ts_cs =
submit->u_trace_submission_data->cmd_trace_data[j].timestamp_copy_cs;
if (ts_cs) {
cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
cmds[entry_idx].submit_idx =
@ -940,24 +918,29 @@ tu_queue_submit_locked(struct tu_queue *queue, struct tu_queue_submit *submit)
tu_perfetto_submit(queue->device, queue->device->submit_count);
#endif
if (submit->cmd_buffer_trace_data) {
struct tu_u_trace_flush_data *flush_data =
vk_alloc(&queue->device->vk.alloc, sizeof(struct tu_u_trace_flush_data),
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
flush_data->submission_id = queue->device->submit_count;
flush_data->syncobj =
if (submit->u_trace_submission_data) {
struct tu_u_trace_submission_data *submission_data =
submit->u_trace_submission_data;
submission_data->submission_id = queue->device->submit_count;
/* We have to allocate it here since it is different between drm/kgsl */
submission_data->syncobj =
vk_alloc(&queue->device->vk.alloc, sizeof(struct tu_u_trace_syncobj),
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
flush_data->syncobj->fence = req.fence;
flush_data->syncobj->msm_queue_id = queue->msm_queue_id;
submission_data->syncobj->fence = req.fence;
submission_data->syncobj->msm_queue_id = queue->msm_queue_id;
flush_data->cmd_trace_data = submit->cmd_buffer_trace_data;
flush_data->trace_count = submit->vk_submit->command_buffer_count;
submit->cmd_buffer_trace_data = NULL;
submit->u_trace_submission_data = NULL;
for (uint32_t i = 0; i < submit->vk_submit->command_buffer_count; i++) {
bool free_data = i == (submit->vk_submit->command_buffer_count - 1);
u_trace_flush(flush_data->cmd_trace_data[i].trace, flush_data, free_data);
bool free_data = i == submission_data->last_buffer_with_tracepoints;
if (submission_data->cmd_trace_data[i].trace)
u_trace_flush(submission_data->cmd_trace_data[i].trace,
submission_data, free_data);
if (!submission_data->cmd_trace_data[i].timestamp_copy_cs) {
/* u_trace is owned by cmd_buffer */
submission_data->cmd_trace_data[i].trace = NULL;
}
}
}

View File

@ -275,11 +275,11 @@ tu_end_##event_name(struct tu_device *dev, uint64_t ts_ns, \
const void *flush_data, \
const struct trace_end_##event_name *payload) \
{ \
auto trace_flush_data = (const struct tu_u_trace_flush_data *) flush_data; \
uint32_t submission_id = \
tu_u_trace_flush_data_get_submit_id(trace_flush_data); \
stage_end(dev, ts_ns, stage, submission_id, payload, \
(trace_payload_as_extra_func) &trace_payload_as_extra_end_##event_name);\
auto trace_flush_data = (const struct tu_u_trace_submission_data *) flush_data; \
uint32_t submission_id = \
tu_u_trace_submission_data_get_submit_id(trace_flush_data); \
stage_end(dev, ts_ns, stage, submission_id, payload, \
(trace_payload_as_extra_func) &trace_payload_as_extra_end_##event_name); \
}
CREATE_EVENT_CALLBACK(render_pass, SURFACE_STAGE_ID)

View File

@ -103,9 +103,9 @@ tu_device_get_timestamp(struct tu_device *dev,
uint64_t
tu_device_ticks_to_ns(struct tu_device *dev, uint64_t ts);
struct tu_u_trace_flush_data;
struct tu_u_trace_submission_data;
uint32_t
tu_u_trace_flush_data_get_submit_id(const struct tu_u_trace_flush_data *data);
tu_u_trace_submission_data_get_submit_id(const struct tu_u_trace_submission_data *data);
#endif

View File

@ -42,7 +42,7 @@ tu_device_get_timestamp(struct tu_device *dev,
}
uint32_t
tu_u_trace_flush_data_get_submit_id(const struct tu_u_trace_flush_data *data)
tu_u_trace_submission_data_get_submit_id(const struct tu_u_trace_submission_data *data)
{
return data->submission_id;
}

View File

@ -1759,25 +1759,41 @@ VkResult
tu_create_copy_timestamp_cs(struct tu_cmd_buffer *cmdbuf, struct tu_cs** cs,
struct u_trace **trace_copy);
/* If we copy trace and timestamps we will have to free them. */
struct tu_u_trace_cmd_data
{
struct tu_cs *timestamp_copy_cs;
struct u_trace *trace;
};
void
tu_u_trace_cmd_data_finish(struct tu_device *device,
struct tu_u_trace_cmd_data *trace_data,
uint32_t entry_count);
struct tu_u_trace_flush_data
/* Data necessary to retrieve timestamps and clean all
* associated resources afterwards.
*/
struct tu_u_trace_submission_data
{
uint32_t submission_id;
/* We have to know when timestamps are available,
* this sync object indicates it.
*/
struct tu_u_trace_syncobj *syncobj;
uint32_t trace_count;
uint32_t cmd_buffer_count;
uint32_t last_buffer_with_tracepoints;
struct tu_u_trace_cmd_data *cmd_trace_data;
};
VkResult
tu_u_trace_submission_data_create(
struct tu_device *device,
struct tu_cmd_buffer **cmd_buffers,
uint32_t cmd_buffer_count,
struct tu_u_trace_submission_data **submission_data);
void
tu_u_trace_submission_data_finish(
struct tu_device *device,
struct tu_u_trace_submission_data *submission_data);
#define TU_FROM_HANDLE(__tu_type, __name, __handle) \
VK_FROM_HANDLE(__tu_type, __name, __handle)