forked from qt-creator/qt-creator
Perf: Move config widget setup closer to settingspage
Change-Id: Idda753dc07103dc0f6d0c3ff9759d0ff083ac2d9 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -10,7 +10,6 @@ endif()
|
||||
|
||||
set(PERFPROFILER_CPP_SOURCES
|
||||
perfconfigeventsmodel.cpp perfconfigeventsmodel.h
|
||||
perfconfigwidget.cpp perfconfigwidget.h
|
||||
perfdatareader.cpp perfdatareader.h
|
||||
perfevent.h
|
||||
perfeventtype.h
|
||||
|
@@ -1,369 +0,0 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "perfconfigeventsmodel.h"
|
||||
#include "perfconfigwidget.h"
|
||||
#include "perfprofilertr.h"
|
||||
|
||||
#include <coreplugin/messagebox.h>
|
||||
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <utils/aspects.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/process.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QHeaderView>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaEnum>
|
||||
#include <QPushButton>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QTableView>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace PerfProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class SettingsDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SettingsDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
PerfConfigWidget::PerfConfigWidget(PerfSettings *settings, QWidget *parent)
|
||||
: m_settings(settings)
|
||||
{
|
||||
setParent(parent);
|
||||
|
||||
eventsView = new QTableView(this);
|
||||
eventsView->setMinimumSize(QSize(0, 300));
|
||||
eventsView->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||||
eventsView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
eventsView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
eventsView->setModel(new PerfConfigEventsModel(m_settings, this));
|
||||
eventsView->setItemDelegate(new SettingsDelegate(this));
|
||||
eventsView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
|
||||
useTracePointsButton = new QPushButton(this);
|
||||
useTracePointsButton->setText(Tr::tr("Use Trace Points"));
|
||||
useTracePointsButton->setVisible(false);
|
||||
connect(useTracePointsButton, &QPushButton::pressed,
|
||||
this, &PerfConfigWidget::readTracePoints);
|
||||
|
||||
addEventButton = new QPushButton(this);
|
||||
addEventButton->setText(Tr::tr("Add Event"));
|
||||
connect(addEventButton, &QPushButton::pressed, this, [this]() {
|
||||
auto model = eventsView->model();
|
||||
model->insertRow(model->rowCount());
|
||||
});
|
||||
|
||||
removeEventButton = new QPushButton(this);
|
||||
removeEventButton->setText(Tr::tr("Remove Event"));
|
||||
connect(removeEventButton, &QPushButton::pressed, this, [this]() {
|
||||
QModelIndex index = eventsView->currentIndex();
|
||||
if (index.isValid())
|
||||
eventsView->model()->removeRow(index.row());
|
||||
});
|
||||
|
||||
resetButton = new QPushButton(this);
|
||||
resetButton->setText(Tr::tr("Reset"));
|
||||
connect(resetButton, &QPushButton::pressed, m_settings, &PerfSettings::resetToDefault);
|
||||
|
||||
using namespace Layouting;
|
||||
Column {
|
||||
Row { st, useTracePointsButton, addEventButton, removeEventButton, resetButton },
|
||||
|
||||
eventsView,
|
||||
|
||||
Grid {
|
||||
m_settings->callgraphMode, m_settings->stackSize, br,
|
||||
m_settings->sampleMode, m_settings->period, br,
|
||||
m_settings->extraArguments,
|
||||
},
|
||||
|
||||
st
|
||||
}.attachTo(this);
|
||||
}
|
||||
|
||||
PerfConfigWidget::~PerfConfigWidget() = default;
|
||||
|
||||
void PerfConfigWidget::setTarget(ProjectExplorer::Target *target)
|
||||
{
|
||||
ProjectExplorer::IDevice::ConstPtr device;
|
||||
if (target) {
|
||||
if (ProjectExplorer::Kit *kit = target->kit())
|
||||
device = ProjectExplorer::DeviceKitAspect::device(kit);
|
||||
}
|
||||
|
||||
if (device.isNull()) {
|
||||
useTracePointsButton->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QTC_ASSERT(device, return);
|
||||
QTC_CHECK(!m_process || m_process->state() == QProcess::NotRunning);
|
||||
|
||||
m_process.reset(new Process);
|
||||
m_process->setCommand({device->filePath("perf"), {"probe", "-l"}});
|
||||
connect(m_process.get(), &Process::done,
|
||||
this, &PerfConfigWidget::handleProcessDone);
|
||||
|
||||
useTracePointsButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void PerfConfigWidget::setTracePointsButtonVisible(bool visible)
|
||||
{
|
||||
useTracePointsButton->setVisible(visible);
|
||||
}
|
||||
|
||||
void PerfConfigWidget::apply()
|
||||
{
|
||||
m_settings->writeGlobalSettings();
|
||||
}
|
||||
|
||||
void PerfConfigWidget::readTracePoints()
|
||||
{
|
||||
QMessageBox messageBox;
|
||||
messageBox.setWindowTitle(Tr::tr("Use Trace Points"));
|
||||
messageBox.setIcon(QMessageBox::Question);
|
||||
messageBox.setText(Tr::tr("Replace events with trace points read from the device?"));
|
||||
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
if (messageBox.exec() == QMessageBox::Yes) {
|
||||
m_process->start();
|
||||
useTracePointsButton->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PerfConfigWidget::handleProcessDone()
|
||||
{
|
||||
if (m_process->error() == QProcess::FailedToStart) {
|
||||
Core::AsynchronousMessageBox::warning(
|
||||
Tr::tr("Cannot List Trace Points"),
|
||||
Tr::tr("\"perf probe -l\" failed to start. Is perf installed?"));
|
||||
useTracePointsButton->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
const QList<QByteArray> lines =
|
||||
m_process->readAllRawStandardOutput().append(m_process->readAllRawStandardError())
|
||||
.split('\n');
|
||||
auto model = eventsView->model();
|
||||
const int previousRows = model->rowCount();
|
||||
QHash<QByteArray, QByteArray> tracePoints;
|
||||
for (const QByteArray &line : lines) {
|
||||
const QByteArray trimmed = line.trimmed();
|
||||
const int space = trimmed.indexOf(' ');
|
||||
if (space < 0)
|
||||
continue;
|
||||
|
||||
// If the whole "on ..." string is the same, the trace points are redundant
|
||||
tracePoints[trimmed.mid(space + 1)] = trimmed.left(space);
|
||||
}
|
||||
|
||||
if (tracePoints.isEmpty()) {
|
||||
Core::AsynchronousMessageBox::warning(
|
||||
Tr::tr("No Trace Points Found"),
|
||||
Tr::tr("Trace points can be defined with \"perf probe -a\"."));
|
||||
} else {
|
||||
for (const QByteArray &event : std::as_const(tracePoints)) {
|
||||
int row = model->rowCount();
|
||||
model->insertRow(row);
|
||||
model->setData(model->index(row, PerfConfigEventsModel::ColumnEventType),
|
||||
PerfConfigEventsModel::EventTypeCustom);
|
||||
model->setData(model->index(row, PerfConfigEventsModel::ColumnSubType),
|
||||
QString::fromUtf8(event));
|
||||
}
|
||||
model->removeRows(0, previousRows);
|
||||
m_settings->sampleMode.setVolatileValue(1);
|
||||
m_settings->period.setVolatileValue(1);
|
||||
}
|
||||
useTracePointsButton->setEnabled(true);
|
||||
}
|
||||
|
||||
QWidget *SettingsDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(option)
|
||||
const int row = index.row();
|
||||
const int column = index.column();
|
||||
const PerfConfigEventsModel *model = qobject_cast<const PerfConfigEventsModel *>(index.model());
|
||||
|
||||
auto getRowEventType = [&]() {
|
||||
return qvariant_cast<PerfConfigEventsModel::EventType>(
|
||||
model->data(model->index(row, PerfConfigEventsModel::ColumnEventType),
|
||||
Qt::EditRole));
|
||||
};
|
||||
|
||||
switch (column) {
|
||||
case PerfConfigEventsModel::ColumnEventType: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
QMetaEnum meta = QMetaEnum::fromType<PerfConfigEventsModel::EventType>();
|
||||
for (int i = 0; i < PerfConfigEventsModel::EventTypeInvalid; ++i) {
|
||||
editor->addItem(QString::fromLatin1(meta.valueToKey(i)).mid(
|
||||
static_cast<int>(strlen("EventType"))).toLower(), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::ColumnSubType: {
|
||||
PerfConfigEventsModel::EventType eventType = getRowEventType();
|
||||
switch (eventType) {
|
||||
case PerfConfigEventsModel::EventTypeHardware: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
for (int i = PerfConfigEventsModel::SubTypeEventTypeHardware;
|
||||
i < PerfConfigEventsModel::SubTypeEventTypeSoftware; ++i) {
|
||||
editor->addItem(PerfConfigEventsModel::subTypeString(PerfConfigEventsModel::EventTypeHardware,
|
||||
PerfConfigEventsModel::SubType(i)), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeSoftware: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
for (int i = PerfConfigEventsModel::SubTypeEventTypeSoftware;
|
||||
i < PerfConfigEventsModel::SubTypeEventTypeCache; ++i) {
|
||||
editor->addItem(PerfConfigEventsModel::subTypeString(PerfConfigEventsModel::EventTypeSoftware,
|
||||
PerfConfigEventsModel::SubType(i)), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeCache: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
for (int i = PerfConfigEventsModel::SubTypeEventTypeCache;
|
||||
i < PerfConfigEventsModel::SubTypeInvalid; ++i) {
|
||||
editor->addItem(PerfConfigEventsModel::subTypeString(PerfConfigEventsModel::EventTypeCache,
|
||||
PerfConfigEventsModel::SubType(i)), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeBreakpoint: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setText("0x0000000000000000");
|
||||
editor->setValidator(new QRegularExpressionValidator(
|
||||
QRegularExpression("0x[0-9a-f]{16}"), parent));
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeCustom: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeRaw: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setText("r000");
|
||||
editor->setValidator(new QRegularExpressionValidator(
|
||||
QRegularExpression("r[0-9a-f]{3}"), parent));
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeInvalid:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr; // Will never be reached, but GCC cannot figure this out.
|
||||
}
|
||||
case PerfConfigEventsModel::ColumnOperation: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
PerfConfigEventsModel::EventType eventType = getRowEventType();
|
||||
if (eventType == PerfConfigEventsModel::EventTypeCache) {
|
||||
editor->addItem("load", PerfConfigEventsModel::OperationLoad);
|
||||
editor->addItem("store", PerfConfigEventsModel::OperationStore);
|
||||
editor->addItem("prefetch", PerfConfigEventsModel::OperationPrefetch);
|
||||
} else if (eventType == PerfConfigEventsModel::EventTypeBreakpoint) {
|
||||
editor->addItem("r", PerfConfigEventsModel::OperationLoad);
|
||||
editor->addItem("rw", PerfConfigEventsModel::OperationLoad
|
||||
| PerfConfigEventsModel::OperationStore);
|
||||
editor->addItem("rwx", PerfConfigEventsModel::OperationLoad
|
||||
| PerfConfigEventsModel::OperationStore
|
||||
| PerfConfigEventsModel::OperationExecute);
|
||||
editor->addItem("rx", PerfConfigEventsModel::OperationLoad
|
||||
| PerfConfigEventsModel::OperationExecute);
|
||||
editor->addItem("w", PerfConfigEventsModel::OperationStore);
|
||||
editor->addItem("wx", PerfConfigEventsModel::OperationStore
|
||||
| PerfConfigEventsModel::OperationExecute);
|
||||
editor->addItem("x", PerfConfigEventsModel::OperationExecute);
|
||||
} else {
|
||||
editor->setEnabled(false);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::ColumnResult: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
PerfConfigEventsModel::EventType eventType = getRowEventType();
|
||||
if (eventType != PerfConfigEventsModel::EventTypeCache) {
|
||||
editor->setEnabled(false);
|
||||
} else {
|
||||
editor->addItem("refs", PerfConfigEventsModel::ResultRefs);
|
||||
editor->addItem("misses", PerfConfigEventsModel::ResultMisses);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *combo = qobject_cast<QComboBox *>(editor)) {
|
||||
QVariant data = index.model()->data(index, Qt::EditRole);
|
||||
for (int i = 0, end = combo->count(); i != end; ++i) {
|
||||
if (combo->itemData(i) == data) {
|
||||
combo->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (QLineEdit *lineedit = qobject_cast<QLineEdit *>(editor)) {
|
||||
lineedit->setText(index.model()->data(index, Qt::DisplayRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *combo = qobject_cast<QComboBox *>(editor)) {
|
||||
model->setData(index, combo->currentData());
|
||||
} else if (QLineEdit *lineedit = qobject_cast<QLineEdit *>(editor)) {
|
||||
QString text = lineedit->text();
|
||||
QVariant type = model->data(model->index(index.row(),
|
||||
PerfConfigEventsModel::ColumnEventType),
|
||||
Qt::EditRole);
|
||||
switch (qvariant_cast<PerfConfigEventsModel::EventType>(type)) {
|
||||
case PerfConfigEventsModel::EventTypeRaw:
|
||||
model->setData(index, text.mid(static_cast<int>(strlen("r"))).toULongLong(nullptr, 16));
|
||||
break;
|
||||
case PerfConfigEventsModel::EventTypeBreakpoint:
|
||||
model->setData(index,
|
||||
text.mid(static_cast<int>(strlen("0x"))).toULongLong(nullptr, 16));
|
||||
break;
|
||||
case PerfConfigEventsModel::EventTypeCustom:
|
||||
model->setData(index, text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace PerfProfiler
|
||||
|
||||
#include "perfconfigwidget.moc"
|
@@ -1,50 +0,0 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "perfsettings.h"
|
||||
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPushButton;
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils { class Process; }
|
||||
|
||||
namespace PerfProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class PerfConfigWidget : public Core::IOptionsPageWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PerfConfigWidget(PerfSettings *settings, QWidget *parent = nullptr);
|
||||
~PerfConfigWidget();
|
||||
|
||||
void updateUi();
|
||||
void setTarget(ProjectExplorer::Target *target);
|
||||
void setTracePointsButtonVisible(bool visible);
|
||||
|
||||
private:
|
||||
void apply() final;
|
||||
|
||||
void readTracePoints();
|
||||
void handleProcessDone();
|
||||
|
||||
PerfSettings *m_settings;
|
||||
std::unique_ptr<Utils::Process> m_process;
|
||||
|
||||
QTableView *eventsView;
|
||||
QPushButton *useTracePointsButton;
|
||||
QPushButton *addEventButton;
|
||||
QPushButton *removeEventButton;
|
||||
QPushButton *resetButton;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace PerfProfiler
|
@@ -18,8 +18,6 @@ QtcPlugin {
|
||||
files: [
|
||||
"perfconfigeventsmodel.cpp",
|
||||
"perfconfigeventsmodel.h",
|
||||
"perfconfigwidget.cpp",
|
||||
"perfconfigwidget.h",
|
||||
"perfdatareader.cpp",
|
||||
"perfdatareader.h",
|
||||
"perfevent.h",
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "perfprofilertool.h"
|
||||
|
||||
#include "perfconfigwidget.h"
|
||||
#include "perfloaddialog.h"
|
||||
#include "perfprofilerplugin.h"
|
||||
#include "perfprofilertr.h"
|
||||
@@ -236,11 +235,8 @@ void PerfProfilerTool::createViews()
|
||||
settings = runConfig->currentSettings<PerfSettings>(Constants::PerfSettingsId);
|
||||
}
|
||||
|
||||
PerfConfigWidget *widget = new PerfConfigWidget(
|
||||
settings ? settings : &globalSettings(),
|
||||
Core::ICore::dialogParent());
|
||||
widget->setTracePointsButtonVisible(true);
|
||||
widget->setTarget(target);
|
||||
QWidget *widget = settings ? settings->createPerfConfigWidget(target)
|
||||
: globalSettings().createPerfConfigWidget(target);
|
||||
widget->setWindowFlags(Qt::Dialog);
|
||||
widget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
widget->show();
|
||||
|
@@ -1,24 +1,375 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "perfconfigwidget.h"
|
||||
#include "perfsettings.h"
|
||||
|
||||
#include "perfconfigeventsmodel.h"
|
||||
#include "perfprofilerconstants.h"
|
||||
#include "perfprofilertr.h"
|
||||
#include "perfsettings.h"
|
||||
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagebox.h>
|
||||
|
||||
#include <debugger/analyzer/analyzericons.h>
|
||||
#include <debugger/debuggertr.h>
|
||||
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <utils/aspects.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/process.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QHeaderView>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaEnum>
|
||||
#include <QPushButton>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QTableView>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
using namespace PerfProfiler::Internal;
|
||||
|
||||
namespace PerfProfiler {
|
||||
|
||||
class PerfConfigWidget : public Core::IOptionsPageWidget
|
||||
{
|
||||
public:
|
||||
PerfConfigWidget(PerfSettings *settings, Target *target);
|
||||
|
||||
private:
|
||||
void apply() final;
|
||||
|
||||
void readTracePoints();
|
||||
void handleProcessDone();
|
||||
|
||||
PerfSettings *m_settings;
|
||||
std::unique_ptr<Utils::Process> m_process;
|
||||
|
||||
QTableView *eventsView;
|
||||
QPushButton *useTracePointsButton;
|
||||
};
|
||||
|
||||
class SettingsDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
SettingsDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &) const override
|
||||
{
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
};
|
||||
|
||||
PerfConfigWidget::PerfConfigWidget(PerfSettings *settings, Target *target)
|
||||
: m_settings(settings)
|
||||
{
|
||||
eventsView = new QTableView(this);
|
||||
eventsView->setMinimumSize(QSize(0, 300));
|
||||
eventsView->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||||
eventsView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
eventsView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
eventsView->setModel(new PerfConfigEventsModel(m_settings, this));
|
||||
eventsView->setItemDelegate(new SettingsDelegate(this));
|
||||
eventsView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
|
||||
useTracePointsButton = new QPushButton(this);
|
||||
useTracePointsButton->setText(Tr::tr("Use Trace Points"));
|
||||
useTracePointsButton->setVisible(target != nullptr);
|
||||
connect(useTracePointsButton, &QPushButton::pressed,
|
||||
this, &PerfConfigWidget::readTracePoints);
|
||||
|
||||
auto addEventButton = new QPushButton(Tr::tr("Add Event"), this);
|
||||
connect(addEventButton, &QPushButton::pressed, this, [this]() {
|
||||
auto model = eventsView->model();
|
||||
model->insertRow(model->rowCount());
|
||||
});
|
||||
|
||||
auto removeEventButton = new QPushButton(Tr::tr("Remove Event"), this);
|
||||
connect(removeEventButton, &QPushButton::pressed, this, [this] {
|
||||
QModelIndex index = eventsView->currentIndex();
|
||||
if (index.isValid())
|
||||
eventsView->model()->removeRow(index.row());
|
||||
});
|
||||
|
||||
auto resetButton = new QPushButton(Tr::tr("Reset"), this);
|
||||
connect(resetButton, &QPushButton::pressed, m_settings, &PerfSettings::resetToDefault);
|
||||
|
||||
using namespace Layouting;
|
||||
Column {
|
||||
Row { st, useTracePointsButton, addEventButton, removeEventButton, resetButton },
|
||||
|
||||
eventsView,
|
||||
|
||||
Grid {
|
||||
m_settings->callgraphMode, m_settings->stackSize, br,
|
||||
m_settings->sampleMode, m_settings->period, br,
|
||||
m_settings->extraArguments,
|
||||
},
|
||||
|
||||
st
|
||||
}.attachTo(this);
|
||||
|
||||
IDevice::ConstPtr device;
|
||||
if (target)
|
||||
device = DeviceKitAspect::device(target->kit());
|
||||
|
||||
if (device.isNull()) {
|
||||
useTracePointsButton->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QTC_ASSERT(device, return);
|
||||
QTC_CHECK(!m_process || m_process->state() == QProcess::NotRunning);
|
||||
|
||||
m_process.reset(new Process);
|
||||
m_process->setCommand({device->filePath("perf"), {"probe", "-l"}});
|
||||
connect(m_process.get(), &Process::done,
|
||||
this, &PerfConfigWidget::handleProcessDone);
|
||||
|
||||
useTracePointsButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void PerfConfigWidget::apply()
|
||||
{
|
||||
m_settings->writeGlobalSettings();
|
||||
}
|
||||
|
||||
void PerfConfigWidget::readTracePoints()
|
||||
{
|
||||
QMessageBox messageBox;
|
||||
messageBox.setWindowTitle(Tr::tr("Use Trace Points"));
|
||||
messageBox.setIcon(QMessageBox::Question);
|
||||
messageBox.setText(Tr::tr("Replace events with trace points read from the device?"));
|
||||
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
if (messageBox.exec() == QMessageBox::Yes) {
|
||||
m_process->start();
|
||||
useTracePointsButton->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PerfConfigWidget::handleProcessDone()
|
||||
{
|
||||
if (m_process->error() == QProcess::FailedToStart) {
|
||||
Core::AsynchronousMessageBox::warning(
|
||||
Tr::tr("Cannot List Trace Points"),
|
||||
Tr::tr("\"perf probe -l\" failed to start. Is perf installed?"));
|
||||
useTracePointsButton->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
const QList<QByteArray> lines =
|
||||
m_process->readAllRawStandardOutput().append(m_process->readAllRawStandardError())
|
||||
.split('\n');
|
||||
auto model = eventsView->model();
|
||||
const int previousRows = model->rowCount();
|
||||
QHash<QByteArray, QByteArray> tracePoints;
|
||||
for (const QByteArray &line : lines) {
|
||||
const QByteArray trimmed = line.trimmed();
|
||||
const int space = trimmed.indexOf(' ');
|
||||
if (space < 0)
|
||||
continue;
|
||||
|
||||
// If the whole "on ..." string is the same, the trace points are redundant
|
||||
tracePoints[trimmed.mid(space + 1)] = trimmed.left(space);
|
||||
}
|
||||
|
||||
if (tracePoints.isEmpty()) {
|
||||
Core::AsynchronousMessageBox::warning(
|
||||
Tr::tr("No Trace Points Found"),
|
||||
Tr::tr("Trace points can be defined with \"perf probe -a\"."));
|
||||
} else {
|
||||
for (const QByteArray &event : std::as_const(tracePoints)) {
|
||||
int row = model->rowCount();
|
||||
model->insertRow(row);
|
||||
model->setData(model->index(row, PerfConfigEventsModel::ColumnEventType),
|
||||
PerfConfigEventsModel::EventTypeCustom);
|
||||
model->setData(model->index(row, PerfConfigEventsModel::ColumnSubType),
|
||||
QString::fromUtf8(event));
|
||||
}
|
||||
model->removeRows(0, previousRows);
|
||||
m_settings->sampleMode.setVolatileValue(1);
|
||||
m_settings->period.setVolatileValue(1);
|
||||
}
|
||||
useTracePointsButton->setEnabled(true);
|
||||
}
|
||||
|
||||
QWidget *SettingsDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(option)
|
||||
const int row = index.row();
|
||||
const int column = index.column();
|
||||
const PerfConfigEventsModel *model = qobject_cast<const PerfConfigEventsModel *>(index.model());
|
||||
|
||||
auto getRowEventType = [&]() {
|
||||
return qvariant_cast<PerfConfigEventsModel::EventType>(
|
||||
model->data(model->index(row, PerfConfigEventsModel::ColumnEventType),
|
||||
Qt::EditRole));
|
||||
};
|
||||
|
||||
switch (column) {
|
||||
case PerfConfigEventsModel::ColumnEventType: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
QMetaEnum meta = QMetaEnum::fromType<PerfConfigEventsModel::EventType>();
|
||||
for (int i = 0; i < PerfConfigEventsModel::EventTypeInvalid; ++i) {
|
||||
editor->addItem(QString::fromLatin1(meta.valueToKey(i)).mid(
|
||||
static_cast<int>(strlen("EventType"))).toLower(), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::ColumnSubType: {
|
||||
PerfConfigEventsModel::EventType eventType = getRowEventType();
|
||||
switch (eventType) {
|
||||
case PerfConfigEventsModel::EventTypeHardware: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
for (int i = PerfConfigEventsModel::SubTypeEventTypeHardware;
|
||||
i < PerfConfigEventsModel::SubTypeEventTypeSoftware; ++i) {
|
||||
editor->addItem(PerfConfigEventsModel::subTypeString(PerfConfigEventsModel::EventTypeHardware,
|
||||
PerfConfigEventsModel::SubType(i)), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeSoftware: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
for (int i = PerfConfigEventsModel::SubTypeEventTypeSoftware;
|
||||
i < PerfConfigEventsModel::SubTypeEventTypeCache; ++i) {
|
||||
editor->addItem(PerfConfigEventsModel::subTypeString(PerfConfigEventsModel::EventTypeSoftware,
|
||||
PerfConfigEventsModel::SubType(i)), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeCache: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
for (int i = PerfConfigEventsModel::SubTypeEventTypeCache;
|
||||
i < PerfConfigEventsModel::SubTypeInvalid; ++i) {
|
||||
editor->addItem(PerfConfigEventsModel::subTypeString(PerfConfigEventsModel::EventTypeCache,
|
||||
PerfConfigEventsModel::SubType(i)), i);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeBreakpoint: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setText("0x0000000000000000");
|
||||
editor->setValidator(new QRegularExpressionValidator(
|
||||
QRegularExpression("0x[0-9a-f]{16}"), parent));
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeCustom: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeRaw: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setText("r000");
|
||||
editor->setValidator(new QRegularExpressionValidator(
|
||||
QRegularExpression("r[0-9a-f]{3}"), parent));
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::EventTypeInvalid:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr; // Will never be reached, but GCC cannot figure this out.
|
||||
}
|
||||
case PerfConfigEventsModel::ColumnOperation: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
PerfConfigEventsModel::EventType eventType = getRowEventType();
|
||||
if (eventType == PerfConfigEventsModel::EventTypeCache) {
|
||||
editor->addItem("load", PerfConfigEventsModel::OperationLoad);
|
||||
editor->addItem("store", PerfConfigEventsModel::OperationStore);
|
||||
editor->addItem("prefetch", PerfConfigEventsModel::OperationPrefetch);
|
||||
} else if (eventType == PerfConfigEventsModel::EventTypeBreakpoint) {
|
||||
editor->addItem("r", PerfConfigEventsModel::OperationLoad);
|
||||
editor->addItem("rw", PerfConfigEventsModel::OperationLoad
|
||||
| PerfConfigEventsModel::OperationStore);
|
||||
editor->addItem("rwx", PerfConfigEventsModel::OperationLoad
|
||||
| PerfConfigEventsModel::OperationStore
|
||||
| PerfConfigEventsModel::OperationExecute);
|
||||
editor->addItem("rx", PerfConfigEventsModel::OperationLoad
|
||||
| PerfConfigEventsModel::OperationExecute);
|
||||
editor->addItem("w", PerfConfigEventsModel::OperationStore);
|
||||
editor->addItem("wx", PerfConfigEventsModel::OperationStore
|
||||
| PerfConfigEventsModel::OperationExecute);
|
||||
editor->addItem("x", PerfConfigEventsModel::OperationExecute);
|
||||
} else {
|
||||
editor->setEnabled(false);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
case PerfConfigEventsModel::ColumnResult: {
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
PerfConfigEventsModel::EventType eventType = getRowEventType();
|
||||
if (eventType != PerfConfigEventsModel::EventTypeCache) {
|
||||
editor->setEnabled(false);
|
||||
} else {
|
||||
editor->addItem("refs", PerfConfigEventsModel::ResultRefs);
|
||||
editor->addItem("misses", PerfConfigEventsModel::ResultMisses);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *combo = qobject_cast<QComboBox *>(editor)) {
|
||||
QVariant data = index.model()->data(index, Qt::EditRole);
|
||||
for (int i = 0, end = combo->count(); i != end; ++i) {
|
||||
if (combo->itemData(i) == data) {
|
||||
combo->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (QLineEdit *lineedit = qobject_cast<QLineEdit *>(editor)) {
|
||||
lineedit->setText(index.model()->data(index, Qt::DisplayRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (QComboBox *combo = qobject_cast<QComboBox *>(editor)) {
|
||||
model->setData(index, combo->currentData());
|
||||
} else if (QLineEdit *lineedit = qobject_cast<QLineEdit *>(editor)) {
|
||||
QString text = lineedit->text();
|
||||
QVariant type = model->data(model->index(index.row(),
|
||||
PerfConfigEventsModel::ColumnEventType),
|
||||
Qt::EditRole);
|
||||
switch (qvariant_cast<PerfConfigEventsModel::EventType>(type)) {
|
||||
case PerfConfigEventsModel::EventTypeRaw:
|
||||
model->setData(index, text.mid(static_cast<int>(strlen("r"))).toULongLong(nullptr, 16));
|
||||
break;
|
||||
case PerfConfigEventsModel::EventTypeBreakpoint:
|
||||
model->setData(index,
|
||||
text.mid(static_cast<int>(strlen("0x"))).toULongLong(nullptr, 16));
|
||||
break;
|
||||
case PerfConfigEventsModel::EventTypeCustom:
|
||||
model->setData(index, text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PerfSettingsPage
|
||||
|
||||
PerfSettings &globalSettings()
|
||||
{
|
||||
static PerfSettings theSettings(nullptr);
|
||||
@@ -67,9 +418,7 @@ PerfSettings::PerfSettings(ProjectExplorer::Target *target)
|
||||
|
||||
setLayouter([this, target] {
|
||||
using namespace Layouting;
|
||||
auto widget = new Internal::PerfConfigWidget(this);
|
||||
widget->setTracePointsButtonVisible(target != nullptr);
|
||||
widget->setTarget(target);
|
||||
auto widget = new PerfConfigWidget(this, target);
|
||||
return Column { widget };
|
||||
});
|
||||
|
||||
@@ -137,6 +486,11 @@ void PerfSettings::resetToDefault()
|
||||
fromMap(map);
|
||||
}
|
||||
|
||||
QWidget *PerfSettings::createPerfConfigWidget(Target *target)
|
||||
{
|
||||
return new PerfConfigWidget(this, target);
|
||||
}
|
||||
|
||||
// PerfSettingsPage
|
||||
|
||||
class PerfSettingsPage final : public Core::IOptionsPage
|
||||
|
@@ -24,6 +24,8 @@ public:
|
||||
|
||||
void resetToDefault();
|
||||
|
||||
QWidget *createPerfConfigWidget(ProjectExplorer::Target *target);
|
||||
|
||||
Utils::IntegerAspect period{this};
|
||||
Utils::IntegerAspect stackSize{this};
|
||||
Utils::SelectionAspect sampleMode{this};
|
||||
|
Reference in New Issue
Block a user