mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Add profiling infrastructure and widget
This commit is contained in:
		
							parent
							
								
									c1d29ac202
								
							
						
					
					
						commit
						cd1fbfcf1b
					
				
					 16 changed files with 757 additions and 0 deletions
				
			
		|  | @ -13,6 +13,7 @@ set(SRCS | |||
|             debugger/graphics_cmdlists.cpp | ||||
|             debugger/graphics_framebuffer.cpp | ||||
|             debugger/graphics_vertex_shader.cpp | ||||
|             debugger/profiler.cpp | ||||
|             debugger/ramview.cpp | ||||
|             debugger/registers.cpp | ||||
|             util/spinbox.cpp | ||||
|  | @ -35,6 +36,7 @@ set(HEADERS | |||
|             debugger/graphics_cmdlists.h | ||||
|             debugger/graphics_framebuffer.h | ||||
|             debugger/graphics_vertex_shader.h | ||||
|             debugger/profiler.h | ||||
|             debugger/ramview.h | ||||
|             debugger/registers.h | ||||
|             util/spinbox.h | ||||
|  | @ -48,6 +50,7 @@ set(UIS | |||
|             config/controller_config.ui | ||||
|             debugger/callstack.ui | ||||
|             debugger/disassembler.ui | ||||
|             debugger/profiler.ui | ||||
|             debugger/registers.ui | ||||
|             hotkeys.ui | ||||
|             main.ui | ||||
|  |  | |||
							
								
								
									
										138
									
								
								src/citra_qt/debugger/profiler.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/citra_qt/debugger/profiler.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | |||
| // Copyright 2015 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "profiler.h" | ||||
| 
 | ||||
| #include "common/profiler_reporting.h" | ||||
| 
 | ||||
| using namespace Common::Profiling; | ||||
| 
 | ||||
| static QVariant GetDataForColumn(int col, const AggregatedDuration& duration) | ||||
| { | ||||
|     static auto duration_to_float = [](Duration dur) -> float { | ||||
|         using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>; | ||||
|         return std::chrono::duration_cast<FloatMs>(dur).count(); | ||||
|     }; | ||||
| 
 | ||||
|     switch (col) { | ||||
|     case 1: return duration_to_float(duration.avg); | ||||
|     case 2: return duration_to_float(duration.min); | ||||
|     case 3: return duration_to_float(duration.max); | ||||
|     default: return QVariant(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static const TimingCategoryInfo* GetCategoryInfo(int id) | ||||
| { | ||||
|     const auto& categories = GetProfilingManager().GetTimingCategoriesInfo(); | ||||
|     if (id >= categories.size()) { | ||||
|         return nullptr; | ||||
|     } else { | ||||
|         return &categories[id]; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) | ||||
| { | ||||
|     updateProfilingInfo(); | ||||
|     const auto& categories = GetProfilingManager().GetTimingCategoriesInfo(); | ||||
|     results.time_per_category.resize(categories.size()); | ||||
| } | ||||
| 
 | ||||
| QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const | ||||
| { | ||||
|     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { | ||||
|         switch (section) { | ||||
|         case 0: return tr("Category"); | ||||
|         case 1: return tr("Avg"); | ||||
|         case 2: return tr("Min"); | ||||
|         case 3: return tr("Max"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return QVariant(); | ||||
| } | ||||
| 
 | ||||
| QModelIndex ProfilerModel::index(int row, int column, const QModelIndex& parent) const | ||||
| { | ||||
|     return createIndex(row, column); | ||||
| } | ||||
| 
 | ||||
| QModelIndex ProfilerModel::parent(const QModelIndex& child) const | ||||
| { | ||||
|     return QModelIndex(); | ||||
| } | ||||
| 
 | ||||
| int ProfilerModel::columnCount(const QModelIndex& parent) const | ||||
| { | ||||
|     return 4; | ||||
| } | ||||
| 
 | ||||
| int ProfilerModel::rowCount(const QModelIndex& parent) const | ||||
| { | ||||
|     if (parent.isValid()) { | ||||
|         return 0; | ||||
|     } else { | ||||
|         return results.time_per_category.size() + 2; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| QVariant ProfilerModel::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|     if (role == Qt::DisplayRole) { | ||||
|         if (index.row() == 0) { | ||||
|             if (index.column() == 0) { | ||||
|                 return tr("Frame"); | ||||
|             } else { | ||||
|                 return GetDataForColumn(index.column(), results.frame_time); | ||||
|             } | ||||
|         } else if (index.row() == 1) { | ||||
|             if (index.column() == 0) { | ||||
|                 return tr("Frame (with swapping)"); | ||||
|             } else { | ||||
|                 return GetDataForColumn(index.column(), results.interframe_time); | ||||
|             } | ||||
|         } else { | ||||
|             if (index.column() == 0) { | ||||
|                 const TimingCategoryInfo* info = GetCategoryInfo(index.row() - 2); | ||||
|                 return info != nullptr ? QString(info->name) : QVariant(); | ||||
|             } else { | ||||
|                 if (index.row() - 2 < results.time_per_category.size()) { | ||||
|                     return GetDataForColumn(index.column(), results.time_per_category[index.row() - 2]); | ||||
|                 } else { | ||||
|                     return QVariant(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return QVariant(); | ||||
| } | ||||
| 
 | ||||
| void ProfilerModel::updateProfilingInfo() | ||||
| { | ||||
|     results = GetTimingResultsAggregator()->GetAggregatedResults(); | ||||
|     emit dataChanged(createIndex(0, 1), createIndex(rowCount() - 1, 3)); | ||||
| } | ||||
| 
 | ||||
| ProfilerWidget::ProfilerWidget(QWidget* parent) : QDockWidget(parent) | ||||
| { | ||||
|     ui.setupUi(this); | ||||
| 
 | ||||
|     model = new ProfilerModel(this); | ||||
|     ui.treeView->setModel(model); | ||||
| 
 | ||||
|     connect(this, SIGNAL(visibilityChanged(bool)), SLOT(setProfilingInfoUpdateEnabled(bool))); | ||||
|     connect(&update_timer, SIGNAL(timeout()), model, SLOT(updateProfilingInfo())); | ||||
| } | ||||
| 
 | ||||
| void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable) | ||||
| { | ||||
|     if (enable) { | ||||
|         update_timer.start(100); | ||||
|         model->updateProfilingInfo(); | ||||
|     } else { | ||||
|         update_timer.stop(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										50
									
								
								src/citra_qt/debugger/profiler.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/citra_qt/debugger/profiler.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| // Copyright 2015 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <QAbstractItemModel> | ||||
| #include <QDockWidget> | ||||
| #include <QTimer> | ||||
| #include "ui_profiler.h" | ||||
| 
 | ||||
| #include "common/profiler_reporting.h" | ||||
| 
 | ||||
| class ProfilerModel : public QAbstractItemModel | ||||
| { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     ProfilerModel(QObject* parent); | ||||
| 
 | ||||
|     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; | ||||
|     QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; | ||||
|     QModelIndex parent(const QModelIndex& child) const override; | ||||
|     int columnCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|     int rowCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|     QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | ||||
| 
 | ||||
| public slots: | ||||
|     void updateProfilingInfo(); | ||||
| 
 | ||||
| private: | ||||
|     Common::Profiling::AggregatedFrameResult results; | ||||
| }; | ||||
| 
 | ||||
| class ProfilerWidget : public QDockWidget | ||||
| { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     ProfilerWidget(QWidget* parent = 0); | ||||
| 
 | ||||
| private slots: | ||||
|     void setProfilingInfoUpdateEnabled(bool enable); | ||||
| 
 | ||||
| private: | ||||
|     Ui::Profiler ui; | ||||
|     ProfilerModel* model; | ||||
| 
 | ||||
|     QTimer update_timer; | ||||
| }; | ||||
							
								
								
									
										33
									
								
								src/citra_qt/debugger/profiler.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/citra_qt/debugger/profiler.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>Profiler</class> | ||||
|  <widget class="QDockWidget" name="Profiler"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>400</width> | ||||
|     <height>300</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Profiler</string> | ||||
|   </property> | ||||
|   <widget class="QWidget" name="dockWidgetContents"> | ||||
|    <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|     <item> | ||||
|      <widget class="QTreeView" name="treeView"> | ||||
|       <property name="alternatingRowColors"> | ||||
|        <bool>true</bool> | ||||
|       </property> | ||||
|       <property name="uniformRowHeights"> | ||||
|        <bool>true</bool> | ||||
|       </property> | ||||
|      </widget> | ||||
|     </item> | ||||
|    </layout> | ||||
|   </widget> | ||||
|  </widget> | ||||
|  <resources/> | ||||
|  <connections/> | ||||
| </ui> | ||||
|  | @ -35,6 +35,7 @@ | |||
| #include "debugger/graphics_cmdlists.h" | ||||
| #include "debugger/graphics_framebuffer.h" | ||||
| #include "debugger/graphics_vertex_shader.h" | ||||
| #include "debugger/profiler.h" | ||||
| 
 | ||||
| #include "core/settings.h" | ||||
| #include "core/system.h" | ||||
|  | @ -57,6 +58,10 @@ GMainWindow::GMainWindow() | |||
|     render_window = new GRenderWindow; | ||||
|     render_window->hide(); | ||||
| 
 | ||||
|     profilerWidget = new ProfilerWidget(this); | ||||
|     addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); | ||||
|     profilerWidget->hide(); | ||||
| 
 | ||||
|     disasmWidget = new DisassemblerWidget(this, render_window->GetEmuThread()); | ||||
|     addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); | ||||
|     disasmWidget->hide(); | ||||
|  | @ -90,6 +95,7 @@ GMainWindow::GMainWindow() | |||
|     graphicsVertexShaderWidget->hide(); | ||||
| 
 | ||||
|     QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); | ||||
|     debug_menu->addAction(profilerWidget->toggleViewAction()); | ||||
|     debug_menu->addAction(disasmWidget->toggleViewAction()); | ||||
|     debug_menu->addAction(registersWidget->toggleViewAction()); | ||||
|     debug_menu->addAction(callstackWidget->toggleViewAction()); | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| 
 | ||||
| class GImageInfo; | ||||
| class GRenderWindow; | ||||
| class ProfilerWidget; | ||||
| class DisassemblerWidget; | ||||
| class RegistersWidget; | ||||
| class CallstackWidget; | ||||
|  | @ -54,6 +55,7 @@ private: | |||
| 
 | ||||
|     GRenderWindow* render_window; | ||||
| 
 | ||||
|     ProfilerWidget* profilerWidget; | ||||
|     DisassemblerWidget* disasmWidget; | ||||
|     RegistersWidget* registersWidget; | ||||
|     CallstackWidget* callstackWidget; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue