1
0
Fork 0

Add performance statistics to status bar

This commit is contained in:
Yuri Kunde Schlesner 2017-02-19 14:34:47 -08:00
parent 21f4f49c7a
commit c75ae6c585
11 changed files with 159 additions and 3 deletions

View File

@ -253,6 +253,8 @@ void GMainWindow::ConnectWidgetEvents() {
connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window,
SLOT(OnEmulationStarting(EmuThread*))); SLOT(OnEmulationStarting(EmuThread*)));
connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
} }
void GMainWindow::ConnectMenuEvents() { void GMainWindow::ConnectMenuEvents() {
@ -401,6 +403,8 @@ void GMainWindow::BootGame(const QString& filename) {
if (ui.action_Single_Window_Mode->isChecked()) { if (ui.action_Single_Window_Mode->isChecked()) {
game_list->hide(); game_list->hide();
} }
status_bar_update_timer.start(1000);
render_window->show(); render_window->show();
render_window->setFocus(); render_window->setFocus();
@ -435,6 +439,12 @@ void GMainWindow::ShutdownGame() {
render_window->hide(); render_window->hide();
game_list->show(); game_list->show();
// Disable status bar updates
status_bar_update_timer.stop();
emu_speed_label->setVisible(false);
game_fps_label->setVisible(false);
emu_frametime_label->setVisible(false);
emulation_running = false; emulation_running = false;
} }
@ -614,6 +624,23 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() {
graphicsSurfaceViewerWidget->show(); graphicsSurfaceViewerWidget->show();
} }
void GMainWindow::UpdateStatusBar() {
if (emu_thread == nullptr) {
status_bar_update_timer.stop();
return;
}
auto results = Core::System::GetInstance().GetAndResetPerfStats();
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 2));
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 1));
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
emu_speed_label->setVisible(true);
game_fps_label->setVisible(true);
emu_frametime_label->setVisible(true);
}
bool GMainWindow::ConfirmClose() { bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
return true; return true;

View File

@ -127,6 +127,8 @@ private slots:
void OnCreateGraphicsSurfaceViewer(); void OnCreateGraphicsSurfaceViewer();
private: private:
void UpdateStatusBar();
Ui::MainWindow ui; Ui::MainWindow ui;
GRenderWindow* render_window; GRenderWindow* render_window;
@ -136,6 +138,7 @@ private:
QLabel* emu_speed_label = nullptr; QLabel* emu_speed_label = nullptr;
QLabel* game_fps_label = nullptr; QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr; QLabel* emu_frametime_label = nullptr;
QTimer status_bar_update_timer;
std::unique_ptr<Config> config; std::unique_ptr<Config> config;

View File

@ -170,6 +170,7 @@ set(SRCS
loader/smdh.cpp loader/smdh.cpp
tracer/recorder.cpp tracer/recorder.cpp
memory.cpp memory.cpp
perf_stats.cpp
settings.cpp settings.cpp
) )
@ -357,6 +358,7 @@ set(HEADERS
memory.h memory.h
memory_setup.h memory_setup.h
mmio.h mmio.h
perf_stats.h
settings.h settings.h
) )

View File

@ -109,6 +109,11 @@ void System::PrepareReschedule() {
reschedule_pending = true; reschedule_pending = true;
} }
PerfStats::Results System::GetAndResetPerfStats() {
auto perf_stats = this->perf_stats.Lock();
return perf_stats->GetAndResetStats(CoreTiming::GetGlobalTimeUs());
}
void System::Reschedule() { void System::Reschedule() {
if (!reschedule_pending) { if (!reschedule_pending) {
return; return;
@ -140,6 +145,10 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
LOG_DEBUG(Core, "Initialized OK"); LOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
perf_stats.Lock()->BeginSystemFrame();
return ResultStatus::Success; return ResultStatus::Success;
} }

View File

@ -6,9 +6,10 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/synchronized_wrapper.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/perf_stats.h"
class EmuWindow; class EmuWindow;
class ARM_Interface; class ARM_Interface;
@ -83,6 +84,8 @@ public:
/// Prepare the core emulation for a reschedule /// Prepare the core emulation for a reschedule
void PrepareReschedule(); void PrepareReschedule();
PerfStats::Results GetAndResetPerfStats();
/** /**
* Gets a reference to the emulated CPU. * Gets a reference to the emulated CPU.
* @returns A reference to the emulated CPU. * @returns A reference to the emulated CPU.
@ -91,6 +94,8 @@ public:
return *cpu_core; return *cpu_core;
} }
Common::SynchronizedWrapper<PerfStats> perf_stats;
private: private:
/** /**
* Initialize the emulated system. * Initialize the emulated system.

View File

@ -4,6 +4,7 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "core/core.h"
#include "core/hle/kernel/event.h" #include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
#include "core/hle/result.h" #include "core/hle/result.h"
@ -280,6 +281,8 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
if (screen_id == 0) { if (screen_id == 0) {
MicroProfileFlip(); MicroProfileFlip();
auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
perf_stats->EndGameFrame();
} }
return RESULT_SUCCESS; return RESULT_SUCCESS;

View File

@ -32,7 +32,7 @@ namespace GPU {
Regs g_regs; Regs g_regs;
/// 268MHz CPU clocks / 60Hz frames per second /// 268MHz CPU clocks / 60Hz frames per second
const u64 frame_ticks = BASE_CLOCK_RATE_ARM11 / 60; const u64 frame_ticks = BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE;
/// Event id for CoreTiming /// Event id for CoreTiming
static int vblank_event; static int vblank_event;
/// Total number of frames drawn /// Total number of frames drawn
@ -41,7 +41,7 @@ static u64 frame_count;
static u32 time_point; static u32 time_point;
/// Total delay caused by slow frames /// Total delay caused by slow frames
static float time_delay; static float time_delay;
constexpr float FIXED_FRAME_TIME = 1000.0f / 60; constexpr float FIXED_FRAME_TIME = 1000.0f / SCREEN_REFRESH_RATE;
// Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher
// values increases time needed to limit frame rate after spikes // values increases time needed to limit frame rate after spikes
constexpr float MAX_LAG_TIME = 18; constexpr float MAX_LAG_TIME = 18;

View File

@ -13,6 +13,8 @@
namespace GPU { namespace GPU {
constexpr float SCREEN_REFRESH_RATE = 60;
// Returns index corresponding to the Regs member labeled by field_name // Returns index corresponding to the Regs member labeled by field_name
// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
// when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).

53
src/core/perf_stats.cpp Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <chrono>
#include "core/hw/gpu.h"
#include "core/perf_stats.h"
namespace Core {
void PerfStats::BeginSystemFrame() {
frame_begin = Clock::now();
}
void PerfStats::EndSystemFrame() {
auto frame_end = Clock::now();
accumulated_frametime += frame_end - frame_begin;
system_frames += 1;
}
void PerfStats::EndGameFrame() {
game_frames += 1;
}
PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) {
using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>;
using std::chrono::duration_cast;
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;
}
} // namespace Core

43
src/core/perf_stats.h Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include "common/common_types.h"
namespace Core {
class PerfStats {
public:
using Clock = std::chrono::high_resolution_clock;
struct Results {
/// System FPS (LCD VBlanks) in Hz
double system_fps;
/// Game FPS (GSP frame submissions) in Hz
double game_fps;
/// Walltime per system frame, in seconds, excluding any waits
double frametime;
/// Ratio of walltime / emulated time elapsed
double emulation_speed;
};
void BeginSystemFrame();
void EndSystemFrame();
void EndGameFrame();
Results GetAndResetStats(u64 current_system_time_us);
private:
Clock::time_point reset_point = Clock::now();
Clock::time_point frame_begin;
Clock::duration accumulated_frametime = Clock::duration::zero();
u64 reset_point_system_us = 0;
u32 system_frames = 0;
u32 game_frames = 0;
};
} // namespace Core

View File

@ -12,6 +12,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler_reporting.h" #include "common/profiler_reporting.h"
#include "common/synchronized_wrapper.h" #include "common/synchronized_wrapper.h"
#include "core/core.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "core/hw/hw.h" #include "core/hw/hw.h"
@ -151,6 +152,10 @@ void RendererOpenGL::SwapBuffers() {
auto aggregator = Common::Profiling::GetTimingResultsAggregator(); auto aggregator = Common::Profiling::GetTimingResultsAggregator();
aggregator->AddFrame(profiler.GetPreviousFrameResults()); aggregator->AddFrame(profiler.GetPreviousFrameResults());
} }
{
auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
perf_stats->EndSystemFrame();
}
// Swap buffers // Swap buffers
render_window->PollEvents(); render_window->PollEvents();
@ -159,6 +164,10 @@ void RendererOpenGL::SwapBuffers() {
prev_state.Apply(); prev_state.Apply();
profiler.BeginFrame(); profiler.BeginFrame();
{
auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
perf_stats->BeginSystemFrame();
}
RefreshRasterizerSetting(); RefreshRasterizerSetting();