Add profiling infrastructure and widget

This commit is contained in:
Yuri Kunde Schlesner 2015-02-05 14:53:25 -02:00
parent c1d29ac202
commit cd1fbfcf1b
16 changed files with 757 additions and 0 deletions

View file

@ -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

View 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();
}
}

View 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;
};

View 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>

View file

@ -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());

View file

@ -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;