Add a performance counter selection dialog.

This commit is contained in:
Matthäus G. Chajdas
2017-07-13 13:32:51 +02:00
committed by baldurk
parent 40a0272a3e
commit 29376f34cc
13 changed files with 436 additions and 6 deletions
@@ -0,0 +1,175 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016-2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "PerformanceCounterSelection.h"
#include "Code/CaptureContext.h"
#include "Code/Interface/QRDInterface.h"
#include "ui_PerformanceCounterSelection.h"
#include <unordered_map>
namespace
{
enum class CounterFamily
{
Unknown,
Generic,
AMD,
Intel,
NVIDIA,
};
CounterFamily GetCounterFamily(GPUCounter counter)
{
if(IsAMDCounter(counter))
{
return CounterFamily::AMD;
}
else if(IsIntelCounter(counter))
{
return CounterFamily::Intel;
}
else if(IsNvidiaCounter(counter))
{
return CounterFamily::NVIDIA;
}
return CounterFamily::Generic;
}
const char *ToString(CounterFamily family)
{
switch(family)
{
case CounterFamily::AMD: return "AMD";
case CounterFamily::Generic: return "Generic";
case CounterFamily::Intel: return "Intel";
case CounterFamily::NVIDIA: return "NVIDIA";
case CounterFamily::Unknown: return "Unknown";
}
return nullptr;
}
}
PerformanceCounterSelection::PerformanceCounterSelection(ICaptureContext &ctx, QWidget *parent)
: QDialog(parent), ui(new Ui::PerformanceCounterSelection), m_Ctx(ctx)
{
ui->setupUi(this);
connect(ui->counterTree, &QTreeWidget::itemEntered, [&](QTreeWidgetItem *item, int) -> void {
const auto d = item->data(0, Qt::UserRole + 1);
if(d.isValid())
{
ui->counterDescription->setText(
QString(QLatin1String("<b>%1</b><hr>%2")).arg(item->text(0)).arg(d.toString()));
}
});
connect(ui->counterTree, &QTreeWidget::itemChanged, [&](QTreeWidgetItem *item, int) -> void {
const auto d = item->data(0, Qt::UserRole + 2);
if(d.isValid())
{
if(item->checkState(0) == Qt::Checked)
{
// Add
auto listItem = new QListWidgetItem(ui->enabledCounters);
listItem->setText(item->text(0));
m_SelectedCounters.insert(d.toInt(), listItem);
}
else
{
// Remove
auto listItem = m_SelectedCounters.take(d.toInt());
delete listItem;
}
}
});
ui->counterTree->setMouseTracking(true);
auto showCounters = [&](const QVector<CounterDescription> &counters) -> void {
ui->counterTree->clear();
ui->enabledCounters->clear();
QTreeWidgetItem *currentRoot = NULL;
CounterFamily currentFamily = CounterFamily::Unknown;
std::unordered_map<std::string, QTreeWidgetItem *> categories;
for(const auto desc : counters)
{
const CounterFamily family = GetCounterFamily(desc.counterID);
if(family != currentFamily)
{
currentRoot = new QTreeWidgetItem(ui->counterTree);
currentRoot->setText(0, QLatin1String{ToString(family)});
categories.clear();
currentFamily = family;
}
QTreeWidgetItem *categoryItem = nullptr;
const auto category = std::string{desc.category};
auto categoryIterator = categories.find(category);
if(categoryIterator == categories.end())
{
auto item = new QTreeWidgetItem{currentRoot};
item->setText(0, desc.category);
categories[category] = item;
categoryItem = item;
}
else
{
categoryItem = categoryIterator->second;
}
auto counterItem = new QTreeWidgetItem{categoryItem};
counterItem->setText(0, desc.name);
counterItem->setData(0, Qt::UserRole + 1, desc.description);
counterItem->setData(0, Qt::UserRole + 2, (int32_t)desc.counterID);
counterItem->setCheckState(0, Qt::Unchecked);
}
};
ctx.Replay().AsyncInvoke([=](IReplayController *controller) -> void {
QVector<CounterDescription> desc;
for(const auto counter : controller->EnumerateCounters())
{
desc.append(controller->DescribeCounter(counter));
}
GUIInvoke::call([=]() -> void { showCounters(desc); });
});
}
PerformanceCounterSelection::~PerformanceCounterSelection()
{
delete ui;
}
@@ -0,0 +1,49 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include <QDialog>
#include <QMap>
namespace Ui
{
class PerformanceCounterSelection;
}
struct ICaptureContext;
class QListWidgetItem;
class PerformanceCounterSelection : public QDialog
{
Q_OBJECT
public:
explicit PerformanceCounterSelection(ICaptureContext &ctx, QWidget *parent = 0);
~PerformanceCounterSelection();
private:
Ui::PerformanceCounterSelection *ui;
ICaptureContext &m_Ctx;
QMap<int, QListWidgetItem *> m_SelectedCounters;
};
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PerformanceCounterSelection</class>
<widget class="QDialog" name="PerformanceCounterSelection">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>640</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>Performance counter selection</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="countersLabel">
<property name="text">
<string>Counters</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="counterTree">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>1</string>
</property>
</column>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="counterDescriptionLabel">
<property name="text">
<string>Counter description</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="counterDescription">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Cache miss&lt;/span&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Lorem ipsum something something about cache misses and why you don't want those to happen all the time. Not sure what to write here, given some people seem to like a high number here.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="enabledCountersLabel">
<property name="text">
<string>Enabled counters</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="enabledCounters">
<property name="sortingEnabled">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Counter 1</string>
</property>
</item>
<item>
<property name="text">
<string>Cache miss</string>
</property>
</item>
<item>
<property name="text">
<string>Counter 2</string>
</property>
</item>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="save">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="load">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="sampleCounters">
<property name="text">
<string>Sample counters</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+7
View File
@@ -41,6 +41,7 @@
#include "Windows/Dialogs/AboutDialog.h"
#include "Windows/Dialogs/CaptureDialog.h"
#include "Windows/Dialogs/LiveCapture.h"
#include "Windows/Dialogs/PerformanceCounterSelection.h"
#include "Windows/Dialogs/RemoteManager.h"
#include "Windows/Dialogs/SettingsDialog.h"
#include "Windows/Dialogs/SuggestRemoteDialog.h"
@@ -1644,6 +1645,12 @@ void MainWindow::on_actionShow_Tips_triggered()
RDDialog::show(&tipsDialog);
}
void MainWindow::on_action_Counter_Viewer_triggered()
{
PerformanceCounterSelection pcs(m_Ctx, this);
RDDialog::show(&pcs);
}
void MainWindow::saveLayout_triggered()
{
LoadSaveLayout(qobject_cast<QAction *>(QObject::sender()), true);
+2
View File
@@ -94,6 +94,7 @@ public:
void showStatisticsViewer() { on_action_Statistics_Viewer_triggered(); }
void showTimelineBar() { on_action_Timeline_triggered(); }
void showPythonShell() { on_action_Python_Shell_triggered(); }
void showPerformanceCounterViewer() { on_action_Counter_Viewer_triggered(); }
private slots:
// automatic slots
void on_action_Exit_triggered();
@@ -122,6 +123,7 @@ private slots:
void on_action_Source_on_github_triggered();
void on_action_Build_Release_downloads_triggered();
void on_actionShow_Tips_triggered();
void on_action_Counter_Viewer_triggered();
// manual slots
void saveLayout_triggered();
+6
View File
@@ -130,6 +130,7 @@
<addaction name="action_Errors_and_Warnings"/>
<addaction name="action_Timeline"/>
<addaction name="action_Statistics_Viewer"/>
<addaction name="action_Counter_Viewer"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
@@ -405,6 +406,11 @@
<string>Start Replay &amp;Loop</string>
</property>
</action>
<action name="action_Counter_Viewer">
<property name="text">
<string>Counter selection</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
+6 -3
View File
@@ -216,7 +216,8 @@ SOURCES += Code/qrenderdoc.cpp \
Widgets/FindReplace.cpp \
Widgets/Extended/RDSplitter.cpp \
Windows/Dialogs/TipsDialog.cpp \
Windows/PythonShell.cpp
Windows/PythonShell.cpp \
Windows/Dialogs/PerformanceCounterSelection.cpp
HEADERS += Code/CaptureContext.h \
Code/qprocessinfo.h \
Code/ReplayManager.h \
@@ -280,7 +281,8 @@ HEADERS += Code/CaptureContext.h \
Widgets/FindReplace.h \
Widgets/Extended/RDSplitter.h \
Windows/Dialogs/TipsDialog.h \
Windows/PythonShell.h
Windows/PythonShell.h \
Windows/Dialogs/PerformanceCounterSelection.h
FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/MainWindow.ui \
Windows/EventBrowser.ui \
@@ -311,7 +313,8 @@ FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/Dialogs/EnvironmentEditor.ui \
Widgets/FindReplace.ui \
Windows/Dialogs/TipsDialog.ui \
Windows/PythonShell.ui
Windows/PythonShell.ui \
Windows/Dialogs/PerformanceCounterSelection.ui
RESOURCES += Resources/resources.qrc
+16
View File
@@ -592,6 +592,7 @@
<ClCompile Include="$(IntDir)generated\moc_EnvironmentEditor.cpp" />
<ClCompile Include="$(IntDir)generated\moc_OrderedListEditor.cpp" />
<ClCompile Include="$(IntDir)generated\moc_RemoteManager.cpp" />
<ClCompile Include="$(IntDir)generated\moc_PerformanceCounterSelection.cpp" />
<ClCompile Include="$(IntDir)generated\moc_PipelineStateViewer.cpp" />
<ClCompile Include="$(IntDir)generated\moc_PythonContext.cpp" />
<ClCompile Include="$(IntDir)generated\moc_QRDUtils.cpp" />
@@ -683,6 +684,7 @@
<ClCompile Include="Windows\Dialogs\LiveCapture.cpp" />
<ClCompile Include="Windows\Dialogs\EnvironmentEditor.cpp" />
<ClCompile Include="Windows\Dialogs\OrderedListEditor.cpp" />
<ClCompile Include="Windows\Dialogs\PerformanceCounterSelection.cpp" />
<ClCompile Include="Windows\Dialogs\RemoteManager.cpp" />
<ClCompile Include="Windows\Dialogs\SettingsDialog.cpp" />
<ClCompile Include="Windows\Dialogs\SuggestRemoteDialog.cpp" />
@@ -763,6 +765,12 @@
<ClInclude Include="3rdparty\scintilla\lexlib\SubStyles.h" />
<ClInclude Include="3rdparty\scintilla\lexlib\WordList.h" />
<ClInclude Include="3rdparty\scintilla\qt\ScintillaEditBase\PlatQt.h" />
<CustomBuild Include="Windows\Dialogs\PerformanceCounterSelection.h">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I$(ProjectDir) -I$(SolutionDir)\renderdoc\api\replay -I$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015 -I$(ProjectDir)3rdparty\qt\$(Platform)\include -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore %(Fullpath) -o $(IntDir)generated\moc_%(Filename).cpp</Command>
<Message>MOC %(Filename).h</Message>
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
</CustomBuild>
<CustomBuild Include="3rdparty\scintilla\qt\ScintillaEditBase\ScintillaEditBase.h">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe" -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I"$(ProjectDir)." -I"$(SolutionDir)\renderdoc\api\replay" -I"$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore" "%(Fullpath)" -o "$(IntDir)generated\moc_%(Filename).cpp"</Command>
@@ -876,6 +884,7 @@
<ClInclude Include="$(IntDir)generated\ui_EnvironmentEditor.h" />
<ClInclude Include="$(IntDir)generated\ui_OrderedListEditor.h" />
<ClInclude Include="$(IntDir)generated\ui_RemoteManager.h" />
<ClInclude Include="$(IntDir)generated\ui_PerformanceCounterSelection.h" />
<ClInclude Include="$(IntDir)generated\ui_PipelineStateViewer.h" />
<ClInclude Include="$(IntDir)generated\ui_ResourcePreview.h" />
<ClInclude Include="$(IntDir)generated\ui_SettingsDialog.h" />
@@ -1501,6 +1510,13 @@ IF %ERRORLEVEL% NEQ 0 (echo ====================================================
<None Include="Resources\zoom.png" />
<None Include="Resources\action.png" />
<None Include="Resources\action_hover.png" />
<CustomBuild Include="Windows\Dialogs\PerformanceCounterSelection.ui">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe %(Fullpath) -o $(IntDir)generated\ui_%(Filename).h</Command>
<Message>UIC %(Filename).ui</Message>
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
<SubType>Designer</SubType>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Content Include="3rdparty\python\python36.zip">
@@ -651,6 +651,9 @@
<ClCompile Include="Styles\StyleData.cpp">
<Filter>Styles</Filter>
</ClCompile>
<ClCompile Include="Windows\Dialogs\PerformanceCounterSelection.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
@@ -965,6 +968,9 @@
<ClInclude Include="Styles\StyleData.h">
<Filter>Styles</Filter>
</ClInclude>
<ClInclude Include="Windows\Dialogs\PerformanceCounterSelection.h">
<Filter>Windows\Dialogs</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Resources\128.png">
@@ -1147,6 +1153,9 @@
<None Include="Code\pyrenderdoc\pyconversion.i">
<Filter>Code\pyrenderdoc</Filter>
</None>
<None Include="Windows\Dialogs\PerformanceCounterSelection.ui">
<Filter>Windows\Dialogs</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resources\qrenderdoc.rc">
+3
View File
@@ -891,6 +891,9 @@ struct CounterDescription
DOCUMENT("A short human-readable name for the counter.");
rdctype::str name;
DOCUMENT("The counter category. Can be empty for uncategorized counters.");
rdctype::str category;
DOCUMENT("If available, a longer human-readable description of the value this counter measures.");
rdctype::str description;
+2 -1
View File
@@ -1593,8 +1593,9 @@ void Serialiser::Serialise(const char *name, CounterDescription &el)
Serialise("", el.resultType);
Serialise("", el.resultByteWidth);
Serialise("", el.unit);
Serialise("", el.category);
SIZE_CHECK(56);
SIZE_CHECK(72);
}
template <>
@@ -90,6 +90,8 @@ void D3D11DebugManager::DescribeCounter(GPUCounter counterID, CounterDescription
}
}
desc.category = "D3D11";
switch(counterID)
{
case GPUCounter::EventGPUDuration:
+30 -2
View File
@@ -219,7 +219,7 @@ vector<AMDCounters::InternalCounterDescription> AMDCounters::EnumerateCounters()
internalDesc.desc = InternalGetCounterDescription(i);
// We ignore any D3D11 counters, as those are handled elsewhere
if(strncmp(internalDesc.desc.description.c_str(), "#D3D11#", 7) == 0)
if(strncmp(internalDesc.desc.category.c_str(), "D3D11", 5) == 0)
{
continue;
}
@@ -249,7 +249,35 @@ CounterDescription AMDCounters::InternalGetCounterDescription(uint32_t internalI
m_pGPUPerfAPI->getCounterName(internalIndex, &tmp);
desc.name = tmp;
m_pGPUPerfAPI->getCounterDescription(internalIndex, &tmp);
desc.description = tmp;
std::vector<char> descCopy;
int separator = -1;
int sharpFound = 0;
const char *c = tmp;
while(*c)
{
if(*c == '#')
{
++sharpFound;
descCopy.push_back('\0');
if(sharpFound == 2)
{
separator = (int32_t)(c - tmp);
}
}
else
{
descCopy.push_back(*c);
}
++c;
}
descCopy.push_back('\0');
desc.category = descCopy.data() + 1;
desc.description = descCopy.data() + separator + 1;
GPA_Usage_Type usageType;