diff options
Diffstat (limited to 'src/core/perf_stats.cpp')
| -rw-r--r-- | src/core/perf_stats.cpp | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp new file mode 100644 index 000000000..2cdfb9ded --- /dev/null +++ b/src/core/perf_stats.cpp | |||
| @@ -0,0 +1,105 @@ | |||
| 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 <mutex> | ||
| 7 | #include <thread> | ||
| 8 | #include "common/math_util.h" | ||
| 9 | #include "core/hw/gpu.h" | ||
| 10 | #include "core/perf_stats.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | using namespace std::chrono_literals; | ||
| 14 | using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>; | ||
| 15 | using std::chrono::duration_cast; | ||
| 16 | using std::chrono::microseconds; | ||
| 17 | |||
| 18 | namespace Core { | ||
| 19 | |||
| 20 | void PerfStats::BeginSystemFrame() { | ||
| 21 | std::lock_guard<std::mutex> lock(object_mutex); | ||
| 22 | |||
| 23 | frame_begin = Clock::now(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void PerfStats::EndSystemFrame() { | ||
| 27 | std::lock_guard<std::mutex> lock(object_mutex); | ||
| 28 | |||
| 29 | auto frame_end = Clock::now(); | ||
| 30 | accumulated_frametime += frame_end - frame_begin; | ||
| 31 | system_frames += 1; | ||
| 32 | |||
| 33 | previous_frame_length = frame_end - previous_frame_end; | ||
| 34 | previous_frame_end = frame_end; | ||
| 35 | } | ||
| 36 | |||
| 37 | void PerfStats::EndGameFrame() { | ||
| 38 | std::lock_guard<std::mutex> lock(object_mutex); | ||
| 39 | |||
| 40 | game_frames += 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) { | ||
| 44 | std::lock_guard<std::mutex> lock(object_mutex); | ||
| 45 | |||
| 46 | auto now = Clock::now(); | ||
| 47 | // Walltime elapsed since stats were reset | ||
| 48 | auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); | ||
| 49 | |||
| 50 | auto system_us_per_second = | ||
| 51 | static_cast<double>(current_system_time_us - reset_point_system_us) / interval; | ||
| 52 | |||
| 53 | Results results{}; | ||
| 54 | results.system_fps = static_cast<double>(system_frames) / interval; | ||
| 55 | results.game_fps = static_cast<double>(game_frames) / interval; | ||
| 56 | results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / | ||
| 57 | static_cast<double>(system_frames); | ||
| 58 | results.emulation_speed = system_us_per_second / 1'000'000.0; | ||
| 59 | |||
| 60 | // Reset counters | ||
| 61 | reset_point = now; | ||
| 62 | reset_point_system_us = current_system_time_us; | ||
| 63 | accumulated_frametime = Clock::duration::zero(); | ||
| 64 | system_frames = 0; | ||
| 65 | game_frames = 0; | ||
| 66 | |||
| 67 | return results; | ||
| 68 | } | ||
| 69 | |||
| 70 | double PerfStats::GetLastFrameTimeScale() { | ||
| 71 | std::lock_guard<std::mutex> lock(object_mutex); | ||
| 72 | |||
| 73 | constexpr double FRAME_LENGTH = 1.0 / GPU::SCREEN_REFRESH_RATE; | ||
| 74 | return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; | ||
| 75 | } | ||
| 76 | |||
| 77 | void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) { | ||
| 78 | // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher | ||
| 79 | // values increase the time needed to recover and limit framerate again after spikes. | ||
| 80 | constexpr microseconds MAX_LAG_TIME_US = 25ms; | ||
| 81 | |||
| 82 | if (!Settings::values.toggle_framelimit) { | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 86 | auto now = Clock::now(); | ||
| 87 | |||
| 88 | frame_limiting_delta_err += microseconds(current_system_time_us - previous_system_time_us); | ||
| 89 | frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime); | ||
| 90 | frame_limiting_delta_err = | ||
| 91 | MathUtil::Clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US); | ||
| 92 | |||
| 93 | if (frame_limiting_delta_err > microseconds::zero()) { | ||
| 94 | std::this_thread::sleep_for(frame_limiting_delta_err); | ||
| 95 | |||
| 96 | auto now_after_sleep = Clock::now(); | ||
| 97 | frame_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now); | ||
| 98 | now = now_after_sleep; | ||
| 99 | } | ||
| 100 | |||
| 101 | previous_system_time_us = current_system_time_us; | ||
| 102 | previous_walltime = now; | ||
| 103 | } | ||
| 104 | |||
| 105 | } // namespace Core | ||