summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/citra_qt/CMakeLists.txt1
-rw-r--r--src/citra_qt/debugger/profiler.cpp111
-rw-r--r--src/citra_qt/debugger/profiler.h40
-rw-r--r--src/citra_qt/debugger/profiler.ui33
-rw-r--r--src/citra_qt/main.cpp5
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/profiler.cpp101
-rw-r--r--src/common/profiler_reporting.h83
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
9 files changed, 2 insertions, 382 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index d4460bf01..15a6ccf9a 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -69,7 +69,6 @@ set(HEADERS
69set(UIS 69set(UIS
70 debugger/callstack.ui 70 debugger/callstack.ui
71 debugger/disassembler.ui 71 debugger/disassembler.ui
72 debugger/profiler.ui
73 debugger/registers.ui 72 debugger/registers.ui
74 configure.ui 73 configure.ui
75 configure_audio.ui 74 configure_audio.ui
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index cee10403d..f060bbe08 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QAction>
6#include <QLayout>
5#include <QMouseEvent> 7#include <QMouseEvent>
6#include <QPainter> 8#include <QPainter>
7#include <QString> 9#include <QString>
@@ -9,121 +11,12 @@
9#include "citra_qt/util/util.h" 11#include "citra_qt/util/util.h"
10#include "common/common_types.h" 12#include "common/common_types.h"
11#include "common/microprofile.h" 13#include "common/microprofile.h"
12#include "common/profiler_reporting.h"
13 14
14// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the 15// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
15// non-Qt frontends don't need it (and don't implement the UI drawing hooks either). 16// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
16#if MICROPROFILE_ENABLED 17#if MICROPROFILE_ENABLED
17#define MICROPROFILEUI_IMPL 1 18#define MICROPROFILEUI_IMPL 1
18#include "common/microprofileui.h" 19#include "common/microprofileui.h"
19#endif
20
21using namespace Common::Profiling;
22
23static QVariant GetDataForColumn(int col, const AggregatedDuration& duration) {
24 static auto duration_to_float = [](Duration dur) -> float {
25 using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>;
26 return std::chrono::duration_cast<FloatMs>(dur).count();
27 };
28
29 switch (col) {
30 case 1:
31 return duration_to_float(duration.avg);
32 case 2:
33 return duration_to_float(duration.min);
34 case 3:
35 return duration_to_float(duration.max);
36 default:
37 return QVariant();
38 }
39}
40
41ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) {
42 updateProfilingInfo();
43}
44
45QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const {
46 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
47 switch (section) {
48 case 0:
49 return tr("Category");
50 case 1:
51 return tr("Avg");
52 case 2:
53 return tr("Min");
54 case 3:
55 return tr("Max");
56 }
57 }
58
59 return QVariant();
60}
61
62QModelIndex ProfilerModel::index(int row, int column, const QModelIndex& parent) const {
63 return createIndex(row, column);
64}
65
66QModelIndex ProfilerModel::parent(const QModelIndex& child) const {
67 return QModelIndex();
68}
69
70int ProfilerModel::columnCount(const QModelIndex& parent) const {
71 return 4;
72}
73
74int ProfilerModel::rowCount(const QModelIndex& parent) const {
75 if (parent.isValid()) {
76 return 0;
77 } else {
78 return 2;
79 }
80}
81
82QVariant ProfilerModel::data(const QModelIndex& index, int role) const {
83 if (role == Qt::DisplayRole) {
84 if (index.row() == 0) {
85 if (index.column() == 0) {
86 return tr("Frame");
87 } else {
88 return GetDataForColumn(index.column(), results.frame_time);
89 }
90 } else if (index.row() == 1) {
91 if (index.column() == 0) {
92 return tr("Frame (with swapping)");
93 } else {
94 return GetDataForColumn(index.column(), results.interframe_time);
95 }
96 }
97 }
98
99 return QVariant();
100}
101
102void ProfilerModel::updateProfilingInfo() {
103 results = GetTimingResultsAggregator()->GetAggregatedResults();
104 emit dataChanged(createIndex(0, 1), createIndex(rowCount() - 1, 3));
105}
106
107ProfilerWidget::ProfilerWidget(QWidget* parent) : QDockWidget(parent) {
108 ui.setupUi(this);
109
110 model = new ProfilerModel(this);
111 ui.treeView->setModel(model);
112
113 connect(this, SIGNAL(visibilityChanged(bool)), SLOT(setProfilingInfoUpdateEnabled(bool)));
114 connect(&update_timer, SIGNAL(timeout()), model, SLOT(updateProfilingInfo()));
115}
116
117void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable) {
118 if (enable) {
119 update_timer.start(100);
120 model->updateProfilingInfo();
121 } else {
122 update_timer.stop();
123 }
124}
125
126#if MICROPROFILE_ENABLED
127 20
128class MicroProfileWidget : public QWidget { 21class MicroProfileWidget : public QWidget {
129public: 22public:
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index c8912fd5a..eae1e9e3c 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -8,46 +8,6 @@
8#include <QDockWidget> 8#include <QDockWidget>
9#include <QTimer> 9#include <QTimer>
10#include "common/microprofile.h" 10#include "common/microprofile.h"
11#include "common/profiler_reporting.h"
12#include "ui_profiler.h"
13
14class ProfilerModel : public QAbstractItemModel {
15 Q_OBJECT
16
17public:
18 explicit ProfilerModel(QObject* parent);
19
20 QVariant headerData(int section, Qt::Orientation orientation,
21 int role = Qt::DisplayRole) const override;
22 QModelIndex index(int row, int column,
23 const QModelIndex& parent = QModelIndex()) const override;
24 QModelIndex parent(const QModelIndex& child) const override;
25 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
26 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
27 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
28
29public slots:
30 void updateProfilingInfo();
31
32private:
33 Common::Profiling::AggregatedFrameResult results;
34};
35
36class ProfilerWidget : public QDockWidget {
37 Q_OBJECT
38
39public:
40 explicit ProfilerWidget(QWidget* parent = nullptr);
41
42private slots:
43 void setProfilingInfoUpdateEnabled(bool enable);
44
45private:
46 Ui::Profiler ui;
47 ProfilerModel* model;
48
49 QTimer update_timer;
50};
51 11
52class MicroProfileDialog : public QWidget { 12class MicroProfileDialog : public QWidget {
53 Q_OBJECT 13 Q_OBJECT
diff --git a/src/citra_qt/debugger/profiler.ui b/src/citra_qt/debugger/profiler.ui
deleted file mode 100644
index d3c9a9a1f..000000000
--- a/src/citra_qt/debugger/profiler.ui
+++ /dev/null
@@ -1,33 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>Profiler</class>
4 <widget class="QDockWidget" name="Profiler">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>300</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Profiler</string>
15 </property>
16 <widget class="QWidget" name="dockWidgetContents">
17 <layout class="QVBoxLayout" name="verticalLayout">
18 <item>
19 <widget class="QTreeView" name="treeView">
20 <property name="alternatingRowColors">
21 <bool>true</bool>
22 </property>
23 <property name="uniformRowHeights">
24 <bool>true</bool>
25 </property>
26 </widget>
27 </item>
28 </layout>
29 </widget>
30 </widget>
31 <resources/>
32 <connections/>
33</ui>
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 41356a6ca..138763080 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -113,11 +113,6 @@ void GMainWindow::InitializeDebugWidgets() {
113 113
114 QMenu* debug_menu = ui.menu_View_Debugging; 114 QMenu* debug_menu = ui.menu_View_Debugging;
115 115
116 profilerWidget = new ProfilerWidget(this);
117 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
118 profilerWidget->hide();
119 debug_menu->addAction(profilerWidget->toggleViewAction());
120
121#if MICROPROFILE_ENABLED 116#if MICROPROFILE_ENABLED
122 microProfileDialog = new MicroProfileDialog(this); 117 microProfileDialog = new MicroProfileDialog(this);
123 microProfileDialog->hide(); 118 microProfileDialog->hide();
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 592911c2b..aca0ebe38 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -12,7 +12,6 @@ set(SRCS
12 memory_util.cpp 12 memory_util.cpp
13 microprofile.cpp 13 microprofile.cpp
14 misc.cpp 14 misc.cpp
15 profiler.cpp
16 scm_rev.cpp 15 scm_rev.cpp
17 string_util.cpp 16 string_util.cpp
18 symbols.cpp 17 symbols.cpp
@@ -45,7 +44,6 @@ set(HEADERS
45 microprofile.h 44 microprofile.h
46 microprofileui.h 45 microprofileui.h
47 platform.h 46 platform.h
48 profiler_reporting.h
49 quaternion.h 47 quaternion.h
50 scm_rev.h 48 scm_rev.h
51 scope_exit.h 49 scope_exit.h
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
deleted file mode 100644
index b40e7205d..000000000
--- a/src/common/profiler.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cstddef>
7#include <vector>
8#include "common/assert.h"
9#include "common/profiler_reporting.h"
10#include "common/synchronized_wrapper.h"
11
12namespace Common {
13namespace Profiling {
14
15ProfilingManager::ProfilingManager()
16 : last_frame_end(Clock::now()), this_frame_start(Clock::now()) {}
17
18void ProfilingManager::BeginFrame() {
19 this_frame_start = Clock::now();
20}
21
22void ProfilingManager::FinishFrame() {
23 Clock::time_point now = Clock::now();
24
25 results.interframe_time = now - last_frame_end;
26 results.frame_time = now - this_frame_start;
27
28 last_frame_end = now;
29}
30
31TimingResultsAggregator::TimingResultsAggregator(size_t window_size)
32 : max_window_size(window_size), window_size(0) {
33 interframe_times.resize(window_size, Duration::zero());
34 frame_times.resize(window_size, Duration::zero());
35}
36
37void TimingResultsAggregator::Clear() {
38 window_size = cursor = 0;
39}
40
41void TimingResultsAggregator::AddFrame(const ProfilingFrameResult& frame_result) {
42 interframe_times[cursor] = frame_result.interframe_time;
43 frame_times[cursor] = frame_result.frame_time;
44
45 ++cursor;
46 if (cursor == max_window_size)
47 cursor = 0;
48 if (window_size < max_window_size)
49 ++window_size;
50}
51
52static AggregatedDuration AggregateField(const std::vector<Duration>& v, size_t len) {
53 AggregatedDuration result;
54 result.avg = Duration::zero();
55 result.min = result.max = (len == 0 ? Duration::zero() : v[0]);
56
57 for (size_t i = 0; i < len; ++i) {
58 Duration value = v[i];
59 result.avg += value;
60 result.min = std::min(result.min, value);
61 result.max = std::max(result.max, value);
62 }
63 if (len != 0)
64 result.avg /= len;
65
66 return result;
67}
68
69static float tof(Common::Profiling::Duration dur) {
70 using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>;
71 return std::chrono::duration_cast<FloatMs>(dur).count();
72}
73
74AggregatedFrameResult TimingResultsAggregator::GetAggregatedResults() const {
75 AggregatedFrameResult result;
76
77 result.interframe_time = AggregateField(interframe_times, window_size);
78 result.frame_time = AggregateField(frame_times, window_size);
79
80 if (result.interframe_time.avg != Duration::zero()) {
81 result.fps = 1000.0f / tof(result.interframe_time.avg);
82 } else {
83 result.fps = 0.0f;
84 }
85
86 return result;
87}
88
89ProfilingManager& GetProfilingManager() {
90 // Takes advantage of "magic" static initialization for race-free initialization.
91 static ProfilingManager manager;
92 return manager;
93}
94
95SynchronizedRef<TimingResultsAggregator> GetTimingResultsAggregator() {
96 static SynchronizedWrapper<TimingResultsAggregator> aggregator(30);
97 return SynchronizedRef<TimingResultsAggregator>(aggregator);
98}
99
100} // namespace Profiling
101} // namespace Common
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h
deleted file mode 100644
index e9ce6d41c..000000000
--- a/src/common/profiler_reporting.h
+++ /dev/null
@@ -1,83 +0,0 @@
1// Copyright 2015 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 <cstddef>
9#include <vector>
10#include "common/synchronized_wrapper.h"
11
12namespace Common {
13namespace Profiling {
14
15using Clock = std::chrono::high_resolution_clock;
16using Duration = Clock::duration;
17
18struct ProfilingFrameResult {
19 /// Time since the last delivered frame
20 Duration interframe_time;
21
22 /// Time spent processing a frame, excluding VSync
23 Duration frame_time;
24};
25
26class ProfilingManager final {
27public:
28 ProfilingManager();
29
30 /// This should be called after swapping screen buffers.
31 void BeginFrame();
32 /// This should be called before swapping screen buffers.
33 void FinishFrame();
34
35 /// Get the timing results from the previous frame. This is updated when you call FinishFrame().
36 const ProfilingFrameResult& GetPreviousFrameResults() const {
37 return results;
38 }
39
40private:
41 Clock::time_point last_frame_end;
42 Clock::time_point this_frame_start;
43
44 ProfilingFrameResult results;
45};
46
47struct AggregatedDuration {
48 Duration avg, min, max;
49};
50
51struct AggregatedFrameResult {
52 /// Time since the last delivered frame
53 AggregatedDuration interframe_time;
54
55 /// Time spent processing a frame, excluding VSync
56 AggregatedDuration frame_time;
57
58 float fps;
59};
60
61class TimingResultsAggregator final {
62public:
63 TimingResultsAggregator(size_t window_size);
64
65 void Clear();
66
67 void AddFrame(const ProfilingFrameResult& frame_result);
68
69 AggregatedFrameResult GetAggregatedResults() const;
70
71 size_t max_window_size;
72 size_t window_size;
73 size_t cursor;
74
75 std::vector<Duration> interframe_times;
76 std::vector<Duration> frame_times;
77};
78
79ProfilingManager& GetProfilingManager();
80SynchronizedRef<TimingResultsAggregator> GetTimingResultsAggregator();
81
82} // namespace Profiling
83} // namespace Common
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 0b90dcb3d..6bc142148 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -10,7 +10,6 @@
10#include "common/assert.h" 10#include "common/assert.h"
11#include "common/bit_field.h" 11#include "common/bit_field.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/profiler_reporting.h"
14#include "common/synchronized_wrapper.h" 13#include "common/synchronized_wrapper.h"
15#include "core/core.h" 14#include "core/core.h"
16#include "core/frontend/emu_window.h" 15#include "core/frontend/emu_window.h"
@@ -146,12 +145,6 @@ void RendererOpenGL::SwapBuffers() {
146 145
147 DrawScreens(); 146 DrawScreens();
148 147
149 auto& profiler = Common::Profiling::GetProfilingManager();
150 profiler.FinishFrame();
151 {
152 auto aggregator = Common::Profiling::GetTimingResultsAggregator();
153 aggregator->AddFrame(profiler.GetPreviousFrameResults());
154 }
155 { 148 {
156 auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); 149 auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
157 perf_stats->EndSystemFrame(); 150 perf_stats->EndSystemFrame();
@@ -163,7 +156,6 @@ void RendererOpenGL::SwapBuffers() {
163 156
164 prev_state.Apply(); 157 prev_state.Apply();
165 158
166 profiler.BeginFrame();
167 { 159 {
168 auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); 160 auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
169 perf_stats->BeginSystemFrame(); 161 perf_stats->BeginSystemFrame();