carb/profiler/Profile.h
File members: carb/profiler/Profile.h
// Copyright (c) 2018-2023, 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 "../cpp/Atomic.h"
#include "IProfiler.h"
#include <cstdarg>
#include <cstdio>
#include "ProfilerUtils.h"
#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_
#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 = ::carb::profiler::detail::makeString2( \
::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 = ::carb::profiler::detail::makeString3( \
::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 = \
::carb::profiler::detail::makeString2(::g_carbProfiler->registerStaticString(pfunc), \
::g_carbProfiler->registerStaticString(__FILE__)); \
return tup; \
} \
return ::carb::profiler::detail::emptyTuple2(); \
} \
(func)
# define CARB_PROFILE_FUNCFILESTR(func, str) \
[](const char* pfunc, const char* pstr) -> const auto& \
{ \
if (::g_carbProfiler) \
{ \
static auto tup = \
::carb::profiler::detail::makeString3(::g_carbProfiler->registerStaticString(pfunc), \
::g_carbProfiler->registerStaticString(__FILE__), \
::g_carbProfiler->registerStaticString(pstr)); \
return tup; \
} \
return ::carb::profiler::detail::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 detail
{
// 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 ::carb::profiler::detail::String2& tup, int line, const char* fmt, Args&&... args)
{
if (!CARB_PROFILE_CHECKMASK(mask))
return kNoZoneId;
return ::g_carbProfiler->beginDynamic(mask, tup.first, tup.second, line, fmt, std::forward<Args>(args)...);
}
template <class... Args>
carb::profiler::ZoneId beginDynamicHelper(const carb::profiler::Channel& channel,
const ::carb::profiler::detail::String2& tup,
int line,
const char* fmt,
Args&&... args)
{
if (!channel.isEnabled())
return kNoZoneId;
return ::g_carbProfiler->beginDynamic(
channel.getMask(), tup.first, tup.second, line, fmt, std::forward<Args>(args)...);
}
inline carb::profiler::ZoneId beginStaticHelper(const uint64_t mask, const ::carb::profiler::detail::String3& tup, int line)
{
if (!CARB_PROFILE_CHECKMASK(mask))
return kNoZoneId;
return ::g_carbProfiler->beginStatic(mask, tup.first, tup.second, line, tup.third);
}
inline carb::profiler::ZoneId beginStaticHelper(const carb::profiler::Channel& channel,
const ::carb::profiler::detail::String3& tup,
int line)
{
if (!channel.isEnabled())
return kNoZoneId;
return ::g_carbProfiler->beginStatic(channel.getMask(), tup.first, tup.second, line, tup.third);
}
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 ::carb::profiler::detail::String2& emptyTuple2()
{
static constexpr auto tup = ::carb::profiler::detail::makeString2(kInvalidStaticString, kInvalidStaticString);
return tup;
}
inline const ::carb::profiler::detail::String3& emptyTuple3()
{
static constexpr auto tup =
::carb::profiler::detail::makeString3(kInvalidStaticString, kInvalidStaticString, kInvalidStaticString);
return tup;
}
} // namespace detail
} // namespace profiler
} // namespace carb
# endif
# 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::detail::beginDynamicHelper( \
maskOrChannel, CARB_PROFILE_UFUNCFILE(__func__), __LINE__, eventName, ##__VA_ARGS__), \
::carb::profiler::detail::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::detail::maskHelper(maskOrChannel), ##__VA_ARGS__), \
end(::carb::profiler::detail::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::detail::enabled(maskOrChannel)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS(valueName, ##__VA_ARGS__), \
::g_carbProfiler->valueDynamic( \
::carb::profiler::detail::maskHelper(maskOrChannel), value, valueName, ##__VA_ARGS__), \
::g_carbProfiler->valueStatic(::carb::profiler::detail::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::detail::enabled(maskOrChannel)) \
{ \
CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(poolName, ##__VA_ARGS__), \
::g_carbProfiler->allocNamedDynamic(::carb::profiler::detail::maskHelper(maskOrChannel), \
ptr, size, poolName, ##__VA_ARGS__), \
::g_carbProfiler->allocNamedStatic( \
::carb::profiler::detail::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::detail::enabled(maskOrChannel)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS(poolName, ##__VA_ARGS__), \
::g_carbProfiler->freeNamedDynamic( \
::carb::profiler::detail::maskHelper(maskOrChannel), ptr, poolName, ##__VA_ARGS__), \
::g_carbProfiler->freeNamedStatic(::carb::profiler::detail::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::detail::enabled(maskOrChannel)) \
{ \
::g_carbProfiler->allocStatic(::carb::profiler::detail::maskHelper(maskOrChannel), ptr, size); \
} \
} while (0)
# define CARB_PROFILE_FREE(maskOrChannel, ptr) \
do \
{ \
if (::g_carbProfiler && ::carb::profiler::detail::enabled(maskOrChannel)) \
{ \
::g_carbProfiler->freeStatic(::carb::profiler::detail::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::detail::enabled(maskOrChannel)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS(name, ##__VA_ARGS__), \
static auto tup = ::carb::profiler::detail::makeString2( \
::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__)); \
::g_carbProfiler->emitInstantDynamic(::carb::profiler::detail::maskHelper(maskOrChannel), tup.first, \
tup.second, __LINE__, (type), (name), ##__VA_ARGS__), \
static auto tup = ::carb::profiler::detail::makeString3( \
::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__), ::g_carbProfiler->registerStaticString(name)); \
::g_carbProfiler->emitInstantStatic(::carb::profiler::detail::maskHelper(maskOrChannel), \
tup.first, tup.second, __LINE__, (type), tup.third)); \
} \
} while (0)
# define CARB_PROFILE_FLOW_BEGIN(maskOrChannel, id, name, ...) \
do \
{ \
if (0) \
printf((name), ##__VA_ARGS__); \
if (::g_carbProfiler && ::carb::profiler::detail::enabled(maskOrChannel)) \
{ \
CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(name, ##__VA_ARGS__), \
static auto tup = ::carb::profiler::detail::makeString2( \
::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__)); \
::g_carbProfiler->emitFlowDynamic( \
::carb::profiler::detail::maskHelper(maskOrChannel), tup.first, tup.second, \
__LINE__, ::carb::profiler::FlowType::Begin, (id), (name), ##__VA_ARGS__), \
static auto tup = ::carb::profiler::detail::makeString3( \
::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__), \
::g_carbProfiler->registerStaticString("" name)); \
::g_carbProfiler->emitFlowStatic(::carb::profiler::detail::maskHelper(maskOrChannel), \
tup.first, tup.second, __LINE__, \
::carb::profiler::FlowType::Begin, (id), tup.third)); \
} \
} while (0)
# define CARB_PROFILE_FLOW_END(maskOrChannel, id) \
do \
{ \
if (::g_carbProfiler && ::carb::profiler::detail::enabled(maskOrChannel)) \
{ \
static auto tup = \
::carb::profiler::detail::makeString2(::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__)); \
::g_carbProfiler->emitFlowStatic(::carb::profiler::detail::maskHelper(maskOrChannel), tup.first, \
tup.second, __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::detail::enabled(maskOrChannel)) \
{ \
CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS(eventName, ##__VA_ARGS__), \
static auto tup = ::carb::profiler::detail::makeString2( \
::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__)); \
::g_carbProfiler->beginGpuQueryDynamic( \
::carb::profiler::detail::maskHelper(maskOrChannel), tup.first, tup.second, \
__LINE__, contextId, queryId, eventName, ##__VA_ARGS__), \
static auto tup = ::carb::profiler::detail::makeString3( \
::g_carbProfiler->registerStaticString(CARB_PRETTY_FUNCTION), \
::g_carbProfiler->registerStaticString(__FILE__), \
::g_carbProfiler->registerStaticString("" eventName)); \
::g_carbProfiler->beginGpuQueryStatic( \
::carb::profiler::detail::maskHelper(maskOrChannel), tup.first, tup.second, \
__LINE__, contextId, queryId, tup.third)); \
} \
} while (0)
# define CARB_PROFILE_GPU_QUERY_END(maskOrChannel, contextId, queryId) \
do \
{ \
if (::g_carbProfiler && ::carb::profiler::detail::enabled(maskOrChannel)) \
{ \
::g_carbProfiler->endGpuQuery(::carb::profiler::detail::maskHelper(maskOrChannel), contextId, queryId); \
} \
} while (0)
# define CARB_PROFILE_GPU_SET_QUERY_VALUE(maskOrChannel, contextId, queryId, gpuTimestamp) \
do \
{ \
if (::g_carbProfiler && ::carb::profiler::detail::enabled(maskOrChannel)) \
{ \
::g_carbProfiler->setGpuQueryValue( \
::carb::profiler::detail::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 = ::carb::profiler::detail::makeString2( \
::g_carbProfiler->registerStaticString(function), ::g_carbProfiler->registerStaticString(__FILE__)); \
return ::g_carbProfiler->createLockable( \
maskParam, nameParam, isSharedLockParam, tup.first, tup.second, __LINE__); \
} \
return ::carb::profiler::kInvalidLockableId; \
}(::carb::profiler::detail::enabled(maskOrChannel), ::carb::profiler::detail::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_UNUSED(str), ::carb::profiler::kInvalidStaticString)
# define CARB_PROFILE_SET_CAPTURE_MASK(mask) CARB_UNUSED(mask)
# define CARB_PROFILE_BEGIN(maskOrChannel, eventName, ...) \
(CARB_UNUSED((maskOrChannel), (eventName), ##__VA_ARGS__), ::carb::profiler::kNoZoneId)
# define CARB_PROFILE_END(maskOrChannel, ...) CARB_UNUSED((maskOrChannel), ##__VA_ARGS__)
# define CARB_PROFILE_FRAME(mask, frameName, ...) CARB_UNUSED((mask), (frameName), ##__VA_ARGS__)
# define CARB_PROFILE_ZONE(maskOrChannel, zoneName, ...) CARB_UNUSED((maskOrChannel), (zoneName), ##__VA_ARGS__)
# define CARB_PROFILE_FUNCTION(maskOrChannel) CARB_UNUSED(maskOrChannel)
# define CARB_PROFILE_VALUE(value, maskOrChannel, valueName, ...) \
CARB_UNUSED((value), (maskOrChannel), (valueName), ##__VA_ARGS__)
# define CARB_PROFILE_ALLOC_NAMED(maskOrChannel, ptr, size, poolName, ...) \
CARB_UNUSED((maskOrChannel), (ptr), (size), (poolName), ##__VA_ARGS__)
# define CARB_PROFILE_FREE_NAMED(maskOrChannel, ptr, poolName, ...) \
CARB_UNUSED((maskOrChannel), (ptr), (poolName), ##__VA_ARGS__)
# define CARB_PROFILE_ALLOC(maskOrChannel, ptr, size) CARB_UNUSED((maskOrChannel), (ptr), (size))
# define CARB_PROFILE_FREE(maskOrChannel, ptr) CARB_UNUSED((maskOrChannel), (ptr))
# define CARB_NAME_THREAD(tidOrZero, threadName, ...) CARB_UNUSED((tidOrZero), (threadName), ##__VA_ARGS__)
# define CARB_PROFILE_EVENT(maskOrChannel, type, name, ...) \
CARB_UNUSED((maskOrChannel), (type), (name), ##__VA_ARGS__)
# define CARB_PROFILE_FLOW_BEGIN(maskOrChannel, id, name, ...) \
CARB_UNUSED((maskOrChannel), (id), (name), ##__VA_ARGS__)
# define CARB_PROFILE_FLOW_END(maskOrChannel, id) CARB_UNUSED((maskOrChannel), (id))
# define CARB_PROFILE_CREATE_GPU_CONTEXT( \
name, correlatedCpuTimestampNs, correlatedGpuTimestamp, gpuTimestampPeriodNs, graphicApi) \
(CARB_UNUSED( \
(name), (correlatedCpuTimestampNs), (correlatedGpuTimestamp), (gpuTimestampPeriodNs), (graphicsApi)), \
carb::profiler::kInvalidGpuContextId)
# define CARB_PROFILE_DESTROY_GPU_CONTEXT(contextId) CARB_UNUSED(contextId)
# define CARB_PROFILE_CALIBRATE_GPU_CONTEXT( \
contextId, correlatedCpuTimestampNs, previousCorrelatedCpuTimestampNs, correlatedGpuTimestamp) \
CARB_UNUSED( \
(contextId), (correlatedCpuTimestampNs), (previousCorrelatedCpuTimestampNs), (correlatedGpuTimestamp))
# define CARB_PROFILE_GPU_QUERY_BEGIN(maskOrChannel, contextId, queryId, eventName, ...) \
CARB_UNUSED((maskOrChannel), (contextId), (queryId), (eventName), ##__VA_ARGS__)
# define CARB_PROFILE_GPU_QUERY_END(maskOrChannel, contextId, queryId) \
(CARB_UNUSED((maskOrChannel), (contextId), (queryId)))
# define CARB_PROFILE_GPU_SET_QUERY_VALUE(maskOrChannel, contextId, queryId, gpuTimestamp) \
CARB_UNUSED((maskOrChannel), (contextId), (queryId), (gpuTimestamp))
# define CARB_PROFILE_LOCKABLE_CREATE(maskOrChannel, isSharedLock, name) \
(CARB_UNUSED((maskOrChannel), (isSharedLock), (name)), ::carb::profiler::kInvalidLockableId)
# define CARB_PROFILE_LOCKABLE_DESTROY(lockableId) CARB_UNUSED(lockableId)
# define CARB_PROFILE_LOCKABLE_OPERATION(lockableId, operation) CARB_UNUSED((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 detail
{
inline void updateMask(uint64_t mask)
{
g_carbProfilerMask.store(mask, std::memory_order_release);
}
inline void releaseHook(void* iface, void*)
{
cpp::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, &detail::releaseHook, nullptr);
cpp::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 detail
#endif
inline IProfiler* getProfiler()
{
return g_carbProfiler;
}
inline void deregisterProfilerForClient() noexcept
{
if (std::exchange(detail::registered(), false))
{
auto fw = getFramework();
auto handle = std::exchange(detail::loadHookHandle(), kInvalidLoadHook);
IProfiler* profiler = cpp::atomic_ref<IProfiler*>(g_carbProfiler).exchange(nullptr, std::memory_order_seq_cst);
if (fw)
{
if (profiler && fw->verifyInterface(profiler) && profiler->setMaskCallback)
{
profiler->setMaskCallback(detail::updateMask, false);
}
if (handle)
{
fw->removeLoadHook(handle);
}
fw->removeReleaseHook(nullptr, &detail::frameworkReleaseHook, nullptr);
if (profiler)
{
fw->removeReleaseHook(profiler, &detail::releaseHook, nullptr);
}
// Unregister channels
Channel::onProfilerUnregistered();
}
}
}
inline void registerProfilerForClient() noexcept
{
if (!std::exchange(detail::registered(), true))
{
auto fw = getFramework();
fw->addReleaseHook(nullptr, &detail::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(detail::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, &detail::releaseHook, nullptr);
CARB_ASSERT(b);
CARB_UNUSED(b);
}
cpp::atomic_ref<IProfiler*>(g_carbProfiler).store(profiler, std::memory_order_seq_cst); // sequentially
// consistent
detail::loadHookHandle() = fw->addLoadHook<IProfiler>(nullptr, &detail::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