diff --git a/src/plugins/valgrind/CMakeLists.txt b/src/plugins/valgrind/CMakeLists.txt index 9896c93a3a8..192304e5795 100644 --- a/src/plugins/valgrind/CMakeLists.txt +++ b/src/plugins/valgrind/CMakeLists.txt @@ -4,7 +4,6 @@ add_qtc_plugin(Valgrind SOURCES callgrind/callgrindabstractmodel.h callgrind/callgrindcallmodel.cpp callgrind/callgrindcallmodel.h - callgrind/callgrindcontroller.cpp callgrind/callgrindcontroller.h callgrind/callgrindcostitem.cpp callgrind/callgrindcostitem.h callgrind/callgrindcycledetection.cpp callgrind/callgrindcycledetection.h callgrind/callgrinddatamodel.cpp callgrind/callgrinddatamodel.h diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp deleted file mode 100644 index 3d9420f969a..00000000000 --- a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "callgrindcontroller.h" - -#include -#include - -#include - -#define CALLGRIND_CONTROL_DEBUG 0 - -using namespace ProjectExplorer; -using namespace Utils; - -namespace Valgrind { -namespace Callgrind { - -const char CALLGRIND_CONTROL_BINARY[] = "callgrind_control"; - -CallgrindController::CallgrindController() = default; - -CallgrindController::~CallgrindController() -{ - cleanupTempFile(); -} - -static QString toOptionString(CallgrindController::Option option) -{ - /* callgrind_control help from v3.9.0 - - Options: - -h --help Show this help text - --version Show version - -s --stat Show statistics - -b --back Show stack/back trace - -e [,...] Show event counters for ,... (default: all) - --dump[=] Request a dump optionally using as description - -z --zero Zero all event counters - -k --kill Kill - --instr= Switch instrumentation state on/off - */ - - switch (option) { - case CallgrindController::Dump: - return QLatin1String("--dump"); - case CallgrindController::ResetEventCounters: - return QLatin1String("--zero"); - case CallgrindController::Pause: - return QLatin1String("--instr=off"); - case CallgrindController::UnPause: - return QLatin1String("--instr=on"); - default: - return QString(); // never reached - } -} - -void CallgrindController::run(Option option) -{ - if (m_controllerProcess) { - emit statusMessage(tr("Previous command has not yet finished.")); - return; - } - - // save back current running operation - m_lastOption = option; - - m_controllerProcess.reset(new QtcProcess); - - switch (option) { - case CallgrindController::Dump: - emit statusMessage(tr("Dumping profile data...")); - break; - case CallgrindController::ResetEventCounters: - emit statusMessage(tr("Resetting event counters...")); - break; - case CallgrindController::Pause: - emit statusMessage(tr("Pausing instrumentation...")); - break; - case CallgrindController::UnPause: - emit statusMessage(tr("Unpausing instrumentation...")); - break; - default: - break; - } - -#if CALLGRIND_CONTROL_DEBUG - m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels); -#endif - connect(m_controllerProcess.get(), &QtcProcess::finished, - this, &CallgrindController::controllerProcessDone); - - const FilePath control = - FilePath(CALLGRIND_CONTROL_BINARY).onDevice(m_valgrindRunnable.command.executable()); - m_controllerProcess->setCommand({control, {toOptionString(option), QString::number(m_pid)}}); - m_controllerProcess->setWorkingDirectory(m_valgrindRunnable.workingDirectory); - m_controllerProcess->setEnvironment(m_valgrindRunnable.environment); - m_controllerProcess->start(); -} - -void CallgrindController::setValgrindPid(qint64 pid) -{ - m_pid = pid; -} - -void CallgrindController::controllerProcessDone() -{ - const QString error = m_controllerProcess->errorString(); - const ProcessResult result = m_controllerProcess->result(); - - m_controllerProcess.release()->deleteLater(); - - if (result != ProcessResult::FinishedWithSuccess) { - emit statusMessage(tr("An error occurred while trying to run %1: %2").arg(CALLGRIND_CONTROL_BINARY).arg(error)); - qWarning() << "Controller exited abnormally:" << error; - return; - } - - // this call went fine, we might run another task after this - switch (m_lastOption) { - case ResetEventCounters: - // lets dump the new reset profiling info - run(Dump); - return; - case Pause: - break; - case Dump: - emit statusMessage(tr("Callgrind dumped profiling info")); - break; - case UnPause: - emit statusMessage(tr("Callgrind unpaused.")); - break; - default: - break; - } - - emit finished(m_lastOption); - m_lastOption = Unknown; -} - -void CallgrindController::getLocalDataFile() -{ - cleanupTempFile(); - { - TemporaryFile dataFile("callgrind.out"); - dataFile.open(); - m_hostOutputFile = FilePath::fromString(dataFile.fileName()); - } - - const auto afterCopy = [this](bool res) { - QTC_CHECK(res); - emit localParseDataAvailable(m_hostOutputFile); - }; - m_valgrindOutputFile.asyncCopyFile(afterCopy, m_hostOutputFile); -} - -void CallgrindController::cleanupTempFile() -{ - if (!m_hostOutputFile.isEmpty() && m_hostOutputFile.exists()) - m_hostOutputFile.removeFile(); - - m_hostOutputFile.clear(); -} - -void CallgrindController::setValgrindRunnable(const Runnable &runnable) -{ - m_valgrindRunnable = runnable; -} - -} // namespace Callgrind -} // namespace Valgrind diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.h b/src/plugins/valgrind/callgrind/callgrindcontroller.h deleted file mode 100644 index d5c273dc951..00000000000 --- a/src/plugins/valgrind/callgrind/callgrindcontroller.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -namespace Utils { class QtcProcess; } - -namespace Valgrind { -namespace Callgrind { - -class CallgrindController : public QObject -{ - Q_OBJECT -public: - enum Option { - Unknown, - Dump, - ResetEventCounters, - Pause, - UnPause - }; - Q_ENUM(Option) - - CallgrindController(); - ~CallgrindController() override; - - void run(Option option); - - /** - * Make data file available locally, triggers @c localParseDataAvailable. - * - * If the valgrind process was run remotely, this transparently - * downloads the data file first and returns a local path. - */ - void getLocalDataFile(); - void setValgrindPid(qint64 pid); - void setValgrindRunnable(const ProjectExplorer::Runnable &runnable); - void setValgrindOutputFile(const Utils::FilePath &output) { m_valgrindOutputFile = output; } - -signals: - void finished(Valgrind::Callgrind::CallgrindController::Option option); - void localParseDataAvailable(const Utils::FilePath &file); - void statusMessage(const QString &msg); - -private: - void cleanupTempFile(); - void controllerProcessDone(); - - std::unique_ptr m_controllerProcess; - ProjectExplorer::Runnable m_valgrindRunnable; - qint64 m_pid = 0; - - Option m_lastOption = Unknown; - - // remote callgrind support - Utils::FilePath m_valgrindOutputFile; // On the device that runs valgrind - Utils::FilePath m_hostOutputFile; // On the device that runs creator -}; - -} // namespace Callgrind -} // namespace Valgrind diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 333d713e15b..c7660468d54 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -27,7 +27,6 @@ #include "valgrindsettings.h" -#include #include #include @@ -36,6 +35,11 @@ #include #include #include +#include + +#include + +#define CALLGRIND_CONTROL_DEBUG 0 using namespace ProjectExplorer; using namespace Valgrind::Callgrind; @@ -44,6 +48,8 @@ using namespace Utils; namespace Valgrind { namespace Internal { +const char CALLGRIND_CONTROL_BINARY[] = "callgrind_control"; + void setupCallgrindRunner(CallgrindToolRunner *); CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl) @@ -56,29 +62,27 @@ CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl) connect(&m_parser, &Callgrind::Parser::parserDataReady, this, &CallgrindToolRunner::slotFinished); - connect(&m_controller, &CallgrindController::finished, - this, &CallgrindToolRunner::controllerFinished); - connect(&m_controller, &CallgrindController::localParseDataAvailable, - this, &CallgrindToolRunner::handleLocalParseData); - connect(&m_controller, &CallgrindController::statusMessage, - this, &CallgrindToolRunner::showStatusMessage); - connect(&m_runner, &ValgrindRunner::valgrindStarted, - &m_controller, &CallgrindController::setValgrindPid); + this, &CallgrindToolRunner::setValgrindPid); connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] { triggerParse(); }); - m_controller.setValgrindRunnable(runControl->runnable()); + setValgrindRunnable(runControl->runnable()); static int fileCount = 100; m_valgrindOutputFile = runControl->workingDirectory() / QString("callgrind.out.f%1").arg(++fileCount); - m_controller.setValgrindOutputFile(m_valgrindOutputFile); + setValgrindOutputFile(m_valgrindOutputFile); setupCallgrindRunner(this); } +CallgrindToolRunner::~CallgrindToolRunner() +{ + cleanupTempFile(); +} + QStringList CallgrindToolRunner::toolArguments() const { QStringList arguments = {"--tool=callgrind"}; @@ -123,7 +127,7 @@ void CallgrindToolRunner::start() void CallgrindToolRunner::dump() { - m_controller.run(CallgrindController::Dump); + run(Dump); } void CallgrindToolRunner::setPaused(bool paused) @@ -150,17 +154,17 @@ void CallgrindToolRunner::setToggleCollectFunction(const QString &toggleCollectF void CallgrindToolRunner::reset() { - m_controller.run(Callgrind::CallgrindController::ResetEventCounters); + run(ResetEventCounters); } void CallgrindToolRunner::pause() { - m_controller.run(Callgrind::CallgrindController::Pause); + run(Pause); } void CallgrindToolRunner::unpause() { - m_controller.run(Callgrind::CallgrindController::UnPause); + run(UnPause); } Callgrind::ParseData *CallgrindToolRunner::takeParserData() @@ -180,32 +184,166 @@ void CallgrindToolRunner::showStatusMessage(const QString &message) void CallgrindToolRunner::triggerParse() { - m_controller.getLocalDataFile(); + getLocalDataFile(); } -void CallgrindToolRunner::handleLocalParseData(const FilePath &outputFile) + +static QString toOptionString(CallgrindToolRunner::Option option) { - QTC_ASSERT(outputFile.exists(), return); - showStatusMessage(tr("Parsing Profile Data...")); - m_parser.parse(outputFile); + /* callgrind_control help from v3.9.0 + + Options: + -h --help Show this help text + --version Show version + -s --stat Show statistics + -b --back Show stack/back trace + -e [,...] Show event counters for ,... (default: all) + --dump[=] Request a dump optionally using as description + -z --zero Zero all event counters + -k --kill Kill + --instr= Switch instrumentation state on/off + */ + + switch (option) { + case CallgrindToolRunner::Dump: + return QLatin1String("--dump"); + case CallgrindToolRunner::ResetEventCounters: + return QLatin1String("--zero"); + case CallgrindToolRunner::Pause: + return QLatin1String("--instr=off"); + case CallgrindToolRunner::UnPause: + return QLatin1String("--instr=on"); + default: + return QString(); // never reached + } } -void CallgrindToolRunner::controllerFinished(CallgrindController::Option option) +void CallgrindToolRunner::run(Option option) { - switch (option) + if (m_controllerProcess) { + showStatusMessage(tr("Previous command has not yet finished.")); + return; + } + + // save back current running operation + m_lastOption = option; + + m_controllerProcess.reset(new QtcProcess); + + switch (option) { + case CallgrindToolRunner::Dump: + showStatusMessage(tr("Dumping profile data...")); + break; + case CallgrindToolRunner::ResetEventCounters: + showStatusMessage(tr("Resetting event counters...")); + break; + case CallgrindToolRunner::Pause: + showStatusMessage(tr("Pausing instrumentation...")); + break; + case CallgrindToolRunner::UnPause: + showStatusMessage(tr("Unpausing instrumentation...")); + break; + default: + break; + } + +#if CALLGRIND_CONTROL_DEBUG + m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels); +#endif + connect(m_controllerProcess.get(), &QtcProcess::finished, + this, &CallgrindToolRunner::controllerProcessDone); + + const FilePath control = + FilePath(CALLGRIND_CONTROL_BINARY).onDevice(m_valgrindRunnable.command.executable()); + m_controllerProcess->setCommand({control, {toOptionString(option), QString::number(m_pid)}}); + m_controllerProcess->setWorkingDirectory(m_valgrindRunnable.workingDirectory); + m_controllerProcess->setEnvironment(m_valgrindRunnable.environment); + m_controllerProcess->start(); +} + +void CallgrindToolRunner::setValgrindPid(qint64 pid) +{ + m_pid = pid; +} + +void CallgrindToolRunner::controllerProcessDone() +{ + const QString error = m_controllerProcess->errorString(); + const ProcessResult result = m_controllerProcess->result(); + + m_controllerProcess.release()->deleteLater(); + + if (result != ProcessResult::FinishedWithSuccess) { + showStatusMessage(tr("An error occurred while trying to run %1: %2").arg(CALLGRIND_CONTROL_BINARY).arg(error)); + qWarning() << "Controller exited abnormally:" << error; + return; + } + + // this call went fine, we might run another task after this + switch (m_lastOption) { + case ResetEventCounters: + // lets dump the new reset profiling info + run(Dump); + return; + case Pause: + break; + case Dump: + showStatusMessage(tr("Callgrind dumped profiling info")); + break; + case UnPause: + showStatusMessage(tr("Callgrind unpaused.")); + break; + default: + break; + } + + switch (m_lastOption) { - case CallgrindController::Pause: + case Pause: m_paused = true; break; - case CallgrindController::UnPause: + case UnPause: m_paused = false; break; - case CallgrindController::Dump: + case Dump: triggerParse(); break; default: break; // do nothing } + + m_lastOption = Unknown; +} + +void CallgrindToolRunner::getLocalDataFile() +{ + cleanupTempFile(); + { + TemporaryFile dataFile("callgrind.out"); + dataFile.open(); + m_hostOutputFile = FilePath::fromString(dataFile.fileName()); + } + + const auto afterCopy = [this](bool res) { + QTC_CHECK(res); + QTC_ASSERT(m_hostOutputFile.exists(), return); + showStatusMessage(tr("Parsing Profile Data...")); + m_parser.parse(m_hostOutputFile); + }; + m_valgrindOutputFile.asyncCopyFile(afterCopy, m_hostOutputFile); +} + +void CallgrindToolRunner::cleanupTempFile() +{ + if (!m_hostOutputFile.isEmpty() && m_hostOutputFile.exists()) + m_hostOutputFile.removeFile(); + + m_hostOutputFile.clear(); +} + +void CallgrindToolRunner::setValgrindRunnable(const Runnable &runnable) +{ + m_valgrindRunnable = runnable; } } // Internal diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index dfee79d95b2..d6357417cab 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -26,11 +26,11 @@ #pragma once #include "valgrindengine.h" -#include "valgrindrunner.h" #include "callgrind/callgrindparsedata.h" #include "callgrind/callgrindparser.h" -#include "callgrind/callgrindcontroller.h" + +#include namespace Valgrind { namespace Internal { @@ -41,6 +41,7 @@ class CallgrindToolRunner : public ValgrindToolRunner public: explicit CallgrindToolRunner(ProjectExplorer::RunControl *runControl); + ~CallgrindToolRunner() override; void start() override; @@ -58,6 +59,16 @@ public: void setToggleCollectFunction(const QString &toggleCollectFunction); + enum Option { + Unknown, + Dump, + ResetEventCounters, + Pause, + UnPause + }; + + Q_ENUM(Option) + protected: QStringList toolArguments() const override; QString progressTitle() const override; @@ -70,12 +81,36 @@ private: void showStatusMessage(const QString &message); void triggerParse(); - void handleLocalParseData(const Utils::FilePath &filePath); - void controllerFinished(Callgrind::CallgrindController::Option option); + void controllerFinished(Option option); + + void run(Option option); + + /** + * Make data file available locally, triggers @c localParseDataAvailable. + * + * If the valgrind process was run remotely, this transparently + * downloads the data file first and returns a local path. + */ + void getLocalDataFile(); + void setValgrindPid(qint64 pid); + void setValgrindRunnable(const ProjectExplorer::Runnable &runnable); + void setValgrindOutputFile(const Utils::FilePath &output) { m_valgrindOutputFile = output; } + + void cleanupTempFile(); + void controllerProcessDone(); bool m_markAsPaused = false; - Utils::FilePath m_valgrindOutputFile; - Callgrind::CallgrindController m_controller; + + std::unique_ptr m_controllerProcess; + ProjectExplorer::Runnable m_valgrindRunnable; + qint64 m_pid = 0; + + Option m_lastOption = Unknown; + + // remote callgrind support + Utils::FilePath m_valgrindOutputFile; // On the device that runs valgrind + Utils::FilePath m_hostOutputFile; // On the device that runs creator + Callgrind::Parser m_parser; bool m_paused = false; diff --git a/src/plugins/valgrind/valgrind.qbs b/src/plugins/valgrind/valgrind.qbs index bee21fdf738..8830ba2b8b3 100644 --- a/src/plugins/valgrind/valgrind.qbs +++ b/src/plugins/valgrind/valgrind.qbs @@ -44,7 +44,6 @@ QtcPlugin { files: [ "callgrindabstractmodel.h", "callgrindcallmodel.cpp", "callgrindcallmodel.h", - "callgrindcontroller.cpp", "callgrindcontroller.h", "callgrindcostitem.cpp", "callgrindcostitem.h", "callgrindcycledetection.cpp", "callgrindcycledetection.h", "callgrinddatamodel.cpp", "callgrinddatamodel.h", diff --git a/tests/auto/valgrind/callgrind/CMakeLists.txt b/tests/auto/valgrind/callgrind/CMakeLists.txt index 72df53a9d40..76859938aed 100644 --- a/tests/auto/valgrind/callgrind/CMakeLists.txt +++ b/tests/auto/valgrind/callgrind/CMakeLists.txt @@ -11,7 +11,6 @@ extend_qtc_test(tst_callgrindparsertests SOURCES_PREFIX "${PROJECT_SOURCE_DIR}/src/plugins/valgrind/" SOURCES callgrind/callgrindcallmodel.h callgrind/callgrindcallmodel.cpp - callgrind/callgrindcontroller.h callgrind/callgrindcontroller.cpp callgrind/callgrindcostitem.h callgrind/callgrindcostitem.cpp callgrind/callgrindcycledetection.h callgrind/callgrindcycledetection.cpp callgrind/callgrinddatamodel.h callgrind/callgrinddatamodel.cpp