Program Listing for carb/profiler/Profile.h

↰ Return to documentation for carb/profiler/Profile.h

// Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

#pragma once

#include "../Defines.h"

#include "../Framework.h"
#include "../cpp20/Atomic.h"
#include "IProfiler.h"

#include <cstdarg>
#include <cstdio>
#include <tuple>

#include "ProfilerUtils.h"

#if CARB_PROFILING || defined(DOXYGEN_BUILD)

#    ifndef DOXYGEN_BUILD
// The following are helper macros for the profiler.
#        define CARB_PROFILE_IF(cond, true_case, false_case) CARB_PROFILE_IF_HELPER(cond, true_case, false_case)

// Note: CARB_PROFILE_HAS_VARARGS only supports up to 10 args now. If more are desired, increase the sequences below
// and add test cases to TestProfiler.cpp
// This trick is from https://stackoverflow.com/a/36015150/1450686
#        if CARB_COMPILER_MSC
#            define CARB_PROFILE_HAS_VARARGS(x, ...) CARB_PROFILE_EXPAND_ARGS(CARB_PROFILE_AUGMENT_ARGS(__VA_ARGS__))
#        elif CARB_COMPILER_GNUC
#            define CARB_PROFILE_HAS_VARARGS(...)                                                                      \
                CARB_PROFILE_ARGCHK_PRIVATE2(0, ##__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0)
#        else
#            error Unsupported Compiler!
#        endif

// The following are implementation helpers not intended to be used
#        define CARB_PROFILE_IF_HELPER(cond, true_case, false_case)                                                    \
            CARB_JOIN(CARB_PROFILE_IF_HELPER_, cond)(true_case, false_case)
#        define CARB_PROFILE_IF_HELPER_0(true_case, false_case) false_case
#        define CARB_PROFILE_IF_HELPER_1(true_case, false_case) true_case

#        define CARB_PROFILE_AUGMENT_ARGS(...) unused, __VA_ARGS__
#        define CARB_PROFILE_EXPAND_ARGS(...)                                                                          \
            CARB_PROFILE_EXPAND(CARB_PROFILE_ARGCHK_PRIVATE(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0))
#        define CARB_PROFILE_EXPAND(x) x
#        define CARB_PROFILE_ARGCHK_PRIVATE(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, count, ...) count
#        define CARB_PROFILE_ARGCHK_PRIVATE2(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, count, ...) count

#        define CARB_PROFILE_UFUNCFILE(func)                                                                           \
            [](const char* pfunc) -> const auto&                                                                       \
            {                                                                                                          \
                static auto tup = ::std::make_tuple(                                                                   \
                    ::g_carbProfiler->registerStaticString(pfunc), ::g_carbProfiler->registerStaticString(__FILE__));  \
                return tup;                                                                                            \
            }                                                                                                          \
            (func)

#        define CARB_PROFILE_UFUNCFILESTR(func, str)                                                                   \
            [](const char* pfunc, const char* pstr) -> const auto&                                                     \
            {                                                                                                          \
                static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(pfunc),                     \
                                                    ::g_carbProfiler->registerStaticString(__FILE__),                  \
                                                    ::g_carbProfiler->registerStaticString(pstr));                     \
                return tup;                                                                                            \
            }                                                                                                          \
            (func, str)

#        define CARB_PROFILE_FUNCFILE(func)                                                                            \
            [](const char* pfunc) -> const auto&                                                                       \
            {                                                                                                          \
                if (::g_carbProfiler)                                                                                  \
                {                                                                                                      \
                    static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(pfunc),                 \
                                                        ::g_carbProfiler->registerStaticString(__FILE__));             \
                    return tup;                                                                                        \
                }                                                                                                      \
                return ::carb::profiler::details::emptyTuple2();                                                       \
            }                                                                                                          \
            (func)

#        define CARB_PROFILE_FUNCFILESTR(func, str)                                                                    \
            [](const char* pfunc, const char* pstr) -> const auto&                                                     \
            {                                                                                                          \
                if (::g_carbProfiler)                                                                                  \
                {                                                                                                      \
                    static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(pfunc),                 \
                                                        ::g_carbProfiler->registerStaticString(__FILE__),              \
                                                        ::g_carbProfiler->registerStaticString(pstr));                 \
                    return tup;                                                                                        \
                }                                                                                                      \
                return ::carb::profiler::details::emptyTuple3();                                                       \
            }                                                                                                          \
            (func, str)

#        define CARB_PROFILE_CHECKMASK(mask)                                                                           \
            (((mask) ? (mask) : carb::profiler::kCaptureMaskDefault) &                                                 \
             g_carbProfilerMask.load(std::memory_order_acquire))

namespace carb
{
namespace profiler
{
namespace details
{
// Helper functions for begin that take the tuples created by CARB_PROFILE_UFUNCFILE and CARB_PROFILE_UFUNCFILESTR
template <class... Args>
carb::profiler::ZoneId beginDynamicHelper(
    const uint64_t mask,
    const std::tuple<carb::profiler::StaticStringType, carb::profiler::StaticStringType>& tup,
    int line,
    const char* fmt,
    Args&&... args)
{
    if (!CARB_PROFILE_CHECKMASK(mask))
        return kNoZoneId;
    return ::g_carbProfiler->beginDynamic(
        mask, std::get<0>(tup), std::get<1>(tup), line, fmt, std::forward<Args>(args)...);
}
template <class... Args>
carb::profiler::ZoneId beginDynamicHelper(
    const carb::profiler::Channel& channel,
    const std::tuple<carb::profiler::StaticStringType, carb::profiler::StaticStringType>& tup,
    int line,
    const char* fmt,
    Args&&... args)
{
    if (!channel.isEnabled())
        return kNoZoneId;
    return ::g_carbProfiler->beginDynamic(
        channel.getMask(), std::get<0>(tup), std::get<1>(tup), line, fmt, std::forward<Args>(args)...);
}
inline carb::profiler::ZoneId beginStaticHelper(
    const uint64_t mask,
    const std::tuple<carb::profiler::StaticStringType, carb::profiler::StaticStringType, carb::profiler::StaticStringType>& tup,
    int line)
{
    if (!CARB_PROFILE_CHECKMASK(mask))
        return kNoZoneId;
    return ::g_carbProfiler->beginStatic(mask, std::get<0>(tup), std::get<1>(tup), line, std::get<2>(tup));
}
inline carb::profiler::ZoneId beginStaticHelper(
    const carb::profiler::Channel& channel,
    const std::tuple<carb::profiler::StaticStringType, carb::profiler::StaticStringType, carb::profiler::StaticStringType>& tup,
    int line)
{
    if (!channel.isEnabled())
        return kNoZoneId;
    return ::g_carbProfiler->beginStatic(channel.getMask(), std::get<0>(tup), std::get<1>(tup), line, std::get<2>(tup));
}
inline uint64_t maskHelper(uint64_t mask)
{
    return mask;
}
inline uint64_t maskHelper(const carb::profiler::Channel& channel)
{
    return channel.getMask();
}
inline bool enabled(uint64_t mask)
{
    return CARB_PROFILE_CHECKMASK(mask);
}
inline bool enabled(const carb::profiler::Channel& channel)
{
    return channel.isEnabled();
}

inline const std::tuple<StaticStringType, StaticStringType>& emptyTuple2()
{
    static auto tup = std::make_tuple(kInvalidStaticString, kInvalidStaticString);
    return tup;
}

inline const std::tuple<StaticStringType, StaticStringType, StaticStringType>& emptyTuple3()
{
    static auto tup = std::make_tuple(kInvalidStaticString, kInvalidStaticString, kInvalidStaticString);
    return tup;
}

} // namespace details
} // namespace profiler
} // namespace carb

#    endif

#    define CARB_PROFILE_DECLARE_CHANNEL(name_, defaultMask_, defaultEnabled_, symbol_)                                \
        ::carb::profiler::Channel symbol_((defaultMask_), (defaultEnabled_), "" name_)

#    define CARB_PROFILE_EXTERN_CHANNEL(symbol_) extern ::carb::profiler::Channel symbol_

#    define CARB_PROFILE_STARTUP()                                                                                     \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                ::g_carbProfiler->startup();                                                                           \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_SHUTDOWN()                                                                                    \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                ::g_carbProfiler->shutdown();                                                                          \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_REGISTER_STRING(str)                                                                          \
        [](const char* pstr) {                                                                                         \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                static ::carb::profiler::StaticStringType p = ::g_carbProfiler->registerStaticString(pstr);            \
                return p;                                                                                              \
            }                                                                                                          \
            return ::carb::profiler::kInvalidStaticString;                                                             \
        }(str)

#    define CARB_PROFILE_SET_CAPTURE_MASK(mask)                                                                        \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                ::g_carbProfiler->setCaptureMask(mask);                                                                \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_BEGIN(maskOrChannel, eventName, ...)                                                          \
        ::g_carbProfiler ?                                                                                             \
            CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(eventName, ##__VA_ARGS__),                                        \
                            ::carb::profiler::details::beginDynamicHelper(                                             \
                                maskOrChannel, CARB_PROFILE_UFUNCFILE(__func__), __LINE__, eventName, ##__VA_ARGS__),  \
                            ::carb::profiler::details::beginStaticHelper(                                              \
                                maskOrChannel, CARB_PROFILE_UFUNCFILESTR(__func__, eventName), __LINE__)) :            \
            (0 ? /*compiler validate*/ printf(eventName, ##__VA_ARGS__) : 0)

#    define CARB_PROFILE_END(maskOrChannel, ...)                                                                       \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                ::g_carbProfiler->CARB_PROFILE_IF(                                                                     \
                    CARB_PROFILE_HAS_VARARGS(maskOrChannel, ##__VA_ARGS__),                                            \
                    endEx(::carb::profiler::details::maskHelper(maskOrChannel), ##__VA_ARGS__),                        \
                    end(::carb::profiler::details::maskHelper(maskOrChannel)));                                        \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_FRAME(mask, frameName, ...)                                                                   \
        do                                                                                                             \
        {                                                                                                              \
            /* Use printf to validate the format string */                                                             \
            if (0)                                                                                                     \
            {                                                                                                          \
                printf(frameName, ##__VA_ARGS__);                                                                      \
            }                                                                                                          \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(frameName, ##__VA_ARGS__),                                    \
                                ::g_carbProfiler->frameDynamic(mask, frameName, ##__VA_ARGS__),                        \
                                ::g_carbProfiler->frameStatic(mask, []() {                                             \
                                    static ::carb::profiler::StaticStringType p =                                      \
                                        ::g_carbProfiler->registerStaticString("" frameName);                          \
                                    return p;                                                                          \
                                }()));                                                                                 \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_ZONE(maskOrChannel, zoneName, ...)                                                            \
        CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(zoneName, ##__VA_ARGS__),                                             \
                        ::carb::profiler::ProfileZoneDynamic CARB_JOIN(_carbZone, __LINE__)(                           \
                            (maskOrChannel), CARB_PROFILE_FUNCFILE(__func__), __LINE__, zoneName, ##__VA_ARGS__),      \
                        ::carb::profiler::ProfileZoneStatic CARB_JOIN(_carbZone, __LINE__)(                            \
                            (maskOrChannel), CARB_PROFILE_FUNCFILESTR(__func__, zoneName), __LINE__))

#    define CARB_PROFILE_FUNCTION(maskOrChannel)                                                                       \
        ::carb::profiler::ProfileZoneStatic CARB_JOIN(_carbZoneFunction, __LINE__)(                                    \
            (maskOrChannel), CARB_PROFILE_FUNCFILESTR(__func__, CARB_PRETTY_FUNCTION), __LINE__)

#    define CARB_PROFILE_VALUE(value, maskOrChannel, valueName, ...)                                                   \
        do                                                                                                             \
        {                                                                                                              \
            /* Use printf to validate the format string */                                                             \
            if (0)                                                                                                     \
            {                                                                                                          \
                printf(valueName, ##__VA_ARGS__);                                                                      \
            }                                                                                                          \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                CARB_PROFILE_IF(                                                                                       \
                    CARB_PROFILE_HAS_VARARGS(valueName, ##__VA_ARGS__),                                                \
                    ::g_carbProfiler->valueDynamic(                                                                    \
                        ::carb::profiler::details::maskHelper(maskOrChannel), value, valueName, ##__VA_ARGS__),        \
                    ::g_carbProfiler->valueStatic(::carb::profiler::details::maskHelper(maskOrChannel), value, []() {  \
                        static ::carb::profiler::StaticStringType p =                                                  \
                            ::g_carbProfiler->registerStaticString("" valueName);                                      \
                        return p;                                                                                      \
                    }()));                                                                                             \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_ALLOC_NAMED(maskOrChannel, ptr, size, poolName, ...)                                          \
        do                                                                                                             \
        {                                                                                                              \
            /* Use printf to validate the format string */                                                             \
            if (0)                                                                                                     \
            {                                                                                                          \
                printf(poolName, ##__VA_ARGS__);                                                                       \
            }                                                                                                          \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                CARB_PROFILE_IF(                                                                                       \
                    CARB_PROFILE_HAS_VARARGS(poolName, ##__VA_ARGS__),                                                 \
                    ::g_carbProfiler->allocNamedDynamic(                                                               \
                        ::carb::profiler::details::maskHelper(maskOrChannel), ptr, size, poolName, ##__VA_ARGS__),     \
                    ::g_carbProfiler->allocNamedStatic(                                                                \
                        ::carb::profiler::details::maskHelper(maskOrChannel), ptr, size, []() {                        \
                            static ::carb::profiler::StaticStringType p =                                              \
                                ::g_carbProfiler->registerStaticString("" poolName);                                   \
                            return p;                                                                                  \
                        }()));                                                                                         \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_FREE_NAMED(maskOrChannel, ptr, poolName, ...)                                                  \
        do                                                                                                              \
        {                                                                                                               \
            /* Use printf to validate the format string */                                                              \
            if (0)                                                                                                      \
            {                                                                                                           \
                printf(poolName, ##__VA_ARGS__);                                                                        \
            }                                                                                                           \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                  \
            {                                                                                                           \
                CARB_PROFILE_IF(                                                                                        \
                    CARB_PROFILE_HAS_VARARGS(poolName, ##__VA_ARGS__),                                                  \
                    ::g_carbProfiler->freeNamedDynamic(                                                                 \
                        ::carb::profiler::details::maskHelper(maskOrChannel), ptr, poolName, ##__VA_ARGS__),            \
                    ::g_carbProfiler->freeNamedStatic(::carb::profiler::details::maskHelper(maskOrChannel), ptr, []() { \
                        static ::carb::profiler::StaticStringType p =                                                   \
                            ::g_carbProfiler->registerStaticString("" poolName);                                        \
                        return p;                                                                                       \
                    }()));                                                                                              \
            }                                                                                                           \
        } while (0)

#    define CARB_PROFILE_ALLOC(maskOrChannel, ptr, size)                                                               \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                ::g_carbProfiler->allocStatic(::carb::profiler::details::maskHelper(maskOrChannel), ptr, size);        \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_FREE(maskOrChannel, ptr)                                                                      \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                ::g_carbProfiler->freeStatic(::carb::profiler::details::maskHelper(maskOrChannel), ptr);               \
            }                                                                                                          \
        } while (0)

#    define CARB_NAME_THREAD(tidOrZero, threadName, ...)                                                               \
        do                                                                                                             \
        {                                                                                                              \
            /* Use printf to validate the format string */                                                             \
            if (0)                                                                                                     \
            {                                                                                                          \
                printf((threadName), ##__VA_ARGS__);                                                                   \
            }                                                                                                          \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(threadName, ##__VA_ARGS__),                                   \
                                ::g_carbProfiler->nameThreadDynamic((tidOrZero), (threadName), ##__VA_ARGS__),         \
                                ::g_carbProfiler->nameThreadStatic((tidOrZero), []() {                                 \
                                    static ::carb::profiler::StaticStringType p =                                      \
                                        ::g_carbProfiler->registerStaticString("" threadName);                         \
                                    return p;                                                                          \
                                }()));                                                                                 \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_EVENT(maskOrChannel, type, name, ...)                                                         \
        do                                                                                                             \
        {                                                                                                              \
            if (0)                                                                                                     \
                printf((name), ##__VA_ARGS__);                                                                         \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                CARB_PROFILE_IF(                                                                                       \
                    CARB_PROFILE_HAS_VARARGS(name, ##__VA_ARGS__),                                                     \
                    static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION),  \
                                                        ::g_carbProfiler->registerStaticString(__FILE__));             \
                    ::g_carbProfiler->emitInstantDynamic(::carb::profiler::details::maskHelper(maskOrChannel),         \
                                                         ::std::get<0>(tup), ::std::get<1>(tup), __LINE__, (type),     \
                                                         (name), ##__VA_ARGS__),                                       \
                    static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION),  \
                                                        ::g_carbProfiler->registerStaticString(__FILE__),              \
                                                        ::g_carbProfiler->registerStaticString(name));                 \
                    ::g_carbProfiler->emitInstantStatic(::carb::profiler::details::maskHelper(maskOrChannel),          \
                                                        ::std::get<0>(tup), ::std::get<1>(tup), __LINE__, (type),      \
                                                        ::std::get<2>(tup)));                                          \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_FLOW_BEGIN(maskOrChannel, id, name, ...)                                                      \
        do                                                                                                             \
        {                                                                                                              \
            if (0)                                                                                                     \
                printf((name), ##__VA_ARGS__);                                                                         \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                CARB_PROFILE_IF(                                                                                       \
                    CARB_PROFILE_HAS_VARARGS(name, ##__VA_ARGS__),                                                     \
                    static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION),  \
                                                        ::g_carbProfiler->registerStaticString(__FILE__));             \
                    ::g_carbProfiler->emitFlowDynamic(::carb::profiler::details::maskHelper(maskOrChannel),            \
                                                      ::std::get<0>(tup), ::std::get<1>(tup), __LINE__,                \
                                                      ::carb::profiler::FlowType::Begin, (id), (name), ##__VA_ARGS__), \
                    static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION),  \
                                                        ::g_carbProfiler->registerStaticString(__FILE__),              \
                                                        ::g_carbProfiler->registerStaticString("" name));              \
                    ::g_carbProfiler->emitFlowStatic(::carb::profiler::details::maskHelper(maskOrChannel),             \
                                                     ::std::get<0>(tup), ::std::get<1>(tup), __LINE__,                 \
                                                     ::carb::profiler::FlowType::Begin, (id), ::std::get<2>(tup)));    \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_FLOW_END(maskOrChannel, id)                                                                   \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION),      \
                                                    ::g_carbProfiler->registerStaticString(__FILE__));                 \
                ::g_carbProfiler->emitFlowStatic(                                                                      \
                    ::carb::profiler::details::maskHelper(maskOrChannel), ::std::get<0>(tup), ::std::get<1>(tup),      \
                    __LINE__, ::carb::profiler::FlowType::End, (id), ::carb::profiler::kInvalidStaticString);          \
            }                                                                                                          \
        } while (0)


#    define CARB_PROFILE_CREATE_GPU_CONTEXT(                                                                           \
        name, correlatedCpuTimestampNs, correlatedGpuTimestamp, gpuTimestampPeriodNs, graphicApi)                      \
        (::g_carbProfiler ? ::g_carbProfiler->createGpuContext(name, correlatedCpuTimestampNs, correlatedGpuTimestamp, \
                                                               gpuTimestampPeriodNs, graphicApi) :                     \
                            carb::profiler::kInvalidGpuContextId)

#    define CARB_PROFILE_DESTROY_GPU_CONTEXT(contextId)                                                                \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler)                                                                                      \
            {                                                                                                          \
                ::g_carbProfiler->destroyGpuContext(contextId);                                                        \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_CALIBRATE_GPU_CONTEXT(                                                                        \
        contextId, correlatedCpuTimestampNs, previousCorrelatedCpuTimestampNs, correlatedGpuTimestamp)                 \
        ((::g_carbProfiler) ?                                                                                          \
             (::g_carbProfiler->calibrateGpuContext(                                                                   \
                 contextId, correlatedCpuTimestampNs, previousCorrelatedCpuTimestampNs, correlatedGpuTimestamp)) :     \
             false)


#    define CARB_PROFILE_GPU_QUERY_BEGIN(maskOrChannel, contextId, queryId, eventName, ...)                            \
        do                                                                                                             \
        {                                                                                                              \
            if (0)                                                                                                     \
                printf((eventName), ##__VA_ARGS__);                                                                    \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION),      \
                                                    ::g_carbProfiler->registerStaticString(__FILE__));                 \
                CARB_PROFILE_IF(                                                                                       \
                    CARB_PROFILE_HAS_VARARGS(eventName, ##__VA_ARGS__),                                                \
                    ::g_carbProfiler->beginGpuQueryDynamic(::carb::profiler::details::maskHelper(maskOrChannel),       \
                                                           ::std::get<0>(tup), ::std::get<1>(tup), __LINE__,           \
                                                           contextId, queryId, eventName, ##__VA_ARGS__),              \
                    ::g_carbProfiler->beginGpuQueryStatic(::carb::profiler::details::maskHelper(maskOrChannel),        \
                                                          ::std::get<0>(tup), ::std::get<1>(tup), __LINE__, contextId, \
                                                          queryId, CARB_PROFILE_REGISTER_STRING("" eventName)));       \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_GPU_QUERY_END(maskOrChannel, contextId, queryId)                                                \
        do                                                                                                               \
        {                                                                                                                \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                   \
            {                                                                                                            \
                ::g_carbProfiler->endGpuQuery(::carb::profiler::details::maskHelper(maskOrChannel), contextId, queryId); \
            }                                                                                                            \
        } while (0)


#    define CARB_PROFILE_GPU_SET_QUERY_VALUE(maskOrChannel, contextId, queryId, gpuTimestamp)                          \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler && ::carb::profiler::details::enabled(maskOrChannel))                                 \
            {                                                                                                          \
                ::g_carbProfiler->setGpuQueryValue(                                                                    \
                    ::carb::profiler::details::maskHelper(maskOrChannel), contextId, queryId, gpuTimestamp);           \
            }                                                                                                          \
        } while (0)


#    define CARB_PROFILE_LOCKABLE_CREATE(maskOrChannel, isSharedLock, name)                                            \
        [](bool enabled, const uint64_t maskParam, const bool isSharedLockParam, const char* nameParam,                \
           const char* function) {                                                                                     \
            if (::g_carbProfiler && enabled)                                                                           \
            {                                                                                                          \
                static auto tup = ::std::make_tuple(::g_carbProfiler->registerStaticString(function),                  \
                                                    ::g_carbProfiler->registerStaticString(__FILE__));                 \
                return ::g_carbProfiler->createLockable(                                                               \
                    maskParam, nameParam, isSharedLockParam, ::std::get<0>(tup), ::std::get<1>(tup), __LINE__);        \
            }                                                                                                          \
            return ::carb::profiler::kInvalidLockableId;                                                               \
        }(::carb::profiler::details::enabled(maskOrChannel), ::carb::profiler::details::maskHelper(maskOrChannel),     \
          (isSharedLock), (name), CARB_PRETTY_FUNCTION)


#    define CARB_PROFILE_LOCKABLE_DESTROY(lockableId)                                                                  \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler && lockableId != carb::profiler::kInvalidLockableId)                                  \
            {                                                                                                          \
                ::g_carbProfiler->destroyLockable((lockableId));                                                       \
            }                                                                                                          \
        } while (0)

#    define CARB_PROFILE_LOCKABLE_OPERATION(lockableId, operation)                                                     \
        do                                                                                                             \
        {                                                                                                              \
            if (::g_carbProfiler && lockableId != carb::profiler::kInvalidLockableId)                                  \
            {                                                                                                          \
                ::g_carbProfiler->lockableOperation((lockableId), (operation));                                        \
            }                                                                                                          \
        } while (0)

#else

#    define CARB_PROFILE_STARTUP() (void(0))
#    define CARB_PROFILE_SHUTDOWN() (void(0))
#    define CARB_PROFILE_REGISTER_STRING(str) (::carb::profiler::kInvalidStaticString)
#    define CARB_PROFILE_SET_CAPTURE_MASK(mask) (void(0))
#    define CARB_PROFILE_BEGIN(mask, eventName, ...) (void(0))
#    define CARB_PROFILE_END(mask) (void(0))
#    define CARB_PROFILE_FRAME(mask, frameName, ...) (void(0))
#    define CARB_PROFILE_ZONE(mask, zoneName, ...) (void(0))
#    define CARB_PROFILE_FUNCTION(mask) (void(0))
#    define CARB_PROFILE_VALUE(value, mask, valueName, ...) (void(0))
#    define CARB_NAME_THREAD(tidOrZero, threadName, ...) (void(0))
#    define CARB_PROFILE_CREATE_GPU_CONTEXT(                                                                           \
        name, correlatedCpuTimestampNs, correlatedGpuTimestamp, gpuTimestampPeriodNs, graphicApi)                      \
        (carb::profiler::kInvalidGpuContextId)
#    define CARB_PROFILE_DESTROY_GPU_CONTEXT(contextId) (void(0))
#    define CARB_PROFILE_CALIBRATE_GPU_CONTEXT(                                                                        \
        contextId, correlatedCpuTimestampNs, previousCorrelatedCpuTimestampNs, correlatedGpuTimestamp)                 \
        (void(0))
#    define CARB_PROFILE_GPU_QUERY_BEGIN(mask, queryId, eventName) (void(0))
#    define CARB_PROFILE_GPU_QUERY_END(mask, queryId) (void(0))
#    define CARB_PROFILE_GPU_SET_QUERY_VALUE(mask, contextId, queryId, gpuTimestamp) (void(0))
#    define CARB_PROFILE_LOCKABLE_CREATE(mask, name, isShared)
#    define CARB_PROFILE_LOCKABLE_DESTROY(mask, lockableId)
#    define CARB_PROFILE_LOCKABLE_OPERATION(mask, lockableId, operation)

#endif

#define CARB_PROFILER_GLOBALS()

namespace carb
{
namespace profiler
{

template <class Mutex>
class ProfiledMutex
{
public:
    ProfiledMutex(const uint64_t profileMask, const char* name) : ProfiledMutex(profileMask, false, name)
    {
    }

    ProfiledMutex(const carb::profiler::Channel& channel, const char* name) : ProfiledMutex(channel, false, name)
    {
    }

    ~ProfiledMutex()
    {
        CARB_PROFILE_LOCKABLE_DESTROY(m_lockableId);
    }

    void lock()
    {
        CARB_PROFILE_LOCKABLE_OPERATION(m_lockableId, LockableOperationType::BeforeLock);
        m_mutex.lock();
        CARB_PROFILE_LOCKABLE_OPERATION(m_lockableId, LockableOperationType::AfterLock);
    }

    bool try_lock()
    {
        bool acquired = m_mutex.try_lock();
        if (acquired)
        {
            CARB_PROFILE_LOCKABLE_OPERATION(m_lockableId, LockableOperationType::AfterSuccessfulTryLock);
        }
        return acquired;
    }

    void unlock()
    {
        m_mutex.unlock();
        CARB_PROFILE_LOCKABLE_OPERATION(m_lockableId, LockableOperationType::AfterUnlock);
    }

    Mutex& getMutex()
    {
        return m_mutex;
    }

    const Mutex& getMutex() const
    {
        return m_mutex;
    }

protected:
    ProfiledMutex(const uint64_t profileMask, bool isSharedMutex, const char* name)
    {
        m_lockableId = CARB_PROFILE_LOCKABLE_CREATE(profileMask, isSharedMutex, name);
    }
    ProfiledMutex(const carb::profiler::Channel& channel, bool isSharedMutex, const char* name)
    {
        m_lockableId = CARB_PROFILE_LOCKABLE_CREATE(channel, isSharedMutex, name);
    }

    Mutex m_mutex;
    LockableId m_lockableId;
};

template <class Mutex>
class ProfiledSharedMutex : public ProfiledMutex<Mutex>
{
    using Base = ProfiledMutex<Mutex>;

public:
    ProfiledSharedMutex(const uint64_t profileMask, const char* name) : Base(profileMask, true, name)
    {
    }

    ProfiledSharedMutex(const carb::profiler::Channel& channel, const char* name) : Base(channel, true, name)
    {
    }

    ~ProfiledSharedMutex()
    {
    }

    void lock_shared()
    {
        CARB_PROFILE_LOCKABLE_OPERATION(this->m_lockableId, LockableOperationType::BeforeLockShared);
        this->m_mutex.lock_shared();
        CARB_PROFILE_LOCKABLE_OPERATION(this->m_lockableId, LockableOperationType::AfterLockShared);
    }

    bool try_lock_shared()
    {
        bool acquired = this->m_mutex.try_lock_shared();
        if (acquired)
        {
            CARB_PROFILE_LOCKABLE_OPERATION(this->m_lockableId, LockableOperationType::AfterSuccessfulTryLockShared);
        }
        return acquired;
    }

    void unlock_shared()
    {
        this->m_mutex.unlock_shared();
        CARB_PROFILE_LOCKABLE_OPERATION(this->m_lockableId, LockableOperationType::AfterUnlockShared);
    }
};


void deregisterProfilerForClient() noexcept;

#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace details
{

inline void updateMask(uint64_t mask)
{
    g_carbProfilerMask.store(mask, std::memory_order_release);
}

inline void releaseHook(void* iface, void*)
{
    cpp20::atomic_ref<IProfiler*>(g_carbProfiler).store(nullptr); // sequentially consistent
    getFramework()->removeReleaseHook(iface, &releaseHook, nullptr);
}

inline void frameworkReleaseHook(void*, void*)
{
    // Framework is going away, so make sure we get fully deregistered.
    deregisterProfilerForClient();
}

inline void loadHook(const PluginDesc&, void*)
{
    if (!g_carbProfiler)
    {
        IProfiler* profiler = getFramework()->tryAcquireInterface<IProfiler>();
        if (profiler)
        {
            if (profiler->setMaskCallback)
            {
                // Relaxed semantics since we will shortly be synchronizing on g_carbProfiler.
                g_carbProfilerMask.store(profiler->setMaskCallback(updateMask, true), std::memory_order_relaxed);
            }
            else
            {
                g_carbProfilerMask.store(uint64_t(-1), std::memory_order_relaxed); // not supported; let everything
                                                                                   // through
            }
            getFramework()->addReleaseHook(profiler, &details::releaseHook, nullptr);
            cpp20::atomic_ref<IProfiler*>(g_carbProfiler).store(profiler, std::memory_order_seq_cst); // sequentially
                                                                                                      // consistent
        }
    }
}

inline bool& registered()
{
    static bool r{ false };
    return r;
}

inline LoadHookHandle& loadHookHandle()
{
    static carb::LoadHookHandle handle{};
    return handle;
}

} // namespace details
#endif

inline IProfiler* getProfiler()
{
    return g_carbProfiler;
}

inline void deregisterProfilerForClient() noexcept
{
    if (std::exchange(details::registered(), false))
    {
        auto fw = getFramework();
        auto handle = std::exchange(details::loadHookHandle(), kInvalidLoadHook);
        IProfiler* profiler = cpp20::atomic_ref<IProfiler*>(g_carbProfiler).exchange(nullptr, std::memory_order_seq_cst);
        if (fw)
        {
            if (profiler && fw->verifyInterface(profiler) && profiler->setMaskCallback)
            {
                profiler->setMaskCallback(details::updateMask, false);
            }
            if (handle)
            {
                fw->removeLoadHook(handle);
            }
            fw->removeReleaseHook(nullptr, &details::frameworkReleaseHook, nullptr);
            if (profiler)
            {
                fw->removeReleaseHook(profiler, &details::releaseHook, nullptr);
            }

            // Unregister channels
            Channel::onProfilerUnregistered();
        }
    }
}

inline void registerProfilerForClient() noexcept
{
    if (!std::exchange(details::registered(), true))
    {
        auto fw = getFramework();
        fw->addReleaseHook(nullptr, &details::frameworkReleaseHook, nullptr);
        IProfiler* profiler = fw->tryAcquireInterface<IProfiler>();
        if (profiler)
        {
            if (profiler->setMaskCallback)
            {
                // Relaxed semantics since we will shortly be synchronizing on g_carbProfiler.
                g_carbProfilerMask.store(profiler->setMaskCallback(details::updateMask, true), std::memory_order_relaxed);
            }
            else
            {
                g_carbProfilerMask.store(uint64_t(-1), std::memory_order_relaxed); // let everything through
            }
            bool b = fw->addReleaseHook(profiler, &details::releaseHook, nullptr);
            CARB_ASSERT(b);
            CARB_UNUSED(b);
        }
        cpp20::atomic_ref<IProfiler*>(g_carbProfiler).store(profiler, std::memory_order_seq_cst); // sequentially
                                                                                                  // consistent
        details::loadHookHandle() = fw->addLoadHook<IProfiler>(nullptr, &details::loadHook, nullptr);

        // Register channels
        Channel::onProfilerRegistered();

        // Make sure this only happens once even if re-registered.
        static bool ensureDeregister = (atexit(&deregisterProfilerForClient), true);
        CARB_UNUSED(ensureDeregister);
    }
}

} // namespace profiler
} // namespace carb