From 1989e1e6d86b9a9dcdc3fc898366b8812409f9ca Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Wed, 15 Sep 2021 17:35:56 +0300 Subject: [PATCH] turnip/perfetto: handle gpu timestamps being non-monotonic Perfetto requires time in clock snaphots to be monotonic, otherwise the clock would be excluded. GPU timestamps start from zero after every suspend-resume cycle which makes them non-monotonic. As a solution on msm we check whether GPU was just resumed and remember previous highest timestamp to then add it to the next timestamps. If the functionality to get whether gpu is resumed is unavailable or doesn't work - we fallback to a check for a discontinuity in timestamps. For kgsl we always use fallback. Fixes renderstage timeline disappearing in AGI. Or you could avoid the issue altogether by preventing GPU from going to sleep by increasing auto suspend delay e.g.: echo 5000 > /sys/devices/platform/soc\@0/3d00000.gpu/power/autosuspend_delay_ms Signed-off-by: Danylo Piliaiev Part-of: --- src/freedreno/vulkan/tu_drm.c | 7 +++++ src/freedreno/vulkan/tu_kgsl.c | 8 ++++++ src/freedreno/vulkan/tu_perfetto.cc | 43 ++++++++++++++++++++++++++++- src/freedreno/vulkan/tu_perfetto.h | 4 +++ src/freedreno/vulkan/tu_private.h | 4 +++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/freedreno/vulkan/tu_drm.c b/src/freedreno/vulkan/tu_drm.c index c3b18e5a8b6..93307300a3c 100644 --- a/src/freedreno/vulkan/tu_drm.c +++ b/src/freedreno/vulkan/tu_drm.c @@ -120,6 +120,13 @@ tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts) return tu_drm_get_param(dev->physical_device, MSM_PARAM_TIMESTAMP, ts); } +int +tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count) +{ + int ret = tu_drm_get_param(dev->physical_device, MSM_PARAM_SUSPENDS, suspend_count); + return ret; +} + int tu_drm_submitqueue_new(const struct tu_device *dev, int priority, diff --git a/src/freedreno/vulkan/tu_kgsl.c b/src/freedreno/vulkan/tu_kgsl.c index e198947aa3e..e93e04d8a6a 100644 --- a/src/freedreno/vulkan/tu_kgsl.c +++ b/src/freedreno/vulkan/tu_kgsl.c @@ -663,6 +663,14 @@ tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts) return 0; } +int +tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count) +{ + /* kgsl doesn't have a way to get it */ + *suspend_count = 0; + return 0; +} + #ifdef ANDROID VKAPI_ATTR VkResult VKAPI_CALL tu_QueueSignalReleaseImageANDROID(VkQueue _queue, diff --git a/src/freedreno/vulkan/tu_perfetto.cc b/src/freedreno/vulkan/tu_perfetto.cc index 7e72bc999af..9973e6300ef 100644 --- a/src/freedreno/vulkan/tu_perfetto.cc +++ b/src/freedreno/vulkan/tu_perfetto.cc @@ -43,6 +43,11 @@ static uint64_t next_clock_sync_ns; /* cpu time of next clk sync */ */ static uint64_t sync_gpu_ts; +static uint64_t last_suspend_count; + +static uint64_t gpu_max_timestamp; +static uint64_t gpu_timestamp_offset; + struct TuRenderpassIncrementalState { bool was_cleared = true; }; @@ -73,6 +78,10 @@ public: */ gpu_clock_id = _mesa_hash_string("org.freedesktop.mesa.freedreno") | 0x80000000; + + gpu_timestamp_offset = 0; + gpu_max_timestamp = 0; + last_suspend_count = 0; } void OnStop(const StopArgs &) override @@ -156,7 +165,9 @@ stage_end(struct tu_device *dev, uint64_t ts_ns, enum tu_stage_id stage, auto packet = tctx.NewTracePacket(); - packet->set_timestamp(p->start_ts[stage]); + gpu_max_timestamp = MAX2(gpu_max_timestamp, ts_ns + gpu_timestamp_offset); + + packet->set_timestamp(p->start_ts[stage] + gpu_timestamp_offset); packet->set_timestamp_clock_id(gpu_clock_id); auto event = packet->set_gpu_render_stage_event(); @@ -201,9 +212,39 @@ sync_timestamp(struct tu_device *dev) return; } + uint64_t current_suspend_count = 0; + /* If we fail to get it we will use a fallback */ + tu_device_get_suspend_count(dev, ¤t_suspend_count); + /* convert GPU ts into ns: */ gpu_ts = tu_device_ticks_to_ns(dev, gpu_ts); + /* GPU timestamp is being reset after suspend-resume cycle. + * Perfetto requires clock snapshots to be monotonic, + * so we have to fix-up the time. + */ + if (current_suspend_count != last_suspend_count) { + gpu_timestamp_offset = gpu_max_timestamp; + last_suspend_count = current_suspend_count; + } + + gpu_ts += gpu_timestamp_offset; + + /* Fallback check, detect non-monotonic cases which would happen + * if we cannot retrieve suspend count. + */ + if (sync_gpu_ts > gpu_ts) { + gpu_ts += (gpu_max_timestamp - gpu_timestamp_offset); + gpu_timestamp_offset = gpu_max_timestamp; + } + + if (sync_gpu_ts > gpu_ts) { + PERFETTO_ELOG("Non-monotonic gpu timestamp detected, bailing out"); + return; + } + + gpu_max_timestamp = gpu_ts; + TuRenderpassDataSource::Trace([=](TuRenderpassDataSource::TraceContext tctx) { auto packet = tctx.NewTracePacket(); diff --git a/src/freedreno/vulkan/tu_perfetto.h b/src/freedreno/vulkan/tu_perfetto.h index a78dd7b7d44..3fa3ab63f72 100644 --- a/src/freedreno/vulkan/tu_perfetto.h +++ b/src/freedreno/vulkan/tu_perfetto.h @@ -100,6 +100,10 @@ int tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts); +int +tu_device_get_suspend_count(struct tu_device *dev, + uint64_t *suspend_count); + uint64_t tu_device_ticks_to_ns(struct tu_device *dev, uint64_t ts); diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 9a6d86ec144..eddcffda0c1 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -1731,6 +1731,10 @@ int tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts); +int +tu_device_get_suspend_count(struct tu_device *dev, + uint64_t *suspend_count); + int tu_drm_submitqueue_new(const struct tu_device *dev, int priority,