diff options
| author | 2017-02-19 14:34:47 -0800 | |
|---|---|---|
| committer | 2017-02-26 17:22:03 -0800 | |
| commit | c75ae6c585f651a1b7c162c2e1ecccd22a1c587d (patch) | |
| tree | 30d51f39c6b57244e1ede29820c3f5d98ca38451 /src | |
| parent | SynchronizedWrapper: Add Lock convenience method (diff) | |
| download | yuzu-c75ae6c585f651a1b7c162c2e1ecccd22a1c587d.tar.gz yuzu-c75ae6c585f651a1b7c162c2e1ecccd22a1c587d.tar.xz yuzu-c75ae6c585f651a1b7c162c2e1ecccd22a1c587d.zip | |
Add performance statistics to status bar
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/main.cpp | 27 | ||||
| -rw-r--r-- | src/citra_qt/main.h | 3 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/core.cpp | 9 | ||||
| -rw-r--r-- | src/core/core.h | 7 | ||||
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 3 | ||||
| -rw-r--r-- | src/core/hw/gpu.cpp | 4 | ||||
| -rw-r--r-- | src/core/hw/gpu.h | 2 | ||||
| -rw-r--r-- | src/core/perf_stats.cpp | 53 | ||||
| -rw-r--r-- | src/core/perf_stats.h | 43 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 9 |
11 files changed, 159 insertions, 3 deletions
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 43530b275..41356a6ca 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -253,6 +253,8 @@ void GMainWindow::ConnectWidgetEvents() { | |||
| 253 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, | 253 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, |
| 254 | SLOT(OnEmulationStarting(EmuThread*))); | 254 | SLOT(OnEmulationStarting(EmuThread*))); |
| 255 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); | 255 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); |
| 256 | |||
| 257 | connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); | ||
| 256 | } | 258 | } |
| 257 | 259 | ||
| 258 | void GMainWindow::ConnectMenuEvents() { | 260 | void GMainWindow::ConnectMenuEvents() { |
| @@ -401,6 +403,8 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 401 | if (ui.action_Single_Window_Mode->isChecked()) { | 403 | if (ui.action_Single_Window_Mode->isChecked()) { |
| 402 | game_list->hide(); | 404 | game_list->hide(); |
| 403 | } | 405 | } |
| 406 | status_bar_update_timer.start(1000); | ||
| 407 | |||
| 404 | render_window->show(); | 408 | render_window->show(); |
| 405 | render_window->setFocus(); | 409 | render_window->setFocus(); |
| 406 | 410 | ||
| @@ -435,6 +439,12 @@ void GMainWindow::ShutdownGame() { | |||
| 435 | render_window->hide(); | 439 | render_window->hide(); |
| 436 | game_list->show(); | 440 | game_list->show(); |
| 437 | 441 | ||
| 442 | // Disable status bar updates | ||
| 443 | status_bar_update_timer.stop(); | ||
| 444 | emu_speed_label->setVisible(false); | ||
| 445 | game_fps_label->setVisible(false); | ||
| 446 | emu_frametime_label->setVisible(false); | ||
| 447 | |||
| 438 | emulation_running = false; | 448 | emulation_running = false; |
| 439 | } | 449 | } |
| 440 | 450 | ||
| @@ -614,6 +624,23 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() { | |||
| 614 | graphicsSurfaceViewerWidget->show(); | 624 | graphicsSurfaceViewerWidget->show(); |
| 615 | } | 625 | } |
| 616 | 626 | ||
| 627 | void GMainWindow::UpdateStatusBar() { | ||
| 628 | if (emu_thread == nullptr) { | ||
| 629 | status_bar_update_timer.stop(); | ||
| 630 | return; | ||
| 631 | } | ||
| 632 | |||
| 633 | auto results = Core::System::GetInstance().GetAndResetPerfStats(); | ||
| 634 | |||
| 635 | emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 2)); | ||
| 636 | game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 1)); | ||
| 637 | emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); | ||
| 638 | |||
| 639 | emu_speed_label->setVisible(true); | ||
| 640 | game_fps_label->setVisible(true); | ||
| 641 | emu_frametime_label->setVisible(true); | ||
| 642 | } | ||
| 643 | |||
| 617 | bool GMainWindow::ConfirmClose() { | 644 | bool GMainWindow::ConfirmClose() { |
| 618 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) | 645 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) |
| 619 | return true; | 646 | return true; |
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 3cbf4ea99..ec841eaa5 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h | |||
| @@ -127,6 +127,8 @@ private slots: | |||
| 127 | void OnCreateGraphicsSurfaceViewer(); | 127 | void OnCreateGraphicsSurfaceViewer(); |
| 128 | 128 | ||
| 129 | private: | 129 | private: |
| 130 | void UpdateStatusBar(); | ||
| 131 | |||
| 130 | Ui::MainWindow ui; | 132 | Ui::MainWindow ui; |
| 131 | 133 | ||
| 132 | GRenderWindow* render_window; | 134 | GRenderWindow* render_window; |
| @@ -136,6 +138,7 @@ private: | |||
| 136 | QLabel* emu_speed_label = nullptr; | 138 | QLabel* emu_speed_label = nullptr; |
| 137 | QLabel* game_fps_label = nullptr; | 139 | QLabel* game_fps_label = nullptr; |
| 138 | QLabel* emu_frametime_label = nullptr; | 140 | QLabel* emu_frametime_label = nullptr; |
| 141 | QTimer status_bar_update_timer; | ||
| 139 | 142 | ||
| 140 | std::unique_ptr<Config> config; | 143 | std::unique_ptr<Config> config; |
| 141 | 144 | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5332e35a3..1adc78d8d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -170,6 +170,7 @@ set(SRCS | |||
| 170 | loader/smdh.cpp | 170 | loader/smdh.cpp |
| 171 | tracer/recorder.cpp | 171 | tracer/recorder.cpp |
| 172 | memory.cpp | 172 | memory.cpp |
| 173 | perf_stats.cpp | ||
| 173 | settings.cpp | 174 | settings.cpp |
| 174 | ) | 175 | ) |
| 175 | 176 | ||
| @@ -357,6 +358,7 @@ set(HEADERS | |||
| 357 | memory.h | 358 | memory.h |
| 358 | memory_setup.h | 359 | memory_setup.h |
| 359 | mmio.h | 360 | mmio.h |
| 361 | perf_stats.h | ||
| 360 | settings.h | 362 | settings.h |
| 361 | ) | 363 | ) |
| 362 | 364 | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index c9c9b7615..ca2c28ce4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -109,6 +109,11 @@ void System::PrepareReschedule() { | |||
| 109 | reschedule_pending = true; | 109 | reschedule_pending = true; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | PerfStats::Results System::GetAndResetPerfStats() { | ||
| 113 | auto perf_stats = this->perf_stats.Lock(); | ||
| 114 | return perf_stats->GetAndResetStats(CoreTiming::GetGlobalTimeUs()); | ||
| 115 | } | ||
| 116 | |||
| 112 | void System::Reschedule() { | 117 | void System::Reschedule() { |
| 113 | if (!reschedule_pending) { | 118 | if (!reschedule_pending) { |
| 114 | return; | 119 | return; |
| @@ -140,6 +145,10 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | |||
| 140 | 145 | ||
| 141 | LOG_DEBUG(Core, "Initialized OK"); | 146 | LOG_DEBUG(Core, "Initialized OK"); |
| 142 | 147 | ||
| 148 | // Reset counters and set time origin to current frame | ||
| 149 | GetAndResetPerfStats(); | ||
| 150 | perf_stats.Lock()->BeginSystemFrame(); | ||
| 151 | |||
| 143 | return ResultStatus::Success; | 152 | return ResultStatus::Success; |
| 144 | } | 153 | } |
| 145 | 154 | ||
diff --git a/src/core/core.h b/src/core/core.h index 17572a74f..3efc20c3d 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -6,9 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | |||
| 10 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/synchronized_wrapper.h" | ||
| 11 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 12 | #include "core/perf_stats.h" | ||
| 12 | 13 | ||
| 13 | class EmuWindow; | 14 | class EmuWindow; |
| 14 | class ARM_Interface; | 15 | class ARM_Interface; |
| @@ -83,6 +84,8 @@ public: | |||
| 83 | /// Prepare the core emulation for a reschedule | 84 | /// Prepare the core emulation for a reschedule |
| 84 | void PrepareReschedule(); | 85 | void PrepareReschedule(); |
| 85 | 86 | ||
| 87 | PerfStats::Results GetAndResetPerfStats(); | ||
| 88 | |||
| 86 | /** | 89 | /** |
| 87 | * Gets a reference to the emulated CPU. | 90 | * Gets a reference to the emulated CPU. |
| 88 | * @returns A reference to the emulated CPU. | 91 | * @returns A reference to the emulated CPU. |
| @@ -91,6 +94,8 @@ public: | |||
| 91 | return *cpu_core; | 94 | return *cpu_core; |
| 92 | } | 95 | } |
| 93 | 96 | ||
| 97 | Common::SynchronizedWrapper<PerfStats> perf_stats; | ||
| 98 | |||
| 94 | private: | 99 | private: |
| 95 | /** | 100 | /** |
| 96 | * Initialize the emulated system. | 101 | * Initialize the emulated system. |
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 1457518d4..67bab38da 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/bit_field.h" | 5 | #include "common/bit_field.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/event.h" | 8 | #include "core/hle/kernel/event.h" |
| 8 | #include "core/hle/kernel/shared_memory.h" | 9 | #include "core/hle/kernel/shared_memory.h" |
| 9 | #include "core/hle/result.h" | 10 | #include "core/hle/result.h" |
| @@ -280,6 +281,8 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | |||
| 280 | 281 | ||
| 281 | if (screen_id == 0) { | 282 | if (screen_id == 0) { |
| 282 | MicroProfileFlip(); | 283 | MicroProfileFlip(); |
| 284 | auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||
| 285 | perf_stats->EndGameFrame(); | ||
| 283 | } | 286 | } |
| 284 | 287 | ||
| 285 | return RESULT_SUCCESS; | 288 | return RESULT_SUCCESS; |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index fa8c13d36..7cf081aad 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -32,7 +32,7 @@ namespace GPU { | |||
| 32 | Regs g_regs; | 32 | Regs g_regs; |
| 33 | 33 | ||
| 34 | /// 268MHz CPU clocks / 60Hz frames per second | 34 | /// 268MHz CPU clocks / 60Hz frames per second |
| 35 | const u64 frame_ticks = BASE_CLOCK_RATE_ARM11 / 60; | 35 | const u64 frame_ticks = BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE; |
| 36 | /// Event id for CoreTiming | 36 | /// Event id for CoreTiming |
| 37 | static int vblank_event; | 37 | static int vblank_event; |
| 38 | /// Total number of frames drawn | 38 | /// Total number of frames drawn |
| @@ -41,7 +41,7 @@ static u64 frame_count; | |||
| 41 | static u32 time_point; | 41 | static u32 time_point; |
| 42 | /// Total delay caused by slow frames | 42 | /// Total delay caused by slow frames |
| 43 | static float time_delay; | 43 | static float time_delay; |
| 44 | constexpr float FIXED_FRAME_TIME = 1000.0f / 60; | 44 | constexpr float FIXED_FRAME_TIME = 1000.0f / SCREEN_REFRESH_RATE; |
| 45 | // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher | 45 | // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher |
| 46 | // values increases time needed to limit frame rate after spikes | 46 | // values increases time needed to limit frame rate after spikes |
| 47 | constexpr float MAX_LAG_TIME = 18; | 47 | constexpr float MAX_LAG_TIME = 18; |
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index d53381216..bdd997b2a 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h | |||
| @@ -13,6 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | namespace GPU { | 14 | namespace GPU { |
| 15 | 15 | ||
| 16 | constexpr float SCREEN_REFRESH_RATE = 60; | ||
| 17 | |||
| 16 | // Returns index corresponding to the Regs member labeled by field_name | 18 | // Returns index corresponding to the Regs member labeled by field_name |
| 17 | // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions | 19 | // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions |
| 18 | // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). | 20 | // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). |
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp new file mode 100644 index 000000000..6d9e603e4 --- /dev/null +++ b/src/core/perf_stats.cpp | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <chrono> | ||
| 6 | #include "core/hw/gpu.h" | ||
| 7 | #include "core/perf_stats.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | |||
| 11 | void PerfStats::BeginSystemFrame() { | ||
| 12 | frame_begin = Clock::now(); | ||
| 13 | } | ||
| 14 | |||
| 15 | void PerfStats::EndSystemFrame() { | ||
| 16 | auto frame_end = Clock::now(); | ||
| 17 | accumulated_frametime += frame_end - frame_begin; | ||
| 18 | system_frames += 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | void PerfStats::EndGameFrame() { | ||
| 22 | game_frames += 1; | ||
| 23 | } | ||
| 24 | |||
| 25 | PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) { | ||
| 26 | using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>; | ||
| 27 | using std::chrono::duration_cast; | ||
| 28 | |||
| 29 | auto now = Clock::now(); | ||
| 30 | // Walltime elapsed since stats were reset | ||
| 31 | auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); | ||
| 32 | |||
| 33 | auto system_us_per_second = | ||
| 34 | static_cast<double>(current_system_time_us - reset_point_system_us) / interval; | ||
| 35 | |||
| 36 | Results results{}; | ||
| 37 | results.system_fps = static_cast<double>(system_frames) / interval; | ||
| 38 | results.game_fps = static_cast<double>(game_frames) / interval; | ||
| 39 | results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / | ||
| 40 | static_cast<double>(system_frames); | ||
| 41 | results.emulation_speed = system_us_per_second / 1'000'000.0; | ||
| 42 | |||
| 43 | // Reset counters | ||
| 44 | reset_point = now; | ||
| 45 | reset_point_system_us = current_system_time_us; | ||
| 46 | accumulated_frametime = Clock::duration::zero(); | ||
| 47 | system_frames = 0; | ||
| 48 | game_frames = 0; | ||
| 49 | |||
| 50 | return results; | ||
| 51 | } | ||
| 52 | |||
| 53 | } // namespace Core | ||
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h new file mode 100644 index 000000000..566a1419a --- /dev/null +++ b/src/core/perf_stats.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <chrono> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | |||
| 12 | class PerfStats { | ||
| 13 | public: | ||
| 14 | using Clock = std::chrono::high_resolution_clock; | ||
| 15 | |||
| 16 | struct Results { | ||
| 17 | /// System FPS (LCD VBlanks) in Hz | ||
| 18 | double system_fps; | ||
| 19 | /// Game FPS (GSP frame submissions) in Hz | ||
| 20 | double game_fps; | ||
| 21 | /// Walltime per system frame, in seconds, excluding any waits | ||
| 22 | double frametime; | ||
| 23 | /// Ratio of walltime / emulated time elapsed | ||
| 24 | double emulation_speed; | ||
| 25 | }; | ||
| 26 | |||
| 27 | void BeginSystemFrame(); | ||
| 28 | void EndSystemFrame(); | ||
| 29 | void EndGameFrame(); | ||
| 30 | |||
| 31 | Results GetAndResetStats(u64 current_system_time_us); | ||
| 32 | |||
| 33 | private: | ||
| 34 | Clock::time_point reset_point = Clock::now(); | ||
| 35 | |||
| 36 | Clock::time_point frame_begin; | ||
| 37 | Clock::duration accumulated_frametime = Clock::duration::zero(); | ||
| 38 | u64 reset_point_system_us = 0; | ||
| 39 | u32 system_frames = 0; | ||
| 40 | u32 game_frames = 0; | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace Core | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 2aa90e5c1..0b90dcb3d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/profiler_reporting.h" | 13 | #include "common/profiler_reporting.h" |
| 14 | #include "common/synchronized_wrapper.h" | 14 | #include "common/synchronized_wrapper.h" |
| 15 | #include "core/core.h" | ||
| 15 | #include "core/frontend/emu_window.h" | 16 | #include "core/frontend/emu_window.h" |
| 16 | #include "core/hw/gpu.h" | 17 | #include "core/hw/gpu.h" |
| 17 | #include "core/hw/hw.h" | 18 | #include "core/hw/hw.h" |
| @@ -151,6 +152,10 @@ void RendererOpenGL::SwapBuffers() { | |||
| 151 | auto aggregator = Common::Profiling::GetTimingResultsAggregator(); | 152 | auto aggregator = Common::Profiling::GetTimingResultsAggregator(); |
| 152 | aggregator->AddFrame(profiler.GetPreviousFrameResults()); | 153 | aggregator->AddFrame(profiler.GetPreviousFrameResults()); |
| 153 | } | 154 | } |
| 155 | { | ||
| 156 | auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||
| 157 | perf_stats->EndSystemFrame(); | ||
| 158 | } | ||
| 154 | 159 | ||
| 155 | // Swap buffers | 160 | // Swap buffers |
| 156 | render_window->PollEvents(); | 161 | render_window->PollEvents(); |
| @@ -159,6 +164,10 @@ void RendererOpenGL::SwapBuffers() { | |||
| 159 | prev_state.Apply(); | 164 | prev_state.Apply(); |
| 160 | 165 | ||
| 161 | profiler.BeginFrame(); | 166 | profiler.BeginFrame(); |
| 167 | { | ||
| 168 | auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||
| 169 | perf_stats->BeginSystemFrame(); | ||
| 170 | } | ||
| 162 | 171 | ||
| 163 | RefreshRasterizerSetting(); | 172 | RefreshRasterizerSetting(); |
| 164 | 173 | ||