diff --git a/src/plugins/valgrind/callgrind/callgrindparsedata.cpp b/src/plugins/valgrind/callgrind/callgrindparsedata.cpp index 8c3c37143b5..683030a2beb 100644 --- a/src/plugins/valgrind/callgrind/callgrindparsedata.cpp +++ b/src/plugins/valgrind/callgrind/callgrindparsedata.cpp @@ -44,13 +44,15 @@ namespace Callgrind { class ParseData::Private { Q_DECLARE_TR_FUNCTIONS(Valgrind::Callgrind::ParseData) public: - Private(ParseData *q) - : m_q(q) + Private(ParseData *q, const QString &fileName) + : m_fileName(fileName) + , m_q(q) { } ~Private(); + QString m_fileName; QStringList m_events; QStringList m_positions; QVector m_totalCosts; @@ -138,10 +140,9 @@ void ParseData::Private::cycleDetection() //BEGIN ParseData -ParseData::ParseData() -: d(new Private(this)) +ParseData::ParseData(const QString &fileName) + : d(new Private(this, fileName)) { - } ParseData::~ParseData() @@ -149,6 +150,11 @@ ParseData::~ParseData() delete d; } +QString ParseData::fileName() const +{ + return d->m_fileName; +} + QString ParseData::prettyStringForEvent(const QString &event) { /* diff --git a/src/plugins/valgrind/callgrind/callgrindparsedata.h b/src/plugins/valgrind/callgrind/callgrindparsedata.h index 4c1ba186f97..e67957f4cd4 100644 --- a/src/plugins/valgrind/callgrind/callgrindparsedata.h +++ b/src/plugins/valgrind/callgrind/callgrindparsedata.h @@ -44,9 +44,11 @@ class Function; class ParseData { public: - explicit ParseData(); + explicit ParseData(const QString &fileName); ~ParseData(); + QString fileName() const; + static QString prettyStringForEvent(const QString &event); /// List of events reported in the data file. QStringList events() const; diff --git a/src/plugins/valgrind/callgrind/callgrindparser.cpp b/src/plugins/valgrind/callgrind/callgrindparser.cpp index d5c5fcff7d3..7d9123933e7 100644 --- a/src/plugins/valgrind/callgrind/callgrindparser.cpp +++ b/src/plugins/valgrind/callgrind/callgrindparser.cpp @@ -32,6 +32,7 @@ #include +#include #include #include #include @@ -202,7 +203,10 @@ void Parser::Private::parse(QIODevice *device) delete data; data = nullptr; - data = new ParseData; + QString file; + if (auto fileDevice = qobject_cast(device)) + file = fileDevice->fileName(); + data = new ParseData(file); parseHeader(device); while (!device->atEnd()) { QByteArray line = device->readLine(); diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 8d0e77feebc..b6c67b746ac 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -186,6 +186,8 @@ public: QPointer m_calleesView; QPointer m_visualization; + QString m_lastFileName; + // Navigation QAction *m_goBack = nullptr; QAction *m_goNext = nullptr; @@ -207,6 +209,7 @@ public: QAction *m_startAction = nullptr; QAction *m_stopAction = nullptr; QAction *m_loadExternalLogFile = nullptr; + QAction *m_startKCachegrind = nullptr; QAction *m_dumpAction = nullptr; QAction *m_resetAction = nullptr; QAction *m_pauseAction = nullptr; @@ -355,6 +358,8 @@ CallgrindTool::CallgrindTool() updateCostFormat(); + ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings(); + // // Control Widget // @@ -365,6 +370,16 @@ CallgrindTool::CallgrindTool() action->setToolTip(tr("Load External Log File")); connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile); + action = m_startKCachegrind = new QAction(this); + action->setEnabled(false); + const Utils::Icon kCachegrindIcon({{":/valgrind/images/kcachegrind.png", + Theme::IconsBaseColor}}); + action->setIcon(kCachegrindIcon.icon()); + action->setToolTip(tr("Open results in KCachegrind.")); + connect(action, &QAction::triggered, this, [this, settings] { + QProcess::startDetached(settings->kcachegrindExecutable(), { m_lastFileName }); + }); + // dump action m_dumpAction = action = new QAction(this); action->setDisabled(true); @@ -423,6 +438,7 @@ CallgrindTool::CallgrindTool() m_perspective.addToolBarAction(m_startAction); m_perspective.addToolBarAction(m_stopAction); m_perspective.addToolBarAction(m_loadExternalLogFile); + m_perspective.addToolBarAction(m_startKCachegrind); m_perspective.addToolBarAction(m_dumpAction); m_perspective.addToolBarAction(m_resetAction); m_perspective.addToolBarAction(m_pauseAction); @@ -466,8 +482,6 @@ CallgrindTool::CallgrindTool() m_perspective.addToolBarWidget(button); } - ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings(); - // Cycle detection //action = new QAction("Cycle Detection", this); ///FIXME: icon action = m_cycleDetection = new QAction("O", this); ///FIXME: icon @@ -713,6 +727,7 @@ void CallgrindTool::setParseData(ParseData *data) delete data; data = nullptr; } + m_lastFileName = data ? data->fileName() : QString(); m_dataModel.setParseData(data); m_calleesModel.setParseData(data); m_callersModel.setParseData(data); @@ -919,14 +934,21 @@ void CallgrindTool::takeParserData(ParseData *data) { showParserResults(data); - if (!data) + if (!data) { + m_lastFileName.clear(); + m_startKCachegrind->setEnabled(false); return; + } // clear first clearTextMarks(); doClear(true); setParseData(data); + const QString kcachegrindExecutable = ValgrindPlugin::globalSettings()->kcachegrindExecutable(); + const bool kcachegrindExists = !Utils::Environment::systemEnvironment().searchInPath( + kcachegrindExecutable).isEmpty(); + m_startKCachegrind->setEnabled(kcachegrindExists && !m_lastFileName.isEmpty()); createTextMarks(); } diff --git a/src/plugins/valgrind/images/kcachegrind.png b/src/plugins/valgrind/images/kcachegrind.png new file mode 100644 index 00000000000..67792f2224e Binary files /dev/null and b/src/plugins/valgrind/images/kcachegrind.png differ diff --git a/src/plugins/valgrind/images/kcachegrind@2x.png b/src/plugins/valgrind/images/kcachegrind@2x.png new file mode 100644 index 00000000000..666e07d596c Binary files /dev/null and b/src/plugins/valgrind/images/kcachegrind@2x.png differ diff --git a/src/plugins/valgrind/valgrind.qrc b/src/plugins/valgrind/valgrind.qrc index 33b69a88bca..0ea209df8ca 100644 --- a/src/plugins/valgrind/valgrind.qrc +++ b/src/plugins/valgrind/valgrind.qrc @@ -2,5 +2,7 @@ images/suppressoverlay.png images/suppressoverlay@2x.png + images/kcachegrind.png + images/kcachegrind@2x.png diff --git a/src/plugins/valgrind/valgrindconfigwidget.cpp b/src/plugins/valgrind/valgrindconfigwidget.cpp index f11907b85d3..3781dfeba95 100644 --- a/src/plugins/valgrind/valgrindconfigwidget.cpp +++ b/src/plugins/valgrind/valgrindconfigwidget.cpp @@ -73,6 +73,10 @@ ValgrindConfigWidget::ValgrindConfigWidget(ValgrindBaseSettings *settings, bool // // Callgrind // + m_ui->kcachegrindExeChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); + m_ui->kcachegrindExeChooser->setPromptDialogTitle(tr("KCachegrind Command")); + connect(m_ui->kcachegrindExeChooser, &Utils::PathChooser::rawPathChanged, + m_settings, &ValgrindBaseSettings::setKCachegrindExecutable); connect(m_ui->enableCacheSim, &QCheckBox::toggled, m_settings, &ValgrindBaseSettings::setEnableCacheSim); connect(m_settings, &ValgrindBaseSettings::enableCacheSimChanged, @@ -168,6 +172,7 @@ void ValgrindConfigWidget::updateUi() { m_ui->valgrindExeChooser->setPath(m_settings->valgrindExecutable()); m_ui->smcDetectionComboBox->setCurrentIndex(m_settings->selfModifyingCodeDetection()); + m_ui->kcachegrindExeChooser->setPath(m_settings->kcachegrindExecutable()); m_ui->enableCacheSim->setChecked(m_settings->enableCacheSim()); m_ui->enableBranchSim->setChecked(m_settings->enableBranchSim()); m_ui->collectSystime->setChecked(m_settings->collectSystime()); diff --git a/src/plugins/valgrind/valgrindconfigwidget.ui b/src/plugins/valgrind/valgrindconfigwidget.ui index d056a47fc02..f0fae915ef9 100644 --- a/src/plugins/valgrind/valgrindconfigwidget.ui +++ b/src/plugins/valgrind/valgrindconfigwidget.ui @@ -6,8 +6,8 @@ 0 0 - 655 - 364 + 708 + 397 @@ -106,7 +106,7 @@ Profiling Options - + Limits the amount of results the profiler gives you. A lower limit will likely increase performance. @@ -119,7 +119,7 @@ - + % @@ -135,7 +135,7 @@ - + Show additional information for events in tooltips @@ -203,14 +203,14 @@ With cache simulation, further event counters are enabled: - + Visualization: Minimum event cost: - + @@ -226,6 +226,23 @@ With cache simulation, further event counters are enabled: + + + + KCachegrind executable: + + + + + + + + 1 + 0 + + + + diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index 897acaf121f..0b854bc651e 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -49,6 +49,7 @@ const char visibleErrorKindsC[] = "Analyzer.Valgrind.VisibleErrorKinds"; const char lastSuppressionDirectoryC[] = "Analyzer.Valgrind.LastSuppressionDirectory"; const char lastSuppressionHistoryC[] = "Analyzer.Valgrind.LastSuppressionHistory"; +const char kcachegrindExeC[] = "Analyzer.Valgrind.KCachegrindExecutable"; const char callgrindEnableCacheSimC[] = "Analyzer.Valgrind.Callgrind.EnableCacheSim"; const char callgrindEnableBranchSimC[] = "Analyzer.Valgrind.Callgrind.EnableBranchSim"; const char callgrindCollectSystimeC[] = "Analyzer.Valgrind.Callgrind.CollectSystime"; @@ -105,6 +106,7 @@ void ValgrindBaseSettings::fromMap(const QVariantMap &map) } // Callgrind + setIfPresent(map, kcachegrindExeC, &m_kcachegrindExecutable); setIfPresent(map, callgrindEnableCacheSimC, &m_enableCacheSim); setIfPresent(map, callgrindEnableBranchSimC, &m_enableBranchSim); setIfPresent(map, callgrindCollectSystimeC, &m_collectSystime); @@ -135,6 +137,7 @@ void ValgrindBaseSettings::toMap(QVariantMap &map) const map.insert(visibleErrorKindsC, errorKinds); // Callgrind + map.insert(kcachegrindExeC, m_kcachegrindExecutable); map.insert(callgrindEnableCacheSimC, m_enableCacheSim); map.insert(callgrindEnableBranchSimC, m_enableBranchSim); map.insert(callgrindCollectSystimeC, m_collectSystime); @@ -216,6 +219,16 @@ void ValgrindBaseSettings::setVisibleErrorKinds(const QList &visibleErrorKi } } +QString ValgrindBaseSettings::kcachegrindExecutable() const +{ + return m_kcachegrindExecutable; +} + +void ValgrindBaseSettings::setKCachegrindExecutable(const QString &exec) +{ + m_kcachegrindExecutable = exec; +} + void ValgrindBaseSettings::setEnableCacheSim(bool enable) { if (m_enableCacheSim == enable) @@ -394,6 +407,7 @@ void ValgrindGlobalSettings::readSettings() defaults.insert(lastSuppressionHistoryC, QStringList()); // Callgrind + defaults.insert(kcachegrindExeC, "kcachegrind"); defaults.insert(callgrindEnableCacheSimC, false); defaults.insert(callgrindEnableBranchSimC, false); defaults.insert(callgrindCollectSystimeC, false); diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index 4eb7f0580d3..0437b50733b 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -129,6 +129,8 @@ protected: * Base callgrind settings */ public: + QString kcachegrindExecutable() const; + bool enableCacheSim() const { return m_enableCacheSim; } bool enableBranchSim() const { return m_enableBranchSim; } bool collectSystime() const { return m_collectSystime; } @@ -141,6 +143,7 @@ public: /// \return Minimum cost ratio, range [0.0..100.0] double visualisationMinimumInclusiveCostRatio() const { return m_visualisationMinimumInclusiveCostRatio; } + void setKCachegrindExecutable(const QString &exec); void setEnableCacheSim(bool enable); void setEnableBranchSim(bool enable); void setCollectSystime(bool collect); @@ -163,6 +166,7 @@ signals: void visualisationMinimumInclusiveCostRatioChanged(double); private: + QString m_kcachegrindExecutable; bool m_enableCacheSim; bool m_collectSystime; bool m_collectBusEvents; diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 809b9524c37..cc05ffbe7fb 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3188,6 +3188,81 @@ width="100%" height="100%" /> + + + + + + + + + + +