carb/profiler/Profile.h
File members: carb/profiler/Profile.h
// Copyright (c) 2018-2024, 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(prof, func) \
[p = (prof), f = (func)] { \
static auto tup = ::carb::profiler::detail::makeString2( \
p->registerStaticString(f), p->registerStaticString(__FILE__)); \
return tup; \
}()
# define CARB_PROFILE_UFUNCFILESTR(prof, func, str) \
[p = (prof), f = (func), s = (str)] { \
static auto tup = ::carb::profiler::detail::makeString3( \
p->registerStaticString(f), p->registerStaticString(__FILE__), p->registerStaticString(s)); \
return tup; \
}()
# define CARB_PROFILE_FUNCFILE(func) \
[f = (func)] { \
if (auto prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
static auto tup = ::carb::profiler::detail::makeString2( \
prof->registerStaticString(f), prof->registerStaticString(__FILE__)); \
return tup; \
} \
return ::carb::profiler::detail::emptyTuple2(); \
}()
# define CARB_PROFILE_FUNCFILESTR(func, str) \
[f = (func), s = (str)] { \
if (auto prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
static auto tup = ::carb::profiler::detail::makeString3(prof->registerStaticString(f), \
prof->registerStaticString(__FILE__), \
prof->registerStaticString(s)); \
return tup; \
} \
return ::carb::profiler::detail::emptyTuple3(); \
}()
# 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(::carb::profiler::IProfiler* prof,
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 prof->beginDynamic(mask, tup.first, tup.second, line, fmt, std::forward<Args>(args)...);
}
template <class... Args>
carb::profiler::ZoneId beginDynamicHelper(::carb::profiler::IProfiler* prof,
const carb::profiler::Channel& channel,
const ::carb::profiler::detail::String2& tup,
int line,
const char* fmt,
Args&&... args)
{
if (!channel.isEnabled())
return kNoZoneId;
return prof->beginDynamic(channel.getMask(), tup.first, tup.second, line, fmt, std::forward<Args>(args)...);
}
inline carb::profiler::ZoneId beginStaticHelper(::carb::profiler::IProfiler* prof,
const uint64_t mask,
const ::carb::profiler::detail::String3& tup,
int line)
{
if (!CARB_PROFILE_CHECKMASK(mask))
return kNoZoneId;
return prof->beginStatic(mask, tup.first, tup.second, line, tup.third);
}
inline carb::profiler::ZoneId beginStaticHelper(::carb::profiler::IProfiler* prof,
const carb::profiler::Channel& channel,
const ::carb::profiler::detail::String3& tup,
int line)
{
if (!channel.isEnabled())
return kNoZoneId;
return prof->beginStatic(channel.getMask(), tup.first, tup.second, line, tup.third);
}
inline void endHelper(const uint64_t mask, ::carb::profiler::ZoneId id = ::carb::profiler::kUnknownZoneId)
{
auto prof = ::g_carbProfiler.load(std::memory_order_acquire);
if (prof && id != ::carb::profiler::kNoZoneId && CARB_PROFILE_CHECKMASK(mask))
prof->endEx(mask, id);
}
inline void endHelper(const carb::profiler::Channel& channel,
::carb::profiler::ZoneId id = ::carb::profiler::kUnknownZoneId)
{
auto prof = ::g_carbProfiler.load(std::memory_order_acquire);
if (prof && id != ::carb::profiler::kNoZoneId && channel.isEnabled())
prof->endEx(channel.getMask(), id);
}
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() \
[] { \
if (auto prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
prof->startup(); \
} \
}()
# define CARB_PROFILE_SHUTDOWN() \
[] { \
if (auto prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
prof->shutdown(); \
} \
}()
# define CARB_PROFILE_REGISTER_STRING(str) \
[&] { \
if (auto __prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
static auto __p = __prof->registerStaticString(str); \
return __p; \
} \
return ::carb::profiler::kInvalidStaticString; \
}()
# define CARB_PROFILE_SET_CAPTURE_MASK(mask) \
[&] { \
if (auto __prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
__prof->setCaptureMask(mask); \
} \
}()
# define CARB_PROFILE_BEGIN(maskOrChannel, eventName, ...) \
[&, __prof = g_carbProfiler.load(std::memory_order_acquire), __func = __func__] { \
return __prof ? CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS((eventName), ##__VA_ARGS__), \
::carb::profiler::detail::beginDynamicHelper( \
__prof, (maskOrChannel), CARB_PROFILE_UFUNCFILE(__prof, __func), \
__LINE__, (eventName), ##__VA_ARGS__), \
::carb::profiler::detail::beginStaticHelper( \
__prof, (maskOrChannel), \
CARB_PROFILE_UFUNCFILESTR(__prof, __func, (eventName)), __LINE__)) : \
(0 ? /*compiler validate*/ printf((eventName), ##__VA_ARGS__) : 0); \
}()
# define CARB_PROFILE_END(maskOrChannel, ...) ::carb::profiler::detail::endHelper((maskOrChannel), ##__VA_ARGS__)
# define CARB_PROFILE_FRAME(maskOrChannel, frameName, ...) \
[&] { \
/* Use printf to validate the format string */ \
if (0) \
{ \
printf((frameName), ##__VA_ARGS__); \
} \
if (auto __prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS((frameName), ##__VA_ARGS__), \
__prof->frameDynamic(0, (frameName), ##__VA_ARGS__), __prof->frameStatic(0, [__prof]() { \
static ::carb::profiler::StaticStringType p = __prof->registerStaticString("" frameName); \
return p; \
}())); \
} \
}()
# 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, ...) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
/* Use printf to validate the format string */ \
if (0) \
{ \
printf((valueName), ##__VA_ARGS__); \
} \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS((valueName), ##__VA_ARGS__), \
__prof->valueDynamic( \
::carb::profiler::detail::maskHelper(__moc), (value), (valueName), ##__VA_ARGS__), \
__prof->valueStatic(::carb::profiler::detail::maskHelper(__moc), (value), [__prof]() { \
static ::carb::profiler::StaticStringType p = \
__prof->registerStaticString("" valueName); \
return p; \
}())); \
} \
}()
# define CARB_PROFILE_ALLOC_NAMED(maskOrChannel, ptr, size, poolName, ...) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
/* Use printf to validate the format string */ \
if (0) \
{ \
printf((poolName), ##__VA_ARGS__); \
} \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS((poolName), ##__VA_ARGS__), \
__prof->allocNamedDynamic( \
::carb::profiler::detail::maskHelper(__moc), (ptr), (size), (poolName), ##__VA_ARGS__), \
__prof->allocNamedStatic(::carb::profiler::detail::maskHelper(__moc), (ptr), (size), [__prof]() { \
static ::carb::profiler::StaticStringType p = __prof->registerStaticString("" poolName); \
return p; \
}())); \
} \
}()
# define CARB_PROFILE_FREE_NAMED(maskOrChannel, ptr, poolName, ...) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
/* Use printf to validate the format string */ \
if (0) \
{ \
printf((poolName), ##__VA_ARGS__); \
} \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS((poolName), ##__VA_ARGS__), \
__prof->freeNamedDynamic( \
::carb::profiler::detail::maskHelper(__moc), (ptr), (poolName), ##__VA_ARGS__), \
__prof->freeNamedStatic(::carb::profiler::detail::maskHelper(__moc), (ptr), [__prof]() { \
static ::carb::profiler::StaticStringType p = __prof->registerStaticString("" poolName); \
return p; \
}())); \
} \
}()
# define CARB_PROFILE_ALLOC(maskOrChannel, ptr, size) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
__prof->allocStatic(::carb::profiler::detail::maskHelper(__moc), (ptr), (size)); \
} \
}()
# define CARB_PROFILE_FREE(maskOrChannel, ptr) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
__prof->freeStatic(::carb::profiler::detail::maskHelper(__moc), (ptr)); \
} \
}()
# define CARB_NAME_THREAD(tidOrZero, threadName, ...) \
[&] { \
/* Use printf to validate the format string */ \
if (0) \
{ \
printf((threadName), ##__VA_ARGS__); \
} \
if (auto __prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS((threadName), ##__VA_ARGS__), \
__prof->nameThreadDynamic((tidOrZero), (threadName), ##__VA_ARGS__), \
__prof->nameThreadStatic((tidOrZero), [__prof]() { \
static ::carb::profiler::StaticStringType p = \
__prof->registerStaticString("" threadName); \
return p; \
}())); \
} \
}()
# define CARB_PROFILE_EVENT(maskOrChannel, type, name, ...) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire), __func = CARB_PRETTY_FUNCTION] { \
if (0) \
printf((name), ##__VA_ARGS__); \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
CARB_PROFILE_IF(CARB_PROFILE_HAS_VARARGS((name), ##__VA_ARGS__), \
static auto __tup = ::carb::profiler::detail::makeString2( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__)); \
__prof->emitInstantDynamic(::carb::profiler::detail::maskHelper(__moc), __tup.first, \
__tup.second, __LINE__, (type), (name), ##__VA_ARGS__), \
static auto __tup = ::carb::profiler::detail::makeString3( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__), \
__prof->registerStaticString(name)); \
__prof->emitInstantStatic(::carb::profiler::detail::maskHelper(__moc), __tup.first, \
__tup.second, __LINE__, (type), __tup.third)); \
} \
}()
# define CARB_PROFILE_FLOW_BEGIN(maskOrChannel, id, name, ...) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire), __func = CARB_PRETTY_FUNCTION] { \
if (0) \
printf((name), ##__VA_ARGS__); \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS(name, ##__VA_ARGS__), \
static auto __tup = ::carb::profiler::detail::makeString2( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__)); \
__prof->emitFlowDynamic(::carb::profiler::detail::maskHelper(__moc), __tup.first, __tup.second, \
__LINE__, ::carb::profiler::FlowType::Begin, (id), (name), ##__VA_ARGS__), \
static auto __tup = ::carb::profiler::detail::makeString3(__prof->registerStaticString(__func), \
__prof->registerStaticString(__FILE__), \
__prof->registerStaticString("" name)); \
__prof->emitFlowStatic(::carb::profiler::detail::maskHelper(__moc), __tup.first, __tup.second, \
__LINE__, ::carb::profiler::FlowType::Begin, (id), __tup.third)); \
} \
}()
# define CARB_PROFILE_FLOW_END(maskOrChannel, id) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire), __func = CARB_PRETTY_FUNCTION] { \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
static auto __tup = ::carb::profiler::detail::makeString2( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__)); \
__prof->emitFlowStatic(::carb::profiler::detail::maskHelper(__moc), __tup.first, __tup.second, __LINE__, \
::carb::profiler::FlowType::End, (id), ::carb::profiler::kInvalidStaticString); \
} \
}()
# define CARB_PROFILE_CREATE_GPU_CONTEXT( \
name, correlatedCpuTimestampNs, correlatedGpuTimestamp, gpuTimestampPeriodNs, graphicsApi) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)]() { \
return __prof ? __prof->createGpuContext((name), (correlatedCpuTimestampNs), (correlatedGpuTimestamp), \
(gpuTimestampPeriodNs), (graphicsApi)) : \
::carb::profiler::kInvalidGpuContextId; \
}()
# define CARB_PROFILE_DESTROY_GPU_CONTEXT(contextId) \
[&] { \
if (auto __prof = ::g_carbProfiler.load(std::memory_order_acquire)) \
{ \
__prof->destroyGpuContext(contextId); \
} \
}()
# define CARB_PROFILE_CALIBRATE_GPU_CONTEXT( \
contextId, correlatedCpuTimestampNs, previousCorrelatedCpuTimestampNs, correlatedGpuTimestamp) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)]() { \
return __prof ? __prof->calibrateGpuContext((contextId), (correlatedCpuTimestampNs), \
(previousCorrelatedCpuTimestampNs), (correlatedGpuTimestamp)) : \
false; \
}()
# define CARB_PROFILE_GPU_QUERY_BEGIN(maskOrChannel, contextId, queryId, eventName, ...) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire), __func = CARB_PRETTY_FUNCTION] { \
if (0) \
printf((eventName), ##__VA_ARGS__); \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
CARB_PROFILE_IF( \
CARB_PROFILE_HAS_VARARGS((eventName), ##__VA_ARGS__), \
static auto __tup = ::carb::profiler::detail::makeString2( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__)); \
__prof->beginGpuQueryDynamic(::carb::profiler::detail::maskHelper(__moc), __tup.first, __tup.second, \
__LINE__, (contextId), (queryId), (eventName), ##__VA_ARGS__), \
static auto __tup = ::carb::profiler::detail::makeString3( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__), \
__prof->registerStaticString("" eventName)); \
__prof->beginGpuQueryStatic(::carb::profiler::detail::maskHelper(__moc), __tup.first, \
__tup.second, __LINE__, (contextId), (queryId), __tup.third)); \
} \
}()
# define CARB_PROFILE_GPU_QUERY_END(maskOrChannel, contextId, queryId) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
__prof->endGpuQuery(::carb::profiler::detail::maskHelper(__moc), (contextId), (queryId)); \
} \
}()
# define CARB_PROFILE_GPU_SET_QUERY_VALUE(maskOrChannel, contextId, queryId, gpuTimestamp) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
__prof->setGpuQueryValue( \
::carb::profiler::detail::maskHelper(__moc), (contextId), (queryId), (gpuTimestamp)); \
} \
}()
# define CARB_PROFILE_LOCKABLE_CREATE(maskOrChannel, isSharedLock, name) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire), __func = CARB_PRETTY_FUNCTION] { \
auto&& __moc = (maskOrChannel); \
if (__prof && ::carb::profiler::detail::enabled(__moc)) \
{ \
static auto __tup = ::carb::profiler::detail::makeString2( \
__prof->registerStaticString(__func), __prof->registerStaticString(__FILE__)); \
return __prof->createLockable(::carb::profiler::detail::maskHelper(__moc), (name), (isSharedLock), \
__tup.first, __tup.second, __LINE__); \
} \
return ::carb::profiler::kInvalidLockableId; \
}()
# define CARB_PROFILE_LOCKABLE_DESTROY(lockableId) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
auto&& __id = (lockableId); \
if (__prof && __id != carb::profiler::kInvalidLockableId) \
{ \
__prof->destroyLockable(__id); \
} \
}()
# define CARB_PROFILE_LOCKABLE_OPERATION(lockableId, operation) \
[&, __prof = ::g_carbProfiler.load(std::memory_order_acquire)] { \
auto&& __id = (lockableId); \
if (__prof && __id != carb::profiler::kInvalidLockableId) \
{ \
__prof->lockableOperation(__id, (operation)); \
} \
}()
#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*)
{
g_carbProfiler.store(nullptr, std::memory_order_seq_cst);
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);
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(std::memory_order order = std::memory_order_seq_cst)
{
return g_carbProfiler.load(order);
}
inline void deregisterProfilerForClient() noexcept
{
if (std::exchange(detail::registered(), false))
{
auto fw = getFramework();
auto handle = std::exchange(detail::loadHookHandle(), kInvalidLoadHook);
IProfiler* profiler = 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);
}
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