diff options
author | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2017-02-26 17:51:15 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-26 17:51:15 -0800 |
commit | b250ce21b9a62cb573540fdb14f30c28fa66e6ad (patch) | |
tree | ef55a0cd4a531a097de2152f563d712551972c4b /src/core/perf_stats.cpp | |
parent | f2ae2a7ff2a053d019985f70a2cc999c8d8bb844 (diff) | |
parent | 174464a87f2e1709597bc1e0cb08c877487a771b (diff) |
Merge pull request #2587 from yuriks/status-bar
Replace built-in Profiler with indicators in status bar
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 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <chrono> +#include <mutex> +#include <thread> +#include "common/math_util.h" +#include "core/hw/gpu.h" +#include "core/perf_stats.h" +#include "core/settings.h" + +using namespace std::chrono_literals; +using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>; +using std::chrono::duration_cast; +using std::chrono::microseconds; + +namespace Core { + +void PerfStats::BeginSystemFrame() { + std::lock_guard<std::mutex> lock(object_mutex); + + frame_begin = Clock::now(); +} + +void PerfStats::EndSystemFrame() { + std::lock_guard<std::mutex> lock(object_mutex); + + auto frame_end = Clock::now(); + accumulated_frametime += frame_end - frame_begin; + system_frames += 1; + + previous_frame_length = frame_end - previous_frame_end; + previous_frame_end = frame_end; +} + +void PerfStats::EndGameFrame() { + std::lock_guard<std::mutex> lock(object_mutex); + + game_frames += 1; +} + +PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) { + std::lock_guard<std::mutex> lock(object_mutex); + + auto now = Clock::now(); + // Walltime elapsed since stats were reset + auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); + + auto system_us_per_second = + static_cast<double>(current_system_time_us - reset_point_system_us) / interval; + + Results results{}; + results.system_fps = static_cast<double>(system_frames) / interval; + results.game_fps = static_cast<double>(game_frames) / interval; + results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / + static_cast<double>(system_frames); + results.emulation_speed = system_us_per_second / 1'000'000.0; + + // Reset counters + reset_point = now; + reset_point_system_us = current_system_time_us; + accumulated_frametime = Clock::duration::zero(); + system_frames = 0; + game_frames = 0; + + return results; +} + +double PerfStats::GetLastFrameTimeScale() { + std::lock_guard<std::mutex> lock(object_mutex); + + constexpr double FRAME_LENGTH = 1.0 / GPU::SCREEN_REFRESH_RATE; + return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; +} + +void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) { + // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher + // values increase the time needed to recover and limit framerate again after spikes. + constexpr microseconds MAX_LAG_TIME_US = 25ms; + + if (!Settings::values.toggle_framelimit) { + return; + } + + auto now = Clock::now(); + + frame_limiting_delta_err += microseconds(current_system_time_us - previous_system_time_us); + frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime); + frame_limiting_delta_err = + MathUtil::Clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US); + + if (frame_limiting_delta_err > microseconds::zero()) { + std::this_thread::sleep_for(frame_limiting_delta_err); + + auto now_after_sleep = Clock::now(); + frame_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now); + now = now_after_sleep; + } + + previous_system_time_us = current_system_time_us; + previous_walltime = now; +} + +} // namespace Core |