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