From 1f34d836b4fb37997e58958630fee5ffb3a678ec Mon Sep 17 00:00:00 2001 From: Gamer64 Date: Sat, 2 Aug 2025 17:22:38 +0200 Subject: [PATCH] Add cmake option to enable microprofile (#179) Backported from https://github.com/azahar-emu/azahar/commit/dd9c743041308112c8dc349c5c237c04b2c4c75f. Co-authored-by: PabloMK7 Co-authored-by: Shinmegumi Co-authored-by: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/179 Co-authored-by: Gamer64 Co-committed-by: Gamer64 --- CMakeLists.txt | 2 ++ externals/CMakeLists.txt | 8 ++++++++ src/core/core.cpp | 6 ++++++ src/core/core.h | 2 ++ src/core/core_timing.cpp | 2 ++ src/core/cpu_manager.cpp | 2 ++ src/core/hle/kernel/kernel.cpp | 2 ++ src/core/hle/kernel/kernel.h | 2 ++ src/core/hle/kernel/physical_core.cpp | 4 ++++ src/core/hle/kernel/svc.cpp | 4 ++++ src/video_core/fence_manager.h | 2 ++ src/video_core/gpu_thread.cpp | 2 ++ src/yuzu/debugger/profiler.cpp | 14 ++++++-------- src/yuzu/debugger/profiler.h | 6 ++++++ src/yuzu/main.cpp | 8 ++++++++ src/yuzu/main.h | 4 ++++ src/yuzu_cmd/yuzu.cpp | 5 ++--- 17 files changed, 64 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c2a880ae0..f775cdf87b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,8 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) +option(ENABLE_MICROPROFILE "Enables microprofile capabilities" OFF) + option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}") if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index cd7b80a33c..c15bd6eefc 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2016 Citra Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later @@ -51,6 +54,11 @@ endif() # MicroProfile add_library(microprofile INTERFACE) target_include_directories(microprofile INTERFACE ./microprofile) +if (ENABLE_MICROPROFILE) + target_compile_definitions(microprofile INTERFACE MICROPROFILE_ENABLED=1) +else() + target_compile_definitions(microprofile INTERFACE MICROPROFILE_ENABLED=0) +endif() # GCC bugs if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND MINGW) diff --git a/src/core/core.cpp b/src/core/core.cpp index ae184f8a88..8aef26d93f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -289,10 +289,12 @@ struct System::Impl { exit_locked = false; exit_requested = false; +#if MICROPROFILE_ENABLED microprofile_cpu[0] = MICROPROFILE_TOKEN(ARM_CPU0); microprofile_cpu[1] = MICROPROFILE_TOKEN(ARM_CPU1); microprofile_cpu[2] = MICROPROFILE_TOKEN(ARM_CPU2); microprofile_cpu[3] = MICROPROFILE_TOKEN(ARM_CPU3); +#endif if (Settings::values.enable_renderdoc_hotkey) { renderdoc_api = std::make_unique(); @@ -573,7 +575,9 @@ struct System::Impl { std::stop_source stop_event; std::array dynarmic_ticks{}; +#if MICROPROFILE_ENABLED std::array microprofile_cpu{}; +#endif std::array gpu_dirty_memory_managers; @@ -952,6 +956,7 @@ void System::RegisterHostThread() { impl->kernel.RegisterHostThread(); } +#if MICROPROFILE_ENABLED void System::EnterCPUProfile() { std::size_t core = impl->kernel.GetCurrentHostThreadID(); impl->dynarmic_ticks[core] = MicroProfileEnter(impl->microprofile_cpu[core]); @@ -961,6 +966,7 @@ void System::ExitCPUProfile() { std::size_t core = impl->kernel.GetCurrentHostThreadID(); MicroProfileLeave(impl->microprofile_cpu[core], impl->dynarmic_ticks[core]); } +#endif bool System::IsMulticore() const { return impl->is_multicore; diff --git a/src/core/core.h b/src/core/core.h index b33cb0c4f7..3f1a3f0388 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -396,11 +396,13 @@ public: /// Register a host thread as an auxiliary thread. void RegisterHostThread(); +#if MICROPROFILE_ENABLED /// Enter CPU Microprofile void EnterCPUProfile(); /// Exit CPU Microprofile void ExitCPUProfile(); +#endif /// Tells if system is running on multicore. [[nodiscard]] bool IsMulticore() const; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index ed07e80ce2..646f12708e 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -61,7 +61,9 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) { Common::SetCurrentThreadPriority(Common::ThreadPriority::High); instance.on_thread_init(); instance.ThreadLoop(); +#if MICROPROFILE_ENABLED MicroProfileOnThreadExit(); +#endif } void CoreTiming::Initialize(std::function&& on_thread_init_) { diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 9b1c773877..1b838eea59 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -201,7 +201,9 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) { // Cleanup SCOPE_EXIT { data.host_context->Exit(); +#if MICROPROFILE_ENABLED MicroProfileOnThreadExit(); +#endif }; // Running diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 9e5eaeec43..7a851e9b02 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1278,6 +1278,7 @@ void KernelCore::ExceptionalExitApplication() { SuspendEmulation(true); } +#if MICROPROFILE_ENABLED void KernelCore::EnterSVCProfile() { impl->svc_ticks[CurrentPhysicalCoreIndex()] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); } @@ -1285,6 +1286,7 @@ void KernelCore::EnterSVCProfile() { void KernelCore::ExitSVCProfile() { MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]); } +#endif Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { return impl->slab_resource_counts; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 57182c0c8d..e11241d6aa 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -271,9 +271,11 @@ public: bool IsShuttingDown() const; +#if MICROPROFILE_ENABLED void EnterSVCProfile(); void ExitSVCProfile(); +#endif /// Workaround for single-core mode when preempting threads while idle. bool IsPhantomModeForSingleCore() const; diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 0f45a32494..3321032563 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -27,7 +27,9 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) { interface->Initialize(); const auto EnterContext = [&]() { +#if MICROPROFILE_ENABLED system.EnterCPUProfile(); +#endif // Lock the core context. std::scoped_lock lk{m_guard}; @@ -59,7 +61,9 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) { m_arm_interface = nullptr; m_current_thread = nullptr; +#if MICROPROFILE_ENABLED system.ExitCPUProfile(); +#endif }; while (true) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c55dc0c8ad..b1ce1e9daa 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -4428,7 +4428,9 @@ void Call(Core::System& system, u32 imm) { std::array args; kernel.CurrentPhysicalCore().SaveSvcArguments(process, args); +#if MICROPROFILE_ENABLED kernel.EnterSVCProfile(); +#endif if (process.Is64Bit()) { Call64(system, imm, args); @@ -4436,7 +4438,9 @@ void Call(Core::System& system, u32 imm) { Call32(system, imm, args); } +#if MICROPROFILE_ENABLED kernel.ExitSVCProfile(); +#endif kernel.CurrentPhysicalCore().LoadSvcArguments(process, args); } diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index dd67bc6d9b..322dfe832b 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h @@ -219,9 +219,11 @@ private: MicroProfileOnThreadCreate(name.c_str()); // Cleanup +#if MICROPROFILE_ENABLED SCOPE_EXIT { MicroProfileOnThreadExit(); }; +#endif Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadPriority(Common::ThreadPriority::High); diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index e2bfdcd7fd..2b4bce4f8d 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -23,9 +23,11 @@ static void RunThread(std::stop_token stop_token, Core::System& system, Tegra::Control::Scheduler& scheduler, SynchState& state) { std::string name = "GPU"; MicroProfileOnThreadCreate(name.c_str()); +#if MICROPROFILE_ENABLED SCOPE_EXIT { MicroProfileOnThreadExit(); }; +#endif Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp index 493ee0b178..55d4298fa6 100644 --- a/src/yuzu/debugger/profiler.cpp +++ b/src/yuzu/debugger/profiler.cpp @@ -1,6 +1,11 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#if MICROPROFILE_ENABLED + #include #include #include @@ -14,7 +19,7 @@ // Include the implementation of the UI in this file. This isn't in microprofile.cpp because the // non-Qt frontends don't need it (and don't implement the UI drawing hooks either). -#if MICROPROFILE_ENABLED + #define MICROPROFILEUI_IMPL 1 #include "common/microprofileui.h" @@ -43,8 +48,6 @@ private: qreal x_scale = 1.0, y_scale = 1.0; }; -#endif - MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { setObjectName(QStringLiteral("MicroProfile")); setWindowTitle(tr("&MicroProfile")); @@ -52,8 +55,6 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Di // Enable the maximize button setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint); -#if MICROPROFILE_ENABLED - MicroProfileWidget* widget = new MicroProfileWidget(this); QLayout* layout = new QVBoxLayout(this); @@ -66,7 +67,6 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Di setFocusProxy(widget); widget->setFocusPolicy(Qt::StrongFocus); widget->setFocus(); -#endif } QAction* MicroProfileDialog::toggleViewAction() { @@ -94,8 +94,6 @@ void MicroProfileDialog::hideEvent(QHideEvent* ev) { QWidget::hideEvent(ev); } -#if MICROPROFILE_ENABLED - /// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the /// QPainter available inside the drawing callbacks. static QPainter* mp_painter = nullptr; diff --git a/src/yuzu/debugger/profiler.h b/src/yuzu/debugger/profiler.h index 4c8ccd3c2f..caf81bdd9b 100644 --- a/src/yuzu/debugger/profiler.h +++ b/src/yuzu/debugger/profiler.h @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#if MICROPROFILE_ENABLED + #include class QAction; @@ -25,3 +30,4 @@ protected: private: QAction* toggle_view_action = nullptr; }; +#endif diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9b35069307..a46c5cd881 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1348,6 +1348,11 @@ void GMainWindow::InitializeDebugWidgets() { microProfileDialog = new MicroProfileDialog(this); microProfileDialog->hide(); debug_menu->addAction(microProfileDialog->toggleViewAction()); +#else + auto micro_profile_stub = new QAction(tr("MicroProfile (unavailable)"), this); + micro_profile_stub->setEnabled(false); + micro_profile_stub->setChecked(false); + debug_menu->addAction(micro_profile_stub); #endif waitTreeWidget = new WaitTreeWidget(*system, this); @@ -5630,10 +5635,13 @@ int main(int argc, char* argv[]) { #endif Common::DetachedTasks detached_tasks; + +#if MICROPROFILE_ENABLED MicroProfileOnThreadCreate("Frontend"); SCOPE_EXIT { MicroProfileShutdown(); }; +#endif Common::ConfigureNvidiaEnvironmentFlags(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7e7c00ec0b..b6f818099a 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -43,7 +43,9 @@ class GameList; class GImageInfo; class GRenderWindow; class LoadingScreen; +#if MICROPROFILE_ENABLED class MicroProfileDialog; +#endif class OverlayDialog; class ProfilerWidget; class ControllerDialog; @@ -565,7 +567,9 @@ private: // Debugger panes ProfilerWidget* profilerWidget; +#if MICROPROFILE_ENABLED MicroProfileDialog* microProfileDialog; +#endif WaitTreeWidget* waitTreeWidget; ControllerDialog* controller_dialog; diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 9bf88c5d9f..6acf7c0ace 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -4,9 +4,6 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - #include #include #include @@ -338,10 +335,12 @@ int main(int argc, char** argv) { LocalFree(argv_w); #endif +#if MICROPROFILE_ENABLED MicroProfileOnThreadCreate("EmuThread"); SCOPE_EXIT { MicroProfileShutdown(); }; +#endif Common::ConfigureNvidiaEnvironmentFlags();