From ca3ff7e08ed15568c49b7239d87a6832abe7804a Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 18 Apr 2025 11:31:17 -0700 Subject: [PATCH] Use the Perfetto SDK instead of ATRACE Perfetto has significantly less overhead. The User facing API is mostly unchanged: Here are the differences: - SYSTRACE_ENABLE() does nothing on ANDROID, initializes systraces on darwin. - SYSTRACE_DISABLE() is removed. - A new "gltfio" tag is added. - SYSTRACE_TAG *must* be defined before including `utils/Systrace.h` - `utils/Systrace.h` should not be used from a public header - the new SYSTRACE_TAG_DISABLE disables systrace at compile time For android a data source MUST be created in the perfetto config: ``` data_sources { config { name: "track_event" track_event_config { enabled_categories: ["filament", "jobsystem", "gltfio"] disabled_categories: "*" } } } ``` This can for example be added to AGI's custom/advanced config. FIXES=[407572663] --- filament/backend/src/CommandStream.cpp | 4 +- filament/backend/src/vulkan/VulkanConstants.h | 6 +- libs/gltfio/src/AssetLoader.cpp | 2 + libs/gltfio/src/ResourceLoader.cpp | 3 + libs/gltfio/src/Utility.cpp | 2 + libs/utils/include/utils/Systrace.h | 20 +- libs/utils/include/utils/android/Systrace.h | 247 ++++-------------- libs/utils/include/utils/darwin/Systrace.h | 66 ++--- libs/utils/src/JobSystem.cpp | 4 +- libs/utils/src/android/Systrace.cpp | 208 +-------------- libs/utils/src/darwin/Systrace.cpp | 25 +- 11 files changed, 136 insertions(+), 451 deletions(-) diff --git a/filament/backend/src/CommandStream.cpp b/filament/backend/src/CommandStream.cpp index bb2207be53..429cfa601b 100644 --- a/filament/backend/src/CommandStream.cpp +++ b/filament/backend/src/CommandStream.cpp @@ -84,7 +84,7 @@ void CommandStream::execute(void* buffer) { Profiler profiler; - if (SYSTRACE_TAG) { + if constexpr (SYSTRACE_TAG) { if (UTILS_UNLIKELY(mUsePerformanceCounter)) { // we want to remove all this when tracing is completely disabled profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES); @@ -100,7 +100,7 @@ void CommandStream::execute(void* buffer) { } }); - if (SYSTRACE_TAG) { + if constexpr (SYSTRACE_TAG) { if (UTILS_UNLIKELY(mUsePerformanceCounter)) { // we want to remove all this when tracing is completely disabled profiler.stop(); diff --git a/filament/backend/src/vulkan/VulkanConstants.h b/filament/backend/src/vulkan/VulkanConstants.h index 1a454d7069..c6524296ce 100644 --- a/filament/backend/src/vulkan/VulkanConstants.h +++ b/filament/backend/src/vulkan/VulkanConstants.h @@ -152,12 +152,12 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION)); #elif FVK_ENABLED(FVK_DEBUG_SYSTRACE) #include - + #define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT() #define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker) #define FVK_SYSTRACE_END() SYSTRACE_NAME_END() - #define FVK_SYSTRACE_SCOPE() SYSTRACE_NAME(__func__) - #define FVK_PROFILE_MARKER(marker) FVK_SYSTRACE_SCOPE() + #define FVK_SYSTRACE_SCOPE() SYSTRACE_CALL() + #define FVK_PROFILE_MARKER(marker) SYSTRACE_CALL() #else #define FVK_SYSTRACE_CONTEXT() diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index ac9b6b502f..e71d8fc897 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -50,6 +50,8 @@ #include #include #include + +#define SYSTRACE_TAG SYSTRACE_TAG_GLTFIO #include #include diff --git a/libs/gltfio/src/ResourceLoader.cpp b/libs/gltfio/src/ResourceLoader.cpp index b88a47b701..fb6b219294 100644 --- a/libs/gltfio/src/ResourceLoader.cpp +++ b/libs/gltfio/src/ResourceLoader.cpp @@ -37,7 +37,10 @@ #include #include #include + +#define SYSTRACE_TAG SYSTRACE_TAG_GLTFIO #include + #include #include diff --git a/libs/gltfio/src/Utility.cpp b/libs/gltfio/src/Utility.cpp index f875f71a4e..9273943c55 100644 --- a/libs/gltfio/src/Utility.cpp +++ b/libs/gltfio/src/Utility.cpp @@ -21,6 +21,8 @@ #include "GltfEnums.h" #include + +#define SYSTRACE_TAG SYSTRACE_TAG_GLTFIO #include #define CGLTF_IMPLEMENTATION diff --git a/libs/utils/include/utils/Systrace.h b/libs/utils/include/utils/Systrace.h index 9f5a7f2a59..02ff62217b 100644 --- a/libs/utils/include/utils/Systrace.h +++ b/libs/utils/include/utils/Systrace.h @@ -17,24 +17,23 @@ #ifndef TNT_UTILS_SYSTRACE_H #define TNT_UTILS_SYSTRACE_H - -#define SYSTRACE_TAG_NEVER (0) -#define SYSTRACE_TAG_ALWAYS (1<<0) -#define SYSTRACE_TAG_FILAMENT (1<<1) // don't change, used in makefiles -#define SYSTRACE_TAG_JOBSYSTEM (1<<2) +#define SYSTRACE_TAG_DISABLED (0) +#define SYSTRACE_TAG_FILAMENT (2) // don't change used in makefiles +#define SYSTRACE_TAG_JOBSYSTEM (3) +#define SYSTRACE_TAG_GLTFIO (4) /* - * The SYSTRACE_ macros use SYSTRACE_TAG as a the TAG, which should be defined - * before this file is included. If not, the SYSTRACE_TAG_ALWAYS tag will be used. + * The SYSTRACE_ macros use SYSTRACE_TAG as a category, which must be defined + * before this file is included. */ #ifndef SYSTRACE_TAG -#define SYSTRACE_TAG (SYSTRACE_TAG_ALWAYS) +# error SYSTRACE_TAG must be set to SYSTRACE_TAG_{DISABLED|FILAMENT|JOBSYSTEM} #endif // Systrace on Apple platforms is fragile and adds overhead, should only be enabled in dev builds. #ifndef FILAMENT_APPLE_SYSTRACE -#define FILAMENT_APPLE_SYSTRACE 0 +# define FILAMENT_APPLE_SYSTRACE 0 #endif #if defined(__ANDROID__) @@ -44,7 +43,6 @@ #else #define SYSTRACE_ENABLE() -#define SYSTRACE_DISABLE() #define SYSTRACE_CONTEXT() #define SYSTRACE_NAME(name) #define SYSTRACE_FRAME_ID(frame) @@ -56,6 +54,6 @@ #define SYSTRACE_VALUE32(name, val) #define SYSTRACE_VALUE64(name, val) -#endif // ANDROID +#endif #endif // TNT_UTILS_SYSTRACE_H diff --git a/libs/utils/include/utils/android/Systrace.h b/libs/utils/include/utils/android/Systrace.h index 760fe5be64..a2b74d76b1 100644 --- a/libs/utils/include/utils/android/Systrace.h +++ b/libs/utils/include/utils/android/Systrace.h @@ -17,226 +17,75 @@ #ifndef TNT_UTILS_ANDROID_SYSTRACE_H #define TNT_UTILS_ANDROID_SYSTRACE_H -#include +#include #include -#include -#include -#include +PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(systrace, + perfetto::Category("filament"), + perfetto::Category("jobsystem"), + perfetto::Category("gltfio")); -// enable tracing -#define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG) +PERFETTO_USE_CATEGORIES_FROM_NAMESPACE(systrace); -// disable tracing -#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG) +#if SYSTRACE_TAG == SYSTRACE_TAG_FILAMENT +# define UTILS_PERFETTO_CATEGORY "filament" +#elif SYSTRACE_TAG == SYSTRACE_TAG_JOBSYSTEM +# define UTILS_PERFETTO_CATEGORY "jobsystem" +#elif SYSTRACE_TAG == SYSTRACE_TAG_GLTFIO +# define UTILS_PERFETTO_CATEGORY "gltfio" +#endif +#if SYSTRACE_TAG == SYSTRACE_TAG_DISABLED -/** - * Creates a Systrace context in the current scope. needed for calling all other systrace - * commands below. - */ -#define SYSTRACE_CONTEXT() ::utils::details::Systrace ___trctx(SYSTRACE_TAG) +#define SYSTRACE_ENABLE() +#define SYSTRACE_CONTEXT() +#define SYSTRACE_NAME(name) +#define SYSTRACE_FRAME_ID(frame) +#define SYSTRACE_NAME_BEGIN(name) +#define SYSTRACE_NAME_END() +#define SYSTRACE_CALL() +#define SYSTRACE_ASYNC_BEGIN(name, cookie) +#define SYSTRACE_ASYNC_END(name, cookie) +#define SYSTRACE_VALUE32(name, val) +#define SYSTRACE_VALUE64(name, val) +#else -// SYSTRACE_NAME traces the beginning and end of the current scope. To trace -// the correct start and end times this macro should be declared first in the -// scope body. -// It also automatically creates a Systrace context -#define SYSTRACE_NAME(name) ::utils::details::ScopedTrace ___tracer(SYSTRACE_TAG, name) +#define SYSTRACE_ENABLE() +#define SYSTRACE_CONTEXT() -// Denotes that a new frame has started processing. -#define SYSTRACE_FRAME_ID(frame) \ - { /* scope for frame id trace */ \ - char buf[64]; \ - snprintf(buf, 64, "frame %u", frame); \ - SYSTRACE_NAME(buf); \ - } +#define SYSTRACE_CALL() \ + auto constexpr FILAMENT_SYSTRACE_FUNCTION = perfetto::StaticString(__FUNCTION__); \ + TRACE_EVENT(UTILS_PERFETTO_CATEGORY, FILAMENT_SYSTRACE_FUNCTION) -// SYSTRACE_CALL is an SYSTRACE_NAME that uses the current function name. -#define SYSTRACE_CALL() SYSTRACE_NAME(__FUNCTION__) +#define SYSTRACE_NAME(name) TRACE_EVENT(UTILS_PERFETTO_CATEGORY, nullptr, \ + [&](perfetto::EventContext ctx) { \ + ctx.event()->set_name(name); \ + }) -#define SYSTRACE_NAME_BEGIN(name) \ - ___trctx.traceBegin(SYSTRACE_TAG, name) +#define SYSTRACE_NAME_BEGIN(name) TRACE_EVENT_BEGIN(UTILS_PERFETTO_CATEGORY, nullptr, \ + [&](perfetto::EventContext ctx) { \ + ctx.event()->set_name(name); \ + }) -#define SYSTRACE_NAME_END() \ - ___trctx.traceEnd(SYSTRACE_TAG) +#define SYSTRACE_NAME_END() TRACE_EVENT_END(UTILS_PERFETTO_CATEGORY) - -/** - * Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END - * contexts, asynchronous events do not need to be nested. The name describes - * the event, and the cookie provides a unique identifier for distinguishing - * simultaneous events. The name and cookie used to begin an event must be - * used to end it. - */ #define SYSTRACE_ASYNC_BEGIN(name, cookie) \ - ___trctx.asyncBegin(SYSTRACE_TAG, name, cookie) + TRACE_EVENT_BEGIN(UTILS_PERFETTO_CATEGORY, name, perfetto::Track(cookie)) -/** - * Trace the end of an asynchronous event. - * This should have a corresponding SYSTRACE_ASYNC_BEGIN. - */ #define SYSTRACE_ASYNC_END(name, cookie) \ - ___trctx.asyncEnd(SYSTRACE_TAG, name, cookie) + TRACE_EVENT_END(UTILS_PERFETTO_CATEGORY, perfetto::Track(cookie)) + +#define SYSTRACE_FRAME_ID(frame) \ + TRACE_EVENT_INSTANT(UTILS_PERFETTO_CATEGORY, "frame", "id", frame) -/** - * Traces an integer counter value. name is used to identify the counter. - * This can be used to track how a value changes over time. - */ #define SYSTRACE_VALUE32(name, val) \ - ___trctx.value(SYSTRACE_TAG, name, int32_t(val)) + TRACE_COUNTER(UTILS_PERFETTO_CATEGORY, name, val) #define SYSTRACE_VALUE64(name, val) \ - ___trctx.value(SYSTRACE_TAG, name, int64_t(val)) + TRACE_COUNTER(UTILS_PERFETTO_CATEGORY, name, val) -// ------------------------------------------------------------------------------------------------ -// No user serviceable code below... -// ------------------------------------------------------------------------------------------------ - -namespace utils { -namespace details { - -class UTILS_PUBLIC Systrace { - public: - - enum tags { - NEVER = SYSTRACE_TAG_NEVER, - ALWAYS = SYSTRACE_TAG_ALWAYS, - FILAMENT = SYSTRACE_TAG_FILAMENT, - JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM - // we could define more TAGS here, as we need them. - }; - - explicit Systrace(uint32_t tag) noexcept { - if (tag) init(tag); - } - - static void enable(uint32_t tags) noexcept; - static void disable(uint32_t tags) noexcept; - - - inline void traceBegin(uint32_t tag, const char* name) noexcept { - if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - beginSection(this, name); - } - } - - inline void traceEnd(uint32_t tag) noexcept { - if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - endSection(this); - } - } - - inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept { - if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - beginAsyncSection(this, name, cookie); - } - } - - inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept { - if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - endAsyncSection(this, name, cookie); - } - } - - inline void value(uint32_t tag, const char* name, int32_t value) noexcept { - if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - setCounter(this, name, value); - } - } - - inline void value(uint32_t tag, const char* name, int64_t value) noexcept { - if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - setCounter(this, name, value); - } - } - - private: - friend class ScopedTrace; - - // whether tracing is supported at all by the platform - - using ATrace_isEnabled_t = bool (*)(); - using ATrace_beginSection_t = void (*)(const char* sectionName); - using ATrace_endSection_t = void (*)(); - using ATrace_beginAsyncSection_t = void (*)(const char* sectionName, int32_t cookie); - using ATrace_endAsyncSection_t = void (*)(const char* sectionName, int32_t cookie); - using ATrace_setCounter_t = void (*)(const char* counterName, int64_t counterValue); - - struct GlobalState { - bool isTracingAvailable; - std::atomic isTracingEnabled; - int markerFd; - - ATrace_isEnabled_t ATrace_isEnabled; - ATrace_beginSection_t ATrace_beginSection; - ATrace_endSection_t ATrace_endSection; - ATrace_beginAsyncSection_t ATrace_beginAsyncSection; - ATrace_endAsyncSection_t ATrace_endAsyncSection; - ATrace_setCounter_t ATrace_setCounter; - - void (*beginSection)(Systrace* that, const char* name); - void (*endSection)(Systrace* that); - void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie); - void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie); - void (*setCounter)(Systrace* that, const char* name, int64_t value); - }; - - static GlobalState sGlobalState; - - - // per-instance versions for better performance - ATrace_isEnabled_t ATrace_isEnabled; - ATrace_beginSection_t ATrace_beginSection; - ATrace_endSection_t ATrace_endSection; - ATrace_beginAsyncSection_t ATrace_beginAsyncSection; - ATrace_endAsyncSection_t ATrace_endAsyncSection; - ATrace_setCounter_t ATrace_setCounter; - - void (*beginSection)(Systrace* that, const char* name); - void (*endSection)(Systrace* that); - void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie); - void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie); - void (*setCounter)(Systrace* that, const char* name, int64_t value); - - void init(uint32_t tag) noexcept; - - // cached values for faster access, no need to be initialized - bool mIsTracingEnabled; - int mMarkerFd = -1; - pid_t mPid; - - static void setup() noexcept; - static void init_once() noexcept; - static bool isTracingEnabled(uint32_t tag) noexcept; - - static void begin_body(int fd, int pid, const char* name) noexcept; - static void end_body(int fd, int pid) noexcept; - static void async_begin_body(int fd, int pid, const char* name, int32_t cookie) noexcept; - static void async_end_body(int fd, int pid, const char* name, int32_t cookie) noexcept; - static void int64_body(int fd, int pid, const char* name, int64_t value) noexcept; -}; - -// ------------------------------------------------------------------------------------------------ - -class UTILS_PUBLIC ScopedTrace { -public: - // we don't inline this because it's relatively heavy due to a global check - ScopedTrace(uint32_t tag, const char* name) noexcept: mTrace(tag), mTag(tag) { - mTrace.traceBegin(tag, name); - } - - inline ~ScopedTrace() noexcept { - mTrace.traceEnd(mTag); - } - -private: - Systrace mTrace; - const uint32_t mTag; -}; - -} // namespace details -} // namespace utils +#endif // SYSTRACE_TAG == SYSTRACE_TAG_DISABLED #endif // TNT_UTILS_ANDROID_SYSTRACE_H diff --git a/libs/utils/include/utils/darwin/Systrace.h b/libs/utils/include/utils/darwin/Systrace.h index e1521cf705..33de07962d 100644 --- a/libs/utils/include/utils/darwin/Systrace.h +++ b/libs/utils/include/utils/darwin/Systrace.h @@ -29,13 +29,25 @@ #include #include +#if SYSTRACE_TAG == SYSTRACE_TAG_DISABLED + +#define SYSTRACE_ENABLE() +#define SYSTRACE_CONTEXT() +#define SYSTRACE_NAME(name) +#define SYSTRACE_FRAME_ID(frame) +#define SYSTRACE_NAME_BEGIN(name) +#define SYSTRACE_NAME_END() +#define SYSTRACE_CALL() +#define SYSTRACE_ASYNC_BEGIN(name, cookie) +#define SYSTRACE_ASYNC_END(name, cookie) +#define SYSTRACE_VALUE32(name, val) +#define SYSTRACE_VALUE64(name, val) + +#else + // enable tracing #define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG) -// disable tracing -#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG) - - /** * Creates a Systrace context in the current scope. needed for calling all other systrace * commands below. @@ -93,6 +105,8 @@ extern thread_local std::stack ___tracerSections; #define SYSTRACE_VALUE64(name, val) \ ___tracer.value(SYSTRACE_TAG, name, int64_t(val)) +#endif // SYSTRACE_TAG == SYSTRACE_TAG_DISABLED + // ------------------------------------------------------------------------------------------------ // No user serviceable code below... // ------------------------------------------------------------------------------------------------ @@ -118,50 +132,40 @@ namespace utils { namespace details { class Systrace { - public: - - enum tags { - NEVER = SYSTRACE_TAG_NEVER, - ALWAYS = SYSTRACE_TAG_ALWAYS, - FILAMENT = SYSTRACE_TAG_FILAMENT, - JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM - // we could define more TAGS here, as we need them. - }; - +public: explicit Systrace(uint32_t tag) noexcept { if (tag) init(tag); } - static void enable(uint32_t tags) noexcept; - static void disable(uint32_t tags) noexcept; + static void enable(uint32_t tag) noexcept; - inline void traceBegin(uint32_t tag, const char* name) noexcept { + void traceBegin(uint32_t tag, const char* name) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { APPLE_SIGNPOST_EMIT(sGlobalState.systraceLog, OS_SIGNPOST_INTERVAL_BEGIN, OS_SIGNPOST_ID_EXCLUSIVE, name, name) } } - inline void traceEnd(uint32_t tag, const char* name) noexcept { + void traceEnd(uint32_t tag, const char* name) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { APPLE_SIGNPOST_EMIT(sGlobalState.systraceLog, OS_SIGNPOST_INTERVAL_END, OS_SIGNPOST_ID_EXCLUSIVE, name, "") } } - inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept { + void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { // TODO } } - inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept { + void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { // TODO } } - inline void value(uint32_t tag, const char* name, int32_t value) noexcept { + void value(uint32_t tag, const char* name, int32_t value) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { char buf[64]; snprintf(buf, 64, "%s - %d", name, value); @@ -170,7 +174,7 @@ class Systrace { } } - inline void value(uint32_t tag, const char* name, int64_t value) noexcept { + void value(uint32_t tag, const char* name, int64_t value) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { char buf[64]; snprintf(buf, 64, "%s - %lld", name, value); @@ -179,16 +183,16 @@ class Systrace { } } - inline void frameId(uint32_t tag, uint32_t frame) noexcept { + void frameId(uint32_t tag, uint32_t frame) noexcept { if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) { - char buf[64]; \ - snprintf(buf, 64, "frame %u", frame); \ + char buf[64]; + snprintf(buf, 64, "frame %u", frame); APPLE_SIGNPOST_EMIT(sGlobalState.frameIdLog, OS_SIGNPOST_EVENT, OS_SIGNPOST_ID_EXCLUSIVE, "frame", buf) } } - private: +private: friend class ScopedTrace; struct GlobalState { @@ -213,25 +217,25 @@ class Systrace { // ------------------------------------------------------------------------------------------------ class ScopedTrace { - public: +public: // we don't inline this because it's relatively heavy due to a global check ScopedTrace(uint32_t tag, const char* name) noexcept : mTrace(tag), mName(name), mTag(tag) { mTrace.traceBegin(tag, name); } - inline ~ScopedTrace() noexcept { + ~ScopedTrace() noexcept { mTrace.traceEnd(mTag, mName); } - inline void value(uint32_t tag, const char* name, int32_t v) noexcept { + void value(uint32_t tag, const char* name, int32_t v) noexcept { mTrace.value(tag, name, v); } - inline void value(uint32_t tag, const char* name, int64_t v) noexcept { + void value(uint32_t tag, const char* name, int64_t v) noexcept { mTrace.value(tag, name, v); } - private: +private: Systrace mTrace; const char* mName; const uint32_t mTag; diff --git a/libs/utils/src/JobSystem.cpp b/libs/utils/src/JobSystem.cpp index ae8bba5443..2651927dea 100644 --- a/libs/utils/src/JobSystem.cpp +++ b/libs/utils/src/JobSystem.cpp @@ -15,10 +15,8 @@ */ // Note: The overhead of SYSTRACE_TAG_JOBSYSTEM is not negligible especially with parallel_for(). -#ifndef SYSTRACE_TAG +#define SYSTRACE_TAG SYSTRACE_TAG_DISABLED //#define SYSTRACE_TAG SYSTRACE_TAG_JOBSYSTEM -#define SYSTRACE_TAG SYSTRACE_TAG_NEVER -#endif // when SYSTRACE_TAG_JOBSYSTEM is used, enables even heavier systraces #define HEAVY_SYSTRACE 0 diff --git a/libs/utils/src/android/Systrace.cpp b/libs/utils/src/android/Systrace.cpp index 0b03d4951d..3528312961 100644 --- a/libs/utils/src/android/Systrace.cpp +++ b/libs/utils/src/android/Systrace.cpp @@ -14,206 +14,26 @@ * limitations under the License. */ -#include -#include +#include +#include -#include +#include -#include +PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE(systrace); -#include -#include -#include -#include +namespace { -namespace utils { -namespace details { - -static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT; - -template -static void loadSymbol(T*& pfn, const char *symbol) noexcept { - pfn = (T*)dlsym(RTLD_DEFAULT, symbol); -} - -Systrace::GlobalState Systrace::sGlobalState = {}; - -void Systrace::init_once() noexcept { - GlobalState& s = sGlobalState; - - s.markerFd = -1; - - // API 23 - loadSymbol(s.ATrace_isEnabled, "ATrace_isEnabled"); - loadSymbol(s.ATrace_beginSection, "ATrace_beginSection"); - loadSymbol(s.ATrace_endSection, "ATrace_endSection"); - // API 29 - loadSymbol(s.ATrace_beginAsyncSection, "ATrace_beginAsyncSection"); - loadSymbol(s.ATrace_endAsyncSection, "ATrace_endAsyncSection"); - loadSymbol(s.ATrace_setCounter, "ATrace_setCounter"); - - - const bool hasBasicAtrace = s.ATrace_isEnabled && - s.ATrace_beginSection && - s.ATrace_endSection; - - const bool hasFullATrace = hasBasicAtrace && - s.ATrace_beginAsyncSection && - s.ATrace_endAsyncSection && - s.ATrace_setCounter; - - if (!hasFullATrace) { - s.markerFd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC); +class SystraceStaticInitialization { +public: + SystraceStaticInitialization() { + perfetto::TracingInitArgs args; + args.backends |= perfetto::kSystemBackend; + perfetto::Tracing::Initialize(args); + systrace::TrackEvent::Register(); } +}; - if (hasBasicAtrace && !hasFullATrace) { - // no-op if we don't have all these - s.ATrace_beginAsyncSection = [](const char* sectionName, int32_t cookie){}; - s.ATrace_endAsyncSection = [](const char* sectionName, int32_t cookie){}; - s.ATrace_setCounter = [](const char* sectionName, int64_t counterValue){}; - } +UTILS_UNUSED SystraceStaticInitialization sSystraceStaticInitialization{}; - const bool hasLegacySystrace = s.markerFd != -1; - - if (hasLegacySystrace && !hasFullATrace) { - // use legacy - s.beginSection = [](Systrace* that, const char* name) { - begin_body(that->mMarkerFd, that->mPid, name); - }; - s.endSection = [](Systrace* that) { - end_body(that->mMarkerFd, that->mPid); - }; - s.beginAsyncSection = [](Systrace* that, const char* name, int32_t cookie) { - async_begin_body(that->mMarkerFd, that->mPid, name, cookie); - }; - s.endAsyncSection = [](Systrace* that, const char* name, int32_t cookie) { - async_end_body(that->mMarkerFd, that->mPid, name, cookie); - }; - s.setCounter = [](Systrace* that, const char* name, int64_t value) { - int64_body(that->mMarkerFd, that->mPid, name, value); - }; - } else if (hasBasicAtrace) { - // we have at least basic ATrace - s.beginSection = [](Systrace* that, const char* name) { - that->ATrace_beginSection(name); - }; - s.endSection = [](Systrace* that) { - that->ATrace_endSection(); - }; - s.beginAsyncSection = [](Systrace* that, const char* name, int32_t cookie) { - that->ATrace_beginAsyncSection(name, cookie); - }; - s.endAsyncSection = [](Systrace* that, const char* name, int32_t cookie) { - that->ATrace_endAsyncSection(name, cookie); - }; - s.setCounter = [](Systrace* that, const char* name, int64_t value) { - that->ATrace_setCounter(name, value); - }; - } - - s.isTracingAvailable = hasLegacySystrace || hasFullATrace || hasBasicAtrace; } -void Systrace::setup() noexcept { - pthread_once(&atrace_once_control, init_once); -} - -void Systrace::enable(uint32_t tags) noexcept { - setup(); - if (UTILS_LIKELY(sGlobalState.isTracingAvailable)) { - sGlobalState.isTracingEnabled.fetch_or(tags, std::memory_order_relaxed); - } -} - -void Systrace::disable(uint32_t tags) noexcept { - sGlobalState.isTracingEnabled.fetch_and(~tags, std::memory_order_relaxed); -} - -// unfortunately, this generates quite a bit of code because reading a global is not -// trivial. For this reason, we do not inline this method. -bool Systrace::isTracingEnabled(uint32_t tag) noexcept { - if (tag) { - setup(); - return bool((sGlobalState.isTracingEnabled.load(std::memory_order_relaxed) | SYSTRACE_TAG_ALWAYS) & tag); - } - return false; -} - -// ------------------------------------------------------------------------------------------------ - -void Systrace::init(uint32_t tag) noexcept { - // must be called first - mIsTracingEnabled = isTracingEnabled(tag); - - // cache static variables for better efficiency - GlobalState& s = sGlobalState; - ATrace_isEnabled = s.ATrace_isEnabled; - ATrace_beginSection = s.ATrace_beginSection; - ATrace_endSection = s.ATrace_endSection; - ATrace_beginAsyncSection = s.ATrace_beginAsyncSection; - ATrace_endAsyncSection = s.ATrace_endAsyncSection; - ATrace_setCounter = s.ATrace_setCounter; - - beginSection = s.beginSection; - endSection = s.endSection; - beginAsyncSection = s.beginAsyncSection; - endAsyncSection = s.endAsyncSection; - setCounter = s.setCounter; - - mMarkerFd = s.markerFd; - - mPid = getpid(); -} - -// ------------------------------------------------------------------------------------------------ - -/** - * Maximum size of a message that can be logged to the trace buffer. - * Note this message includes a tag, the pid, and the string given as the name. - * Names should be kept short to get the most use of the trace buffer. - */ -#define ATRACE_MESSAGE_LENGTH 512 - -#define WRITE_MSG(format_begin, format_end, pid, name, value) { \ - char buf[ATRACE_MESSAGE_LENGTH]; \ - int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \ - name, value); \ - if (len >= (int) sizeof(buf)) { \ - /* Given the sizeof(buf), and all of the current format buffers, \ - * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \ - int name_len = strlen(name) - (len - sizeof(buf)) - 1; \ - /* Truncate the name to make the message fit. */ \ - len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \ - name_len, name, value); \ - } \ - write(fd, buf, len); \ -} - -void Systrace::begin_body(int fd, int pid, const char* name) noexcept { - char buf[ATRACE_MESSAGE_LENGTH]; - ssize_t len = snprintf(buf, sizeof(buf), "B|%d|%s", pid, name); - if (len >= sizeof(buf)) { - len = sizeof(buf) - 1; - } - write(fd, buf, size_t(len)); -} - -void Systrace::end_body(int fd, int pid) noexcept { - const char END_TAG = 'E'; - write(fd, &END_TAG, 1); -} - -void Systrace::async_begin_body(int fd, int pid, const char* name, int32_t cookie) noexcept { - WRITE_MSG("S|%d|", "|%" PRId32, pid, name, cookie); -} - -void Systrace::async_end_body(int fd, int pid, const char* name, int32_t cookie) noexcept { - WRITE_MSG("F|%d|", "|%" PRId32, pid, name, cookie); -} - -void Systrace::int64_body(int fd, int pid, const char* name, int64_t value) noexcept { - WRITE_MSG("C|%d|", "|%" PRId64, pid, name, value); -} - -} // namespace details -} // namespace utils diff --git a/libs/utils/src/darwin/Systrace.cpp b/libs/utils/src/darwin/Systrace.cpp index 523b7ebd02..759ca25f83 100644 --- a/libs/utils/src/darwin/Systrace.cpp +++ b/libs/utils/src/darwin/Systrace.cpp @@ -14,11 +14,17 @@ * limitations under the License. */ -#include -#include +#include + +#ifndef FILAMENT_APPLE_SYSTRACE +# define FILAMENT_APPLE_SYSTRACE 0 +#endif #if FILAMENT_APPLE_SYSTRACE +#include +#include +#include #include static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT; @@ -41,21 +47,24 @@ void Systrace::setup() noexcept { pthread_once(&atrace_once_control, init_once); } -void Systrace::enable(uint32_t tags) noexcept { +void Systrace::enable(uint32_t tag) noexcept { setup(); - sGlobalState.isTracingEnabled.fetch_or(tags, std::memory_order_relaxed); + uint32_t const mask = 1 << tag; + sGlobalState.isTracingEnabled.fetch_or(mask, std::memory_order_relaxed); } -void Systrace::disable(uint32_t tags) noexcept { - sGlobalState.isTracingEnabled.fetch_and(~tags, std::memory_order_relaxed); +void Systrace::disable(uint32_t tag) noexcept { + uint32_t const mask = 1 << tag; + sGlobalState.isTracingEnabled.fetch_and(~mask, std::memory_order_relaxed); } -// unfortunately, this generates quite a bit of code because reading a global is not +// Unfortunately, this generates quite a bit of code because reading a global is not // trivial. For this reason, we do not inline this method. bool Systrace::isTracingEnabled(uint32_t tag) noexcept { if (tag) { setup(); - return bool((sGlobalState.isTracingEnabled.load(std::memory_order_relaxed) | SYSTRACE_TAG_ALWAYS) & tag); + uint32_t const mask = 1 << tag; + return bool(sGlobalState.isTracingEnabled.load(std::memory_order_relaxed) & mask); } return false; }