diff options
Diffstat (limited to 'src/zencore/profiling')
| -rw-r--r-- | src/zencore/profiling/counterstrace.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/zencore/profiling/counterstrace.cpp b/src/zencore/profiling/counterstrace.cpp new file mode 100644 index 000000000..63e8a2dd3 --- /dev/null +++ b/src/zencore/profiling/counterstrace.cpp @@ -0,0 +1,99 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zencore/profiling/counterstrace.h> + +#if ZEN_WITH_TRACE + +# include <zencore/timer.h> +# include <zencore/trace.h> + +# include <atomic> +# include <cstring> + +namespace { + +// Wire-compatible with UE's CountersTrace events (Counters.Spec / +// SetValueInt / SetValueFloat). Channel name matches UE so users can mix & +// match analyzers. +UE_TRACE_CHANNEL_DEFINE(CountersChannel) + +UE_TRACE_EVENT_BEGIN(Counters, Spec, NoSync | Important) + UE_TRACE_EVENT_FIELD(uint16_t, Id) + UE_TRACE_EVENT_FIELD(uint8_t, Type) + UE_TRACE_EVENT_FIELD(uint8_t, DisplayHint) + UE_TRACE_EVENT_FIELD(UE::Trace::AnsiString, Name) +UE_TRACE_EVENT_END() + +UE_TRACE_EVENT_BEGIN(Counters, SetValueInt) + UE_TRACE_EVENT_FIELD(uint64_t, Cycle) + UE_TRACE_EVENT_FIELD(int64_t, Value) + UE_TRACE_EVENT_FIELD(uint16_t, CounterId) +UE_TRACE_EVENT_END() + +UE_TRACE_EVENT_BEGIN(Counters, SetValueFloat) + UE_TRACE_EVENT_FIELD(uint64_t, Cycle) + UE_TRACE_EVENT_FIELD(double, Value) + UE_TRACE_EVENT_FIELD(uint16_t, CounterId) +UE_TRACE_EVENT_END() + +} // namespace + +namespace zen::counters_detail { + +uint16_t +OutputInitCounter(const char* Name, TraceCounterType Type, TraceCounterDisplayHint Hint) +{ + if (!UE_TRACE_CHANNELEXPR_IS_ENABLED(CountersChannel) || Name == nullptr) + { + return 0; + } + + // Counter ids are uint16; tourist's analyzer truncates anyway. Wrapping + // past 0xFFFF would re-use ids, so we cap allocation -- in practice no + // real-world trace uses anywhere near 65k distinct counters. + static std::atomic<uint32_t> g_NextId{0}; + uint32_t Allocated = g_NextId.fetch_add(1, std::memory_order_relaxed) + 1; + if (Allocated > 0xFFFFu) + { + return 0; + } + uint16_t Id = uint16_t(Allocated); + + uint16_t NameLen = uint16_t(std::strlen(Name)); + UE_TRACE_LOG(Counters, Spec, CountersChannel, NameLen * sizeof(char)) + << Spec.Id(Id) << Spec.Type(uint8_t(Type)) << Spec.DisplayHint(uint8_t(Hint)) << Spec.Name(Name, NameLen); + + return Id; +} + +void +OutputSetValueInt(uint16_t Id, int64_t Value) +{ + if (Id == 0 || !UE_TRACE_CHANNELEXPR_IS_ENABLED(CountersChannel)) + { + return; + } + UE_TRACE_LOG(Counters, SetValueInt, CountersChannel) + << SetValueInt.Cycle(zen::GetHifreqTimerValue()) << SetValueInt.Value(Value) << SetValueInt.CounterId(Id); +} + +void +OutputSetValueFloat(uint16_t Id, double Value) +{ + if (Id == 0 || !UE_TRACE_CHANNELEXPR_IS_ENABLED(CountersChannel)) + { + return; + } + UE_TRACE_LOG(Counters, SetValueFloat, CountersChannel) + << SetValueFloat.Cycle(zen::GetHifreqTimerValue()) << SetValueFloat.Value(Value) << SetValueFloat.CounterId(Id); +} + +bool +IsCountersChannelEnabled() +{ + return UE_TRACE_CHANNELEXPR_IS_ENABLED(CountersChannel); +} + +} // namespace zen::counters_detail + +#endif // ZEN_WITH_TRACE |