From 940a2b03d94cfe5faf84070d8e737fbaa676a3f5 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 28 Apr 2026 09:41:57 +0300 Subject: [PATCH] libweston: Introduce Perfetto debug annotations Introduce a bunch of helper macros and flush function that allow in-situ debug annotation of Perfetto tracks. This introduces a STR, INT and FLOAT variants to stack debug annotations into a temporary array and have COMMIT to push that to Perfetto. There's a maximum imposed limit of 128 entries in the array. Users shouldn't be concerned with allocating char string arrays as COMMIT will basically flush all the data in the temporary array to Perfetto. Signed-off-by: Marius Vlad --- libweston/perfetto/u_perfetto.cc | 77 +++++++++++++++++ libweston/perfetto/u_perfetto.h | 46 +++++++++++ libweston/weston-trace.h | 137 +++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) diff --git a/libweston/perfetto/u_perfetto.cc b/libweston/perfetto/u_perfetto.cc index 9d0a2eb99..b7a96fd2a 100644 --- a/libweston/perfetto/u_perfetto.cc +++ b/libweston/perfetto/u_perfetto.cc @@ -151,6 +151,83 @@ util_perfetto_next_id(void) return p_atomic_inc_return(&util_perfetto_unique_id); } +static void +util_perfetto_flush_debug_annotation(perfetto::EventContext *ctx, + unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + if (nr_entries == 0) + return; + + for (unsigned int idx = 0; idx < nr_entries; idx++) { + switch (annots[idx].type) { + case WESTON_DEBUG_ANNOTATION_INT_VAL: + ctx->AddDebugAnnotation(annots[idx].key, annots[idx].ivalue); + break; + case WESTON_DEBUG_ANNOTATION_FLOAT_VAL: + ctx->AddDebugAnnotation(annots[idx].key, annots[idx].fvalue); + break; + case WESTON_DEBUG_ANNOTATION_STR_VAL: + ctx->AddDebugAnnotation(annots[idx].key, annots[idx].svalue); + break; + default: + break; + } + } + +} + +void +util_perfetto_trace_commit_debug_annots(uint64_t id, const char *name, + unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + if (id) { + TRACE_EVENT_INSTANT(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + perfetto::Flow::ProcessScoped(id), + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); + return; + } + + TRACE_EVENT_INSTANT(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); +} + +void +util_perfetto_trace_commit_annotate_func(const char *name, unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + TRACE_EVENT_BEGIN(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); +} + +void +util_perfetto_trace_commit_annotate_func_flow(uint64_t id, const char *name, + unsigned int nr_entries, + struct weston_debug_annotation *annots) +{ + TRACE_EVENT_BEGIN(UTIL_PERFETTO_CATEGORY_DEFAULT_STR, + nullptr, + perfetto::Flow::ProcessScoped(id), + [&](perfetto::EventContext ctx) { + ctx.event()->set_name(name); + util_perfetto_flush_debug_annotation(&ctx, nr_entries, annots); + }); +} + + class UtilPerfettoObserver : public perfetto::TrackEventSessionObserver { public: UtilPerfettoObserver() { perfetto::TrackEvent::AddSessionObserver(this); } diff --git a/libweston/perfetto/u_perfetto.h b/libweston/perfetto/u_perfetto.h index 576348fce..4c84b7250 100644 --- a/libweston/perfetto/u_perfetto.h +++ b/libweston/perfetto/u_perfetto.h @@ -39,6 +39,22 @@ extern "C" { #endif +enum weston_debug_annotation_type { + WESTON_DEBUG_ANNOTATION_INT_VAL, + WESTON_DEBUG_ANNOTATION_FLOAT_VAL, + WESTON_DEBUG_ANNOTATION_STR_VAL, +}; + +struct weston_debug_annotation { + const char *key; + enum weston_debug_annotation_type type; + union { + int ivalue; + float fvalue; + const char *svalue; + }; +}; + #ifdef HAVE_PERFETTO extern int util_perfetto_tracing_state; @@ -63,6 +79,15 @@ void util_perfetto_trace_full_begin(const char *name, uint64_t track_id, uint64_ void util_perfetto_trace_full_end(const char *name, uint64_t track_id, clockid_t clock, uint64_t timestamp); +void util_perfetto_trace_commit_debug_annots(uint64_t id, const char *name, + unsigned int entries, struct weston_debug_annotation *annots); + +void util_perfetto_trace_commit_annotate_func(const char *name, + unsigned int entries, struct weston_debug_annotation *annots); + +void util_perfetto_trace_commit_annotate_func_flow(uint64_t id, const char *name, + unsigned int entries, struct weston_debug_annotation *annots); + uint64_t util_perfetto_next_id(void); uint64_t util_perfetto_new_track(const char *name); @@ -104,6 +129,27 @@ util_perfetto_trace_full_end(const char *name, uint64_t track_id, clockid_t cloc { } +static inline void +util_perfetto_trace_commit_debug_annots(uint64_t id, const char *name, + unsigned int entries, + struct weston_debug_annotation *annots) +{ +} + +static inline void +util_perfetto_trace_commit_annotate_func(const char *name, + unsigned int entries, + struct weston_debug_annotation *annots) +{ +} + +static inline void +util_perfetto_trace_commit_annotate_func_flow(uint64_t id, const char *name, + unsigned int entries, + struct weston_debug_annotation *annots) +{ +} + static inline void util_perfetto_counter_set(const char *name, double value) { } diff --git a/libweston/weston-trace.h b/libweston/weston-trace.h index 154663157..b2ba55492 100644 --- a/libweston/weston-trace.h +++ b/libweston/weston-trace.h @@ -11,6 +11,7 @@ #define WESTON_TRACE_H #include "perfetto/u_perfetto.h" +#include #if defined(HAVE_PERFETTO) @@ -28,6 +29,9 @@ # endif #endif +/* maximum allowed debug annotations */ +#define WESTON_MAX_DEBUG_ANNOTS 128 + /* note that util_perfetto_is_tracing_enabled always returns false until * util_perfetto_init is called */ @@ -69,6 +73,53 @@ clock, timestamp); \ } while (0) +#define _WESTON_TRACE_BEGIN_ANNOTATION() \ + struct weston_debug_annotation __pd_annots[WESTON_MAX_DEBUG_ANNOTS]; \ + unsigned int __pd_i = 0 + +#define _WESTON_TRACE_ANNOTATE_ADD_INT(k, v) \ + weston_assert_u32_gt(NULL, WESTON_MAX_DEBUG_ANNOTS, __pd_i); \ + __pd_annots[__pd_i].type = WESTON_DEBUG_ANNOTATION_INT_VAL; \ + __pd_annots[__pd_i].ivalue = v; \ + __pd_annots[__pd_i].key = k; \ + __pd_i++ + +#define _WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) \ + weston_assert_u32_gt(NULL, WESTON_MAX_DEBUG_ANNOTS, __pd_i); \ + __pd_annots[__pd_i].type = WESTON_DEBUG_ANNOTATION_FLOAT_VAL; \ + __pd_annots[__pd_i].fvalue = v; \ + __pd_annots[__pd_i].key = k; \ + __pd_i++ + +#define _WESTON_TRACE_ANNOTATE_ADD_STR(k, v) \ + weston_assert_u32_gt(NULL, WESTON_MAX_DEBUG_ANNOTS, __pd_i); \ + __pd_annots[__pd_i].type = WESTON_DEBUG_ANNOTATION_STR_VAL; \ + __pd_annots[__pd_i].svalue = v; \ + __pd_annots[__pd_i].key = k; \ + __pd_i++ + +#define _WESTON_TRACE_COMMIT_ANNOTATION(id, name) \ + do { \ + if (unlikely(util_perfetto_is_tracing_enabled())) { \ + _weston_trace_scope_annotate_commit(id, name, &__pd_i, __pd_annots); \ + } \ + } while (0) + +/* annotated funcs */ +#define _WESTON_TRACE_ANNOTATE_FUNC_BEGIN(name, nr_entries, annots) \ + do { \ + if (unlikely(util_perfetto_is_tracing_enabled())) { \ + util_perfetto_trace_commit_annotate_func(name, *nr_entries, annots); \ + } \ + } while (0) + +#define _WESTON_TRACE_ANNOTATE_FUNC_BEGIN_FLOW(name, id, nr_entries, annots) \ + do { \ + if (unlikely(util_perfetto_is_tracing_enabled())) { \ + util_perfetto_trace_commit_annotate_func_flow(id, name, *nr_entries, annots); \ + } \ + } while (0) + #if __has_attribute(cleanup) && __has_attribute(unused) #define _WESTON_TRACE_SCOPE_VAR_CONCAT(name, suffix) name##suffix @@ -92,6 +143,16 @@ __attribute__((cleanup(_weston_trace_scope_end), unused)) = \ _weston_trace_scope_flow_begin(name, id) +#define _WESTON_TRACE_ANNOTATE_FUNC(name) \ + int _WESTON_TRACE_SCOPE_VAR(__LINE__) \ + __attribute__((cleanup(_weston_trace_scope_end), unused)) = \ + _weston_trace_annotate_func_begin(name, &__pd_i, __pd_annots) + +#define _WESTON_TRACE_ANNOTATE_FUNC_FLOW(id, name) \ + int _WESTON_TRACE_SCOPE_VAR(__LINE__) \ + __attribute__((cleanup(_weston_trace_scope_end), unused)) = \ + _weston_trace_annotate_func_begin_flow(name, id, &__pd_i, __pd_annots) + static inline int _weston_trace_scope_begin(const char *name) { @@ -108,6 +169,53 @@ _weston_trace_scope_flow_begin(const char *name, uint64_t *id) return 0; } +static inline void +_weston_trace_scope_annotate_commit(uint64_t *id, const char *name, + unsigned int *nr_entries, + struct weston_debug_annotation *annots) +{ + if (id && *id == 0) { + *id = util_perfetto_next_id(); + util_perfetto_trace_commit_debug_annots(*id, name, *nr_entries, annots); + goto reset_entries; + } + + util_perfetto_trace_commit_debug_annots(0, name, *nr_entries, annots); + + /* reset the array and counter */ +reset_entries: + memset(annots, 0, sizeof(struct weston_debug_annotation) * *nr_entries); + *nr_entries = 0; +} + +static inline int +_weston_trace_annotate_func_begin(const char *name, unsigned int *nr_entries, + struct weston_debug_annotation *annots) +{ + _WESTON_TRACE_ANNOTATE_FUNC_BEGIN(name, nr_entries, annots); + + /* reset the array and counter */ + memset(annots, 0, sizeof(struct weston_debug_annotation) * *nr_entries); + *nr_entries = 0; + return 0; +} + +static inline int +_weston_trace_annotate_func_begin_flow(const char *name, uint64_t *id, + unsigned int *nr_entries, + struct weston_debug_annotation *annots) +{ + if (*id == 0) + *id = util_perfetto_next_id(); + + _WESTON_TRACE_ANNOTATE_FUNC_BEGIN_FLOW(name, *id, nr_entries, annots); + + /* reset the array and counter */ + memset(annots, 0, sizeof(struct weston_debug_annotation) * *nr_entries); + *nr_entries = 0; + return 0; +} + static inline void _weston_trace_scope_end(int *scope) { @@ -130,6 +238,14 @@ _weston_trace_scope_end(int *scope) #define _WESTON_TRACE_TIMESTAMP_BEGIN(name, track_id, flow_id, clock, timestamp) #define _WESTON_TRACE_TIMESTAMP_END(name, track_id, clock, timestamp) +#define _WESTON_TRACE_BEGIN_ANNOTATION() +#define _WESTON_TRACE_COMMIT_ANNOTATION(id, name) +#define _WESTON_TRACE_ANNOTATE_ADD_INT(k, v) +#define _WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) +#define _WESTON_TRACE_ANNOTATE_ADD_STR(k, v) +#define _WESTON_TRACE_ANNOTATE_FUNC() +#define _WESTON_TRACE_ANNOTATE_FUNC_FLOW(id, name) + #endif /* HAVE_PERFETTO */ #define WESTON_TRACE_SCOPE(name) _WESTON_TRACE_SCOPE(name) @@ -142,4 +258,25 @@ _weston_trace_scope_end(int *scope) #define WESTON_TRACE_TIMESTAMP_END(name, track_id, clock, timestamp) \ _WESTON_TRACE_TIMESTAMP_END(name, track_id, clock, timestamp) +#define WESTON_TRACE_BEGIN_ANNOTATION() \ + _WESTON_TRACE_BEGIN_ANNOTATION() + +#define WESTON_TRACE_ANNOTATE_ADD_INT(k, v) \ + _WESTON_TRACE_ANNOTATE_ADD_INT(k, v) + +#define WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) \ + _WESTON_TRACE_ANNOTATE_ADD_FLOAT(k, v) + +#define WESTON_TRACE_ANNOTATE_ADD_STR(k, v) \ + _WESTON_TRACE_ANNOTATE_ADD_STR(k, v) + +#define WESTON_TRACE_COMMIT_ANNOTATION(id) \ + _WESTON_TRACE_COMMIT_ANNOTATION(id, __func__) + +#define WESTON_TRACE_ANNOTATE_FUNC() \ + _WESTON_TRACE_ANNOTATE_FUNC(__func__) + +#define WESTON_TRACE_ANNOTATE_FUNC_FLOW(id) \ + _WESTON_TRACE_ANNOTATE_FUNC_FLOW(id, __func__) + #endif /* WESTON_TRACE_H */