Skip to content

Commit

Permalink
Profiler: Add Tracy backend
Browse files Browse the repository at this point in the history
This differs from the existing GPUVis backend in a number of ways:
* Tracy is optimized for minimal overhead and nanosecond-resolution profiling
* Tracy supports live tracing (in addition to capture-based operation)
* Tracy has a richer feature set and a more polished UI (notably, statistics and histograms are generated out-of-the-box)
* GPUVis supports tracing multiple processes, whereas Tracy is single-process only

To use this backend, one of the environment variables FEX_PROFILE_TARGET_NAME
or FEX_PROFILE_TARGET_PATH must be defined to select the application under
profile by name or by path suffix.
  • Loading branch information
neobrain committed Jan 23, 2025
1 parent 5e2c7e9 commit 7650aef
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 8 deletions.
16 changes: 15 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ option(ENABLE_VIXL_SIMULATOR "Enable use of VIXL simulator for emulation (only u
option(ENABLE_VIXL_DISASSEMBLER "Enables debug disassembler output with VIXL" FALSE)
option(USE_LEGACY_BINFMTMISC "Uses legacy method of setting up binfmt_misc" FALSE)
option(ENABLE_FEXCORE_PROFILER "Enables use of the FEXCore timeline profiling capabilities" FALSE)
set (FEXCORE_PROFILER_BACKEND "gpuvis" CACHE STRING "Set which backend you want to use for the FEXCore profiler")
set (FEXCORE_PROFILER_BACKEND "gpuvis" CACHE STRING "Set which backend to use for the FEXCore profiler (gpuvis, tracy)")
option(ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT "Enables glibc memory allocation hooking with fault for CI testing")
option(USE_PDB_DEBUGINFO "Builds debug info in PDB format" FALSE)

Expand Down Expand Up @@ -61,6 +61,16 @@ if (ENABLE_FEXCORE_PROFILER)

if (FEXCORE_PROFILER_BACKEND STREQUAL "GPUVIS")
add_definitions(-DFEXCORE_PROFILER_BACKEND=1)
elseif (FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
add_definitions(-DFEXCORE_PROFILER_BACKEND=2)
# Required so that Tracy will only start in the selected guest application
add_definitions(-DTRACY_MANUAL_LIFETIME=1)
add_definitions(-DTRACY_DELAYED_INIT=1)
# This interferes with FEX's signal handling
add_definitions(-DTRACY_NO_CRASH_HANDLER=1)
# Tracy can gather call stack samples in regular intervals, but this
# isn't useful for us since it would usually sample opaque JIT code
add_definitions(-DTRACY_NO_SAMPLING=1)
else()
message(FATAL_ERROR "Unknown FEXCore profiler backend ${FEXCORE_PROFILER_BACKEND}")
endif()
Expand Down Expand Up @@ -270,6 +280,10 @@ if (BUILD_TESTS OR ENABLE_VIXL_DISASSEMBLER OR ENABLE_VIXL_SIMULATOR)
include_directories(SYSTEM External/vixl/src/)
endif()

if (ENABLE_FEXCORE_PROFILER AND FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
add_subdirectory(External/tracy)
endif()

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# This means we were attempted to get compiled with GCC
message(FATAL_ERROR "FEX doesn't support getting compiled with GCC!")
Expand Down
4 changes: 4 additions & 0 deletions FEXCore/Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ add_library(FEXCore_Base STATIC ${FEXCORE_BASE_SRCS})
target_link_libraries(FEXCore_Base ${LIBS})
AddDefaultOptionsToTarget(FEXCore_Base)

if (ENABLE_FEXCORE_PROFILER AND FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
target_link_libraries(FEXCore_Base TracyClient)
endif()

function(AddObject Name Type)
add_library(${Name} ${Type} ${SRCS})

Expand Down
41 changes: 40 additions & 1 deletion FEXCore/Source/Utils/Profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#define BACKEND_OFF 0
#define BACKEND_GPUVIS 1
#define BACKEND_TRACY 2

#ifdef ENABLE_FEXCORE_PROFILER
#ifndef _WIN32
Expand Down Expand Up @@ -110,35 +111,73 @@ void TraceObject(std::string_view const Format) {
}
}
} // namespace GPUVis
#elif FEXCORE_PROFILER_BACKEND == BACKEND_TRACY
#include "tracy/TracyC.h"
namespace Tracy {
void Init() {}

void Shutdown() {}

void TraceObject(std::string_view const Format, uint64_t Duration) {}

void TraceObject(std::string_view const Format) {}
} // namespace Tracy
#else
#error Unknown profiler backend
#endif
#endif

extern "C" bool g_Enable = false;
namespace FEXCore::Profiler {
#ifdef ENABLE_FEXCORE_PROFILER
void Init() {
void Init(bool Enable) {
#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS
GPUVis::Init();
#elif FEXCORE_PROFILER_BACKEND == BACKEND_TRACY
Tracy::Init();
g_Enable = Enable;
if (g_Enable) {
tracy::StartupProfiler();
}
#endif
}

bool IsActive() {
#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS
// Always active
return true;
#elif FEXCORE_PROFILER_BACKEND == BACKEND_TRACY
// Active if previously enabled
return g_Enable;
#endif
}

void Shutdown() {
#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS
GPUVis::Shutdown();
#elif FEXCORE_PROFILER_BACKEND == BACKEND_TRACY
if (g_Enable) {
tracy::ShutdownProfiler();
}
Tracy::Shutdown();
#endif
}

void TraceObject(std::string_view const Format, uint64_t Duration) {
#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS
GPUVis::TraceObject(Format, Duration);
#elif FEXCORE_PROFILER_BACKEND == BACKEND_TRACY
Tracy::TraceObject(Format, Duration);
#endif
}

void TraceObject(std::string_view const Format) {
#if FEXCORE_PROFILER_BACKEND == BACKEND_GPUVIS
GPUVis::TraceObject(Format);
#elif FEXCORE_PROFILER_BACKEND == BACKEND_TRACY
Tracy::TraceObject(Format);
#endif
}

#endif
} // namespace FEXCore::Profiler
16 changes: 11 additions & 5 deletions FEXCore/include/FEXCore/Utils/Profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
#include <string_view>

#include <FEXCore/Utils/CompilerDefs.h>
#if defined(ENABLE_FEXCORE_PROFILER) && FEXCORE_PROFILER_BACKEND == 2
#include "tracy/Tracy.hpp"
#endif

namespace FEXCore::Profiler {
#ifdef ENABLE_FEXCORE_PROFILER

FEX_DEFAULT_VISIBILITY void Init();
FEX_DEFAULT_VISIBILITY void Init(bool Active);
FEX_DEFAULT_VISIBILITY bool IsActive();
FEX_DEFAULT_VISIBILITY void Shutdown();
FEX_DEFAULT_VISIBILITY void TraceObject(std::string_view const Format);
FEX_DEFAULT_VISIBILITY void TraceObject(std::string_view const Format, uint64_t Duration);
Expand All @@ -25,18 +29,20 @@ class ProfilerBlock final {
std::string_view const Format;
};

#define UniqueScopeName2(name, line) name##line
#define UniqueScopeName(name, line) UniqueScopeName2(name, line)
//#define UniqueScopeName2(name, line) name##line
//#define UniqueScopeName(name, line) UniqueScopeName2(name, line)

// Declare an instantaneous profiler event.
#define FEXCORE_PROFILE_INSTANT(name) FEXCore::Profiler::TraceObject(name)

// Declare a scoped profile block variable with a fixed name.
#define FEXCORE_PROFILE_SCOPED(name) FEXCore::Profiler::ProfilerBlock UniqueScopeName(ScopedBlock_, __LINE__)(name)
//#define FEXCORE_PROFILE_SCOPED(name) FEXCore::Profiler::ProfilerBlock UniqueScopeName(ScopedBlock_, __LINE__)(name)
#define FEXCORE_PROFILE_SCOPED(name) \
ZoneNamedN( ___tracy_scoped_zone, name, ::FEXCore::Profiler::IsActive())

#else
[[maybe_unused]]
static void Init() {}
static void Init(bool Active) {}
[[maybe_unused]]
static void Shutdown() {}
[[maybe_unused]]
Expand Down
5 changes: 4 additions & 1 deletion Source/Tools/FEXLoader/FEXLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,10 @@ int main(int argc, char** argv, char** const envp) {
std::this_thread::sleep_for(std::chrono::seconds(StartupSleep()));
}

FEXCore::Profiler::Init();
const char* ProfileTargetName = getenv("FEX_PROFILE_TARGET_NAME"); // Match by application name
const char* ProfileTargetPath = getenv("FEX_PROFILE_TARGET_PATH"); // Match by path suffix
FEXCore::Profiler::Init((ProfileTargetName && Program.ProgramName == ProfileTargetName) ||
(ProfileTargetPath && Program.ProgramPath.ends_with(ProfileTargetPath)));
FEXCore::Telemetry::Initialize();

if (!LDPath().empty() && Program.ProgramPath.starts_with(LDPath())) {
Expand Down
4 changes: 4 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ desc: Handles host -> host and host -> guest signal routing, emulates procmask &
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/MathUtils.h>
#include <FEXCore/Utils/FPState.h>
#include <FEXCore/Utils/Profiler.h>
#include <FEXCore/Utils/ArchHelpers/Arm64.h>
#include <FEXHeaderUtils/Syscalls.h>

Expand Down Expand Up @@ -59,6 +60,7 @@ static FEX::HLE::ThreadStateObject* GetThreadFromAltStack(const stack_t& alt_sta
static void SignalHandlerThunk(int Signal, siginfo_t* Info, void* UContext) {
ucontext_t* _context = (ucontext_t*)UContext;
auto ThreadObject = GetThreadFromAltStack(_context->uc_stack);
FEXCORE_PROFILE_SCOPED("GuestSignalHandler");
ThreadObject->SignalInfo.Delegator->HandleSignal(ThreadObject, Signal, Info, UContext);
}

Expand Down Expand Up @@ -916,6 +918,8 @@ SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::str
return false;
}

FEXCORE_PROFILE_SCOPED("HandleAuxSIGBUS");

const auto Delegator = FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator;
const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, Delegator->GetUnalignedHandlerType(), PC,
ArchHelpers::Context::GetArmGPRs(ucontext));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ desc: SMC/MMan Tracking
#include <FEXCore/Debug/InternalThreadState.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/MathUtils.h>
#include <FEXCore/Utils/Profiler.h>
#include <FEXCore/Utils/SignalScopeGuards.h>
#include <FEXCore/Utils/TypeDefines.h>

Expand Down Expand Up @@ -54,6 +55,8 @@ bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState* Thread,
// Can't use the deferred signal lock in the SIGSEGV handler.
auto lk = FEXCore::MaskSignalsAndLockMutex<std::shared_lock>(_SyscallHandler->VMATracking.Mutex);

FEXCORE_PROFILE_SCOPED("SMC segfault");

auto VMATracking = &_SyscallHandler->VMATracking;

// If the write spans two pages, they will be flushed one at a time (generating two faults)
Expand Down

0 comments on commit 7650aef

Please sign in to comment.