// Copyright Epic Games, Inc. All Rights Reserved. #include #if ZEN_WITH_TRACE # include # include # include # include 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 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