From 86e11befca98ad972bdb51a3d9c48e8afab3fc5b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Jul 2023 13:55:32 +0200 Subject: [PATCH] Perf: Move config widget setup closer to settingspage Change-Id: Idda753dc07103dc0f6d0c3ff9759d0ff083ac2d9 Reviewed-by: Christian Stenger --- src/plugins/perfprofiler/CMakeLists.txt | 1 - src/plugins/perfprofiler/perfconfigwidget.cpp | 369 ------------------ src/plugins/perfprofiler/perfconfigwidget.h | 50 --- src/plugins/perfprofiler/perfprofiler.qbs | 2 - src/plugins/perfprofiler/perfprofilertool.cpp | 8 +- src/plugins/perfprofiler/perfsettings.cpp | 364 ++++++++++++++++- src/plugins/perfprofiler/perfsettings.h | 2 + 7 files changed, 363 insertions(+), 433 deletions(-) delete mode 100644 src/plugins/perfprofiler/perfconfigwidget.cpp delete mode 100644 src/plugins/perfprofiler/perfconfigwidget.h diff --git a/src/plugins/perfprofiler/CMakeLists.txt b/src/plugins/perfprofiler/CMakeLists.txt index 7140042f565..360ee8a7ee9 100644 --- a/src/plugins/perfprofiler/CMakeLists.txt +++ b/src/plugins/perfprofiler/CMakeLists.txt @@ -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 diff --git a/src/plugins/perfprofiler/perfconfigwidget.cpp b/src/plugins/perfprofiler/perfconfigwidget.cpp deleted file mode 100644 index e5e3fd37256..00000000000 --- a/src/plugins/perfprofiler/perfconfigwidget.cpp +++ /dev/null @@ -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 - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -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 lines = - m_process->readAllRawStandardOutput().append(m_process->readAllRawStandardError()) - .split('\n'); - auto model = eventsView->model(); - const int previousRows = model->rowCount(); - QHash 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(index.model()); - - auto getRowEventType = [&]() { - return qvariant_cast( - model->data(model->index(row, PerfConfigEventsModel::ColumnEventType), - Qt::EditRole)); - }; - - switch (column) { - case PerfConfigEventsModel::ColumnEventType: { - QComboBox *editor = new QComboBox(parent); - QMetaEnum meta = QMetaEnum::fromType(); - for (int i = 0; i < PerfConfigEventsModel::EventTypeInvalid; ++i) { - editor->addItem(QString::fromLatin1(meta.valueToKey(i)).mid( - static_cast(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(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(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(editor)) { - model->setData(index, combo->currentData()); - } else if (QLineEdit *lineedit = qobject_cast(editor)) { - QString text = lineedit->text(); - QVariant type = model->data(model->index(index.row(), - PerfConfigEventsModel::ColumnEventType), - Qt::EditRole); - switch (qvariant_cast(type)) { - case PerfConfigEventsModel::EventTypeRaw: - model->setData(index, text.mid(static_cast(strlen("r"))).toULongLong(nullptr, 16)); - break; - case PerfConfigEventsModel::EventTypeBreakpoint: - model->setData(index, - text.mid(static_cast(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" diff --git a/src/plugins/perfprofiler/perfconfigwidget.h b/src/plugins/perfprofiler/perfconfigwidget.h deleted file mode 100644 index 5372647064e..00000000000 --- a/src/plugins/perfprofiler/perfconfigwidget.h +++ /dev/null @@ -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 - -#include - -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 m_process; - - QTableView *eventsView; - QPushButton *useTracePointsButton; - QPushButton *addEventButton; - QPushButton *removeEventButton; - QPushButton *resetButton; -}; - -} // namespace Internal -} // namespace PerfProfiler diff --git a/src/plugins/perfprofiler/perfprofiler.qbs b/src/plugins/perfprofiler/perfprofiler.qbs index 4604a2e2099..93235770250 100644 --- a/src/plugins/perfprofiler/perfprofiler.qbs +++ b/src/plugins/perfprofiler/perfprofiler.qbs @@ -18,8 +18,6 @@ QtcPlugin { files: [ "perfconfigeventsmodel.cpp", "perfconfigeventsmodel.h", - "perfconfigwidget.cpp", - "perfconfigwidget.h", "perfdatareader.cpp", "perfdatareader.h", "perfevent.h", diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 6e530e77689..4d2ed0b05a5 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -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(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(); diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index 4cb1286885e..0cc95595b6c 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -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 #include +#include #include #include +#include +#include +#include +#include + +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 lines = + m_process->readAllRawStandardOutput().append(m_process->readAllRawStandardError()) + .split('\n'); + auto model = eventsView->model(); + const int previousRows = model->rowCount(); + QHash 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(index.model()); + + auto getRowEventType = [&]() { + return qvariant_cast( + model->data(model->index(row, PerfConfigEventsModel::ColumnEventType), + Qt::EditRole)); + }; + + switch (column) { + case PerfConfigEventsModel::ColumnEventType: { + QComboBox *editor = new QComboBox(parent); + QMetaEnum meta = QMetaEnum::fromType(); + for (int i = 0; i < PerfConfigEventsModel::EventTypeInvalid; ++i) { + editor->addItem(QString::fromLatin1(meta.valueToKey(i)).mid( + static_cast(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(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(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(editor)) { + model->setData(index, combo->currentData()); + } else if (QLineEdit *lineedit = qobject_cast(editor)) { + QString text = lineedit->text(); + QVariant type = model->data(model->index(index.row(), + PerfConfigEventsModel::ColumnEventType), + Qt::EditRole); + switch (qvariant_cast(type)) { + case PerfConfigEventsModel::EventTypeRaw: + model->setData(index, text.mid(static_cast(strlen("r"))).toULongLong(nullptr, 16)); + break; + case PerfConfigEventsModel::EventTypeBreakpoint: + model->setData(index, + text.mid(static_cast(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 diff --git a/src/plugins/perfprofiler/perfsettings.h b/src/plugins/perfprofiler/perfsettings.h index bef4d996071..a53557b9c47 100644 --- a/src/plugins/perfprofiler/perfsettings.h +++ b/src/plugins/perfprofiler/perfsettings.h @@ -24,6 +24,8 @@ public: void resetToDefault(); + QWidget *createPerfConfigWidget(ProjectExplorer::Target *target); + Utils::IntegerAspect period{this}; Utils::IntegerAspect stackSize{this}; Utils::SelectionAspect sampleMode{this};