// Copyright Epic Games, Inc. All Rights Reserved. #if ZEN_WITH_TRACE # include # include # include # include # include # define TRACE_IMPLEMENT 1 # undef _WINSOCK_DEPRECATED_NO_WARNINGS # include # include # include namespace zen { void TraceConfigure(const TraceOptions& Options) { // Configure channels based on command line options using namespace std::literals; std::function ProcessChannelList; auto ProcessTraceArg = [&](const std::string_view& Arg) { if (Arg == "default"sv) { ProcessChannelList("cpu,log"sv); } else if (Arg == "memory"sv) { ProcessChannelList("memtag,memalloc,callstack,module"sv); } else if (Arg == "memory_light"sv) { ProcessChannelList("memtag,memalloc"sv); } else if (Arg == "memtag"sv) { // memtag actually traces to the memalloc channel ProcessChannelList("memalloc"sv); } else { // Presume that the argument is a trace channel name StringBuilder<128> AnsiChannel; AnsiChannel << Arg; const bool IsEnabled = trace::ToggleChannel(AnsiChannel.c_str(), true); if (IsEnabled == false) { // Logging here could be iffy, but we might want some other feedback mechanism here // to indicate to users that they're not getting what they might be expecting } } }; ProcessChannelList = [&](const std::string_view& OptionArgs) { IterateCommaSeparatedValue(OptionArgs, ProcessTraceArg); }; if (Options.Channels.empty()) { ProcessTraceArg("default"sv); } else { ProcessChannelList(Options.Channels); } if (Options.Host.size()) { trace::SendTo(Options.Host.c_str()); } else if (Options.File.size()) { trace::WriteTo(Options.File.c_str()); } # if ZEN_WITH_MEMTRACK FMalloc* TraceMalloc = MemoryTrace_Create(GMalloc, Options); if (TraceMalloc != GMalloc) { GMalloc = TraceMalloc; MemoryTrace_Initialize(); } # endif } void TraceInit(std::string_view ProgramName) { static std::atomic_bool gInited = false; bool Expected = false; if (!gInited.compare_exchange_strong(Expected, true)) { return; } trace::FInitializeDesc Desc = { .bUseImportantCache = true, }; trace::Initialize(Desc); # if ZEN_PLATFORM_WINDOWS const char* CommandLineString = GetCommandLineA(); # else const char* CommandLineString = ""; # endif trace::ThreadRegister("main", /* system id */ 0, /* sort id */ 0); trace::DescribeSession(ProgramName, # if ZEN_BUILD_DEBUG trace::Build::Debug, # else trace::Build::Development, # endif CommandLineString, ZEN_CFG_VERSION_BUILD_STRING); atexit([] { # if ZEN_WITH_MEMTRACK zen::MemoryTrace_Shutdown(); # endif trace::Update(); TraceShutdown(); }); } void TraceShutdown() { (void)TraceStop(); trace::Shutdown(); } bool IsTracing() { return trace::IsTracing(); } bool TraceStop() { if (trace::Stop()) { return true; } return false; } bool GetTraceOptionsFromCommandline(TraceOptions& OutOptions) { bool HasOptions = false; # if ZEN_WITH_TRACE using namespace std::literals; auto MatchesArg = [](std::string_view Option, std::string_view Arg) -> std::optional { if (Arg.starts_with(Option)) { std::string_view::value_type DelimChar = Arg[Option.length()]; if (DelimChar == ' ' || DelimChar == '=') { return Arg.substr(Option.size() + 1); } } return {}; }; constexpr std::string_view TraceOption = "--trace"sv; constexpr std::string_view TraceHostOption = "--tracehost"sv; constexpr std::string_view TraceFileOption = "--tracefile"sv; std::function ProcessArg = [&](const std::string_view& Arg) { if (auto Host = MatchesArg(TraceHostOption, Arg); Host.has_value()) { OutOptions.Host = Host.value(); HasOptions = true; } else if (auto File = MatchesArg(TraceFileOption, Arg); File.has_value()) { OutOptions.File = File.value(); HasOptions = true; } else if (auto Channels = MatchesArg(TraceOption, Arg); Channels.has_value()) { if (!OutOptions.Channels.empty()) { OutOptions.Channels = ","sv; } OutOptions.Channels += Channels.value(); HasOptions = true; } }; IterateCommandlineArgs(ProcessArg); # endif // ZEN_WITH_TRACE return HasOptions; } } // namespace zen #endif // ZEN_WITH_TRACE