diff --git a/core/job.cpp b/core/job.cpp index 9540db3..bb60e61 100644 --- a/core/job.cpp +++ b/core/job.cpp @@ -1,312 +1,308 @@ /* This file is part of KDevelop Copyright 2011 Mathieu Lornac Copyright 2011 Damien Coppel Copyright 2011 Lionel Duc Copyright 2011 Sebastien Rannou Copyright 2011 Lucas Sarie Copyright 2006-2008 Hamish Rodda Copyright 2002 Harald Fernengel Copyright 2016-2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "job.h" #include "debug.h" #include "globalsettings.h" #include "plugin.h" #include "tool.h" #include "utils.h" #include "private/common_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Valgrind { inline QString valgrindErrorsPrefix() { return QStringLiteral("valgrind: "); } Job::Job(const Tool* tool, KDevelop::ILaunchConfiguration* launchConfig) : KDevelop::OutputExecuteJob(KDevelop::ICore::self()->runController()) , m_tool(tool) , m_configGroup(launchConfig->config()) , m_tcpServerPort(0) { Q_ASSERT(tool); Q_ASSERT(launchConfig); setProperties(KDevelop::OutputExecuteJob::JobProperty::DisplayStdout); setProperties(KDevelop::OutputExecuteJob::JobProperty::DisplayStderr); setProperties(KDevelop::OutputExecuteJob::JobProperty::PostProcessOutput); setCapabilities(KJob::Killable); setStandardToolView(KDevelop::IOutputView::TestView); setBehaviours(KDevelop::IOutputView::AutoScroll); auto pluginController = KDevelop::ICore::self()->pluginController(); auto iface = pluginController->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"))->extension(); Q_ASSERT(iface); QString envProfile = iface->environmentProfileName(launchConfig); if (envProfile.isEmpty()) { envProfile = KDevelop::EnvironmentProfileList(KSharedConfig::openConfig()).defaultProfileName(); } setEnvironmentProfile(envProfile); QString errorString; m_analyzedExecutable = iface->executable(launchConfig, errorString).toLocalFile(); if (!errorString.isEmpty()) { setError(-1); setErrorText(errorString); } m_analyzedExecutableArguments = iface->arguments(launchConfig, errorString); if (!errorString.isEmpty()) { setError(-1); setErrorText(errorString); } QUrl workDir = iface->workingDirectory(launchConfig); if (workDir.isEmpty() || !workDir.isValid()) { workDir = QUrl::fromLocalFile(QFileInfo(m_analyzedExecutable).absolutePath()); } setWorkingDirectory(workDir); connect(this, &Job::finished, Plugin::self(), &Plugin::jobFinished); auto tcpServer = new QTcpServer(this); tcpServer->listen(QHostAddress::LocalHost); m_tcpServerPort = tcpServer->serverPort(); connect(tcpServer, &QTcpServer::newConnection, this, [this, tcpServer]() { auto tcpSocket = tcpServer->nextPendingConnection(); connect(tcpSocket, &QTcpSocket::readyRead, this, [this, tcpSocket]() { QStringList lines; while (!tcpSocket->atEnd()) { lines += tcpSocket->readLine().trimmed(); } processValgrindOutput(lines); }); }); connect(this, &Job::finished, this, [this]() { emit hideProgress(this); }); KDevelop::ICore::self()->uiController()->registerStatus(this); } -Job::~Job() -{ -} - const Tool* Job::tool() const { return m_tool; } QString Job::statusName() const { return i18n("%1 Analysis (%2)", m_tool->name(), QFileInfo(m_analyzedExecutable).fileName()); } void Job::addLoggingArgs(QStringList& args) const { args += QStringLiteral("--log-socket=127.0.0.1:%1").arg(m_tcpServerPort); } QStringList Job::buildCommandLine() const { CommonConfig config; config.setConfigGroup(m_configGroup); config.load(); QStringList args; args += QStringLiteral("--tool=%1").arg(m_tool->valgrindToolName()); addLoggingArgs(args); args += config.cmdArgs(); addToolArgs(args); return args; } void Job::start() { *this << KDevelop::Path(GlobalSettings::valgrindExecutablePath()).toLocalFile(); *this << buildCommandLine(); *this << m_analyzedExecutable; *this << m_analyzedExecutableArguments; qCDebug(KDEV_VALGRIND) << "executing:" << commandLine().join(' '); Plugin::self()->jobReadyToStart(this); emit showProgress(this, 0, 0, 0); KDevelop::OutputExecuteJob::start(); } void Job::postProcessStderr(const QStringList& lines) { for (const QString& line : lines) { if (line.startsWith(valgrindErrorsPrefix())) { m_valgrindOutput += line; } } KDevelop::OutputExecuteJob::postProcessStderr(lines); } void Job::processValgrindOutput(const QStringList& lines) { m_valgrindOutput += lines; if (GlobalSettings::showValgrindOutput()) { KDevelop::OutputExecuteJob::postProcessStderr(lines); } } void Job::childProcessExited(int exitCode, QProcess::ExitStatus exitStatus) { qCDebug(KDEV_VALGRIND) << "Process Finished, exitCode" << exitCode << "process exit status" << exitStatus; bool ok = !exitCode; if (ok) { ok = processEnded(); } Plugin::self()->jobReadyToFinish(this, ok); KDevelop::OutputExecuteJob::childProcessExited(exitCode, exitStatus); } void Job::childProcessError(QProcess::ProcessError processError) { QString errorMessage; switch (processError) { case QProcess::FailedToStart: errorMessage = i18n("Failed to start valgrind from \"%1\".", commandLine().at(0)); break; case QProcess::Crashed: // if the process was killed by the user, the crash was expected // don't notify the user if (status() != KDevelop::OutputExecuteJob::JobStatus::JobCanceled) { errorMessage = i18n("Valgrind crashed."); } break; case QProcess::Timedout: errorMessage = i18n("Valgrind process timed out."); break; case QProcess::WriteError: errorMessage = i18n("Write to Valgrind process failed."); break; case QProcess::ReadError: errorMessage = i18n("Read from Valgrind process failed."); break; case QProcess::UnknownError: // Here, check if Valgrind failed (because of bad parameters or whatever). // Because Valgrind always returns 1 on failure, and the profiled application's return // on success, we cannot know for sure which process returned != 0. // // The only way to guess that it is Valgrind which failed is to check stderr and look for // "valgrind: " at the beginning of the first line, even though it can still be the // profiled process that writes it on stderr. It is, however, unlikely enough to be // reliable in most cases. if (!m_valgrindOutput.isEmpty() && m_valgrindOutput.at(0).startsWith(valgrindErrorsPrefix())) { errorMessage = m_valgrindOutput.join('\n').remove(valgrindErrorsPrefix()); errorMessage += QStringLiteral("\n\n"); errorMessage += i18n("Please review your Valgrind launch configuration."); } else { errorMessage = i18n("Unknown Valgrind process error."); } break; } if (!errorMessage.isEmpty()) { KMessageBox::error(activeMainWindow(), errorMessage, i18n("Valgrind Error")); } KDevelop::OutputExecuteJob::childProcessError(processError); } bool Job::processEnded() { return true; } int Job::executeProcess(const QString& executable, const QStringList& args, QByteArray& processOutput) { QString commandLine = executable + QLatin1Char(' ') + args.join(QLatin1Char(' ')); if (GlobalSettings::showValgrindOutput()) { KDevelop::OutputExecuteJob::postProcessStdout({i18n("Executing command: ") + commandLine }); } QProcess process; process.start(executable, args); if (!process.waitForFinished()){ return -1; } processOutput = process.readAllStandardOutput(); QString errOutput(process.readAllStandardError()); if (GlobalSettings::showValgrindOutput()) { KDevelop::OutputExecuteJob::postProcessStdout(QString(processOutput).split('\n')); } KDevelop::OutputExecuteJob::postProcessStderr(errOutput.split('\n')); if (process.exitCode()) { QString message = i18n("Failed to execute the command:"); message += "\n\n"; message += commandLine; message += "\n\n"; message += i18n("Please review your Valgrind launch configuration."); KMessageBox::error(activeMainWindow(), message, i18n("Valgrind Error")); } return process.exitCode(); } } diff --git a/core/job.h b/core/job.h index 1b8b5bd..e84d90a 100644 --- a/core/job.h +++ b/core/job.h @@ -1,94 +1,93 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda Copyright 2002 Harald Fernengel Copyright 2011 Mathieu Lornac Copyright 2011 Damien Coppel Copyright 2011 Lionel Duc Copyright 2016-2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include class QWidget; namespace KDevelop { class ILaunchConfiguration; } namespace Valgrind { class Tool; class Job : public KDevelop::OutputExecuteJob, public KDevelop::IStatus { Q_OBJECT Q_INTERFACES(KDevelop::IStatus) public: Job(const Tool* tool, KDevelop::ILaunchConfiguration* launchConfig); - - ~Job() override; + ~Job() override = default; void start() override; using KDevelop::OutputExecuteJob::doKill; const Tool* tool() const; virtual QWidget* createView() = 0; QString statusName() const override; Q_SIGNALS: void clearMessage(KDevelop::IStatus*) override; void hideProgress(KDevelop::IStatus*) override; void showErrorMessage(const QString& message, int timeout = 0) override; void showMessage(KDevelop::IStatus*, const QString& message, int timeout = 0) override; void showProgress(KDevelop::IStatus*, int minimum, int maximum, int value) override; protected: void postProcessStderr(const QStringList& lines) override; virtual void processValgrindOutput(const QStringList& lines); void childProcessExited(int exitCode, QProcess::ExitStatus exitStatus) override; void childProcessError(QProcess::ProcessError processError) override; virtual bool processEnded(); virtual void addLoggingArgs(QStringList& args) const; virtual void addToolArgs(QStringList& args) const = 0; int executeProcess(const QString& executable, const QStringList& args, QByteArray& processOutput); QStringList buildCommandLine() const; const Tool* m_tool; KConfigGroup m_configGroup; QString m_analyzedExecutable; QStringList m_analyzedExecutableArguments; QStringList m_valgrindOutput; quint16 m_tcpServerPort; }; } diff --git a/tools/cachegrind/cachegrind_job.cpp b/tools/cachegrind/cachegrind_job.cpp index 7c7cc26..91fa470 100644 --- a/tools/cachegrind/cachegrind_job.cpp +++ b/tools/cachegrind/cachegrind_job.cpp @@ -1,93 +1,89 @@ /* This file is part of KDevelop Copyright 2011 Mathieu Lornac Copyright 2011 Damien Coppel Copyright 2011 Lionel Duc Copyright 2011 Sebastien Rannou Copyright 2016-2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cachegrind_job.h" #include "cachegrind_config.h" #include "cachegrind_model.h" #include "cachegrind_parser.h" #include "cachegrind_tool.h" #include "cachegrind_view.h" #include "plugin.h" #include #include #include #include #include #include namespace Valgrind { CachegrindJob::CachegrindJob(KDevelop::ILaunchConfiguration* launchConfig) : Job(CachegrindTool::self(), launchConfig) , m_model(new CachegrindFunctionsModel) , m_outputFile(new QTemporaryFile(this)) { m_outputFile->open(); } -CachegrindJob::~CachegrindJob() -{ -} - bool CachegrindJob::processEnded() { CachegrindConfig config; config.setConfigGroup(m_configGroup); config.load(); QStringList cgArgs; cgArgs += KShell::splitArgs(config.cgAnnotateParameters()); cgArgs += m_outputFile->fileName(); QByteArray cgOutput; if (executeProcess(config.cgAnnotateExecutablePath(), cgArgs, cgOutput) != 0) { return false; } cachegrindParse(cgOutput, m_model); return true; } void CachegrindJob::addToolArgs(QStringList& args) const { CachegrindConfig config; config.setConfigGroup(m_configGroup); config.load(); args += config.cmdArgs(); args += QStringLiteral("--cachegrind-out-file=%1").arg(m_outputFile->fileName()); } QWidget* CachegrindJob::createView() { return new CachegrindView(m_model); } } diff --git a/tools/cachegrind/cachegrind_job.h b/tools/cachegrind/cachegrind_job.h index 26b70f5..bf5cb0e 100644 --- a/tools/cachegrind/cachegrind_job.h +++ b/tools/cachegrind/cachegrind_job.h @@ -1,53 +1,53 @@ /* This file is part of KDevelop Copyright 2011 Mathieu Lornac Copyright 2011 Damien Coppel Copyright 2011 Lionel Duc Copyright 2011 Sebastien Rannou Copyright 2016-2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "job.h" class QTemporaryFile; namespace Valgrind { class CachegrindFunctionsModel; class CachegrindJob : public Job { Q_OBJECT public: explicit CachegrindJob(KDevelop::ILaunchConfiguration* launchConfig); - ~CachegrindJob() override; + ~CachegrindJob() override = default; QWidget* createView() override; protected: bool processEnded() override; void addToolArgs(QStringList& args) const override; CachegrindFunctionsModel* m_model; QTemporaryFile* m_outputFile; }; } diff --git a/tools/callgrind/callgrind_job.cpp b/tools/callgrind/callgrind_job.cpp index 5f8cefc..9a68be2 100644 --- a/tools/callgrind/callgrind_job.cpp +++ b/tools/callgrind/callgrind_job.cpp @@ -1,95 +1,91 @@ /* This file is part of KDevelop Copyright 2011 Mathieu Lornac Copyright 2011 Damien Coppel Copyright 2011 Lionel Duc Copyright 2011 Sebastien Rannou Copyright 2011 Lucas Sarie Copyright 2016-2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "callgrind_job.h" #include "callgrind_config.h" #include "callgrind_model.h" #include "callgrind_parser.h" #include "callgrind_tool.h" #include "callgrind_view.h" #include "plugin.h" #include #include #include #include #include #include namespace Valgrind { CallgrindJob::CallgrindJob(KDevelop::ILaunchConfiguration* launchConfig) : Job(CallgrindTool::self(), launchConfig) , m_model(new CallgrindFunctionsModel) , m_outputFile(new QTemporaryFile(this)) { m_outputFile->open(); } -CallgrindJob::~CallgrindJob() -{ -} - bool CallgrindJob::processEnded() { CallgrindConfig config; config.setConfigGroup(m_configGroup); config.load(); QStringList caArgs; caArgs += KShell::splitArgs(config.callgrindAnnotateArgs()); caArgs += QStringLiteral("--tree=calling"); caArgs += QStringLiteral("--threshold=100"); caArgs += m_outputFile->fileName(); QByteArray caOutput; if (executeProcess(config.callgrindAnnotateExecutablePath(), caArgs, caOutput)) { return false; } callgrindParse(caOutput, m_model); return true; } void CallgrindJob::addToolArgs(QStringList& args) const { CallgrindConfig config; config.setConfigGroup(m_configGroup); config.load(); args += config.cmdArgs(); args += QStringLiteral("--callgrind-out-file=%1").arg(m_outputFile->fileName()); } QWidget* CallgrindJob::createView() { return new CallgrindView(m_configGroup, m_outputFile, m_model); } } diff --git a/tools/callgrind/callgrind_job.h b/tools/callgrind/callgrind_job.h index 2105fd2..aaaa768 100644 --- a/tools/callgrind/callgrind_job.h +++ b/tools/callgrind/callgrind_job.h @@ -1,54 +1,54 @@ /* This file is part of KDevelop Copyright 2011 Mathieu Lornac Copyright 2011 Damien Coppel Copyright 2011 Lionel Duc Copyright 2011 Sebastien Rannou Copyright 2011 Lucas Sarie Copyright 2016-2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "job.h" class QTemporaryFile; namespace Valgrind { class CallgrindFunctionsModel; class CallgrindJob : public Job { Q_OBJECT public: explicit CallgrindJob(KDevelop::ILaunchConfiguration* launchConfig); - ~CallgrindJob() override; + ~CallgrindJob() override = default; QWidget* createView() override; protected: bool processEnded() override; void addToolArgs(QStringList& args) const override; CallgrindFunctionsModel* m_model; QTemporaryFile* m_outputFile; }; } diff --git a/tools/callgrind/callgrind_model.cpp b/tools/callgrind/callgrind_model.cpp index 77051f6..edf01fb 100644 --- a/tools/callgrind/callgrind_model.cpp +++ b/tools/callgrind/callgrind_model.cpp @@ -1,520 +1,512 @@ /* This file is part of KDevelop * Copyright 2011 Mathieu Lornac * Copyright 2011 Damien Coppel * Copyright 2011 Lionel Duc * Copyright 2011 Lucas Sarie * Copyright 2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "callgrind_model.h" #include "debug.h" #include "utils.h" #include #include #include namespace Valgrind { void addValues(const QStringList& stringValues, QVector& intValues) { for (int i = 0; i < stringValues.size(); ++i) { intValues[i] += stringValues[i].toInt(); } } CallgrindCallInformation::CallgrindCallInformation(const QStringList& stringValues) { Q_ASSERT(!stringValues.isEmpty()); m_eventValues.resize(stringValues.size()); addValues(stringValues, m_eventValues); } int CallgrindCallInformation::eventValue(int type) { Q_ASSERT(type < m_eventValues.size()); return m_eventValues[type]; } CallgrindFunction::CallgrindFunction(int eventsCount) { m_eventValues.resize(eventsCount); } int CallgrindFunction::callCount() { int count = 0; for (auto info : qAsConst(callersInformation)) { count += info->callCount; } return count; } int CallgrindFunction::eventValue(int type, bool inclusive) { Q_ASSERT(type < m_eventValues.size()); int value = m_eventValues[type]; if (!inclusive) { return value; } if (callersInformation.isEmpty()) { // The function is NOT CALLED by others, therefore we calc // the event inclusive value as sum of self value and all callees. for (auto info : qAsConst(calleesInformation)) { value += info->eventValue(type); } return value; } // The function is CALLED by others, therefore we calc // the event inclusive value as sum of all callers. value = 0; for (auto info : qAsConst(callersInformation)) { value += info->eventValue(type); } return value; } void CallgrindFunction::addEventValues(const QStringList& stringValues) { Q_ASSERT(stringValues.size() == m_eventValues.size()); addValues(stringValues, m_eventValues); } CallgrindFunctionsModel::CallgrindFunctionsModel() : m_currentEventType(0) , m_percentageValues(false) { } CallgrindFunctionsModel::~CallgrindFunctionsModel() { qDeleteAll(m_functions); qDeleteAll(m_information); } const QStringList & CallgrindFunctionsModel::eventTypes() { return m_eventTypes; } void CallgrindFunctionsModel::setEventTypes(const QStringList& eventTypes) { Q_ASSERT(!eventTypes.isEmpty()); m_eventTypes = eventTypes; m_eventTotals.resize(m_eventTypes.size()); } void CallgrindFunctionsModel::setEventTotals(const QStringList& stringValues) { Q_ASSERT(stringValues.size() == m_eventTotals.size()); addValues(stringValues, m_eventTotals); } int CallgrindFunctionsModel::currentEventType() { return m_currentEventType; } void CallgrindFunctionsModel::setCurrentEventType(int type) { Q_ASSERT(type < m_eventTotals.size()); m_currentEventType = type; emitDataChanged(this); } void CallgrindFunctionsModel::setPercentageValues(bool value) { m_percentageValues = value; emitDataChanged(this); } CallgrindFunction* CallgrindFunctionsModel::addFunction( const QString& name, const QString& sourceFile, const QString& binaryFile) { Q_ASSERT(!name.isEmpty()); Q_ASSERT(!m_eventTypes.isEmpty()); CallgrindFunction* function = nullptr; for (auto currentFunction : qAsConst(m_functions)) { if (currentFunction->name == name && (currentFunction->binaryFile.isEmpty() || binaryFile.isEmpty() || currentFunction->binaryFile == binaryFile)) { function = currentFunction; break; } } if (function) { if (function->binaryFile.isEmpty()) { function->binaryFile = binaryFile; } function->sourceFiles += sourceFile; function->sourceFiles.removeDuplicates(); function->sourceFiles.sort(); } else { function = new CallgrindFunction(m_eventTypes.size()); function->name = name; function->binaryFile = binaryFile; function->sourceFiles += sourceFile; m_functions.append(function); } return function; } void CallgrindFunctionsModel::addCall( CallgrindFunction* caller, CallgrindFunction* callee, int callCount, const QStringList& eventValues) { Q_ASSERT(caller); Q_ASSERT(callee); auto info = new CallgrindCallInformation(eventValues); m_information.append(info); info->caller = caller; info->callee = callee; info->callCount = callCount; caller->calleesInformation.append(info); callee->callersInformation.append(info); } QModelIndex CallgrindFunctionsModel::index(int row, int column, const QModelIndex&) const { if (hasIndex(row, column)) { return createIndex(row, column, m_functions.at(row)); } return QModelIndex(); } int CallgrindFunctionsModel::rowCount(const QModelIndex&) const { return m_functions.size(); } int CallgrindFunctionsModel::columnCount(const QModelIndex&) const { return 4; } QString CallgrindFunctionsModel::displayValue(int eventIntValue, int eventType) const { if (m_percentageValues) { return Valgrind::displayValue(eventIntValue * 100.0 / m_eventTotals[eventType]); } return Valgrind::displayValue(eventIntValue); } QVariant CallgrindFunctionsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } auto function = static_cast(index.internalPointer()); if (role == Qt::TextAlignmentRole && index.column() < 3) { return rightAlign; } if (index.column() < 2) { int intValue = function->eventValue(m_currentEventType, (index.column() == 0)); if (role == SortRole) { return intValue; } if (role == Qt::DisplayRole) { return displayValue(intValue, m_currentEventType); } } if (index.column() == 2 && (role == Qt::DisplayRole || role == SortRole)) { return function->callCount(); } if (index.column() == 3 && (role == Qt::DisplayRole || role == SortRole)) { return function->name; } return QVariant(); } QVariant CallgrindFunctionsModel::headerData(int section, Qt::Orientation, int role) const { if (role == Qt::DisplayRole) { switch (section) { case 0: return i18n("Incl."); case 1: return i18n("Self"); case 2: return i18n("Called"); case 3: return i18n("Function"); } } return QVariant(); } CallgrindFunctionEventsModel::CallgrindFunctionEventsModel(CallgrindFunctionsModel* baseModel) : QAbstractTableModel(baseModel) , m_baseModel(baseModel) , m_function(nullptr) { Q_ASSERT(m_baseModel); connect(m_baseModel, &CallgrindFunctionsModel::dataChanged, this, [this](const QModelIndex&, const QModelIndex&, const QVector&) { emitDataChanged(this); }); } -CallgrindFunctionEventsModel::~CallgrindFunctionEventsModel() -{ -} - void CallgrindFunctionEventsModel::setFunction(CallgrindFunction* function) { m_function = function; emitDataChanged(this); } QModelIndex CallgrindFunctionEventsModel::index(int row, int column, const QModelIndex&) const { if (hasIndex(row, column)) { return createIndex(row, column); } return QModelIndex(); } int CallgrindFunctionEventsModel::rowCount(const QModelIndex&) const { return m_baseModel->eventTypes().size(); } int CallgrindFunctionEventsModel::columnCount(const QModelIndex&) const { return 4; } QVariant CallgrindFunctionEventsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } int row = index.row(); int column = index.column(); if (column == 0 && role == Qt::DisplayRole) { return eventFullName(m_baseModel->eventTypes().at(row)); } if (column == 3 && role == Qt::DisplayRole) { return m_baseModel->eventTypes().at(row); } if (m_function && (column == 1 || column == 2)) { if (role == Qt::TextAlignmentRole) { return rightAlign; } int intValue = m_function->eventValue(row, (column == 1)); if (role == SortRole) { return intValue; } if (role == Qt::DisplayRole) { return m_baseModel->displayValue(intValue, row); } } return QVariant(); } QVariant CallgrindFunctionEventsModel::headerData(int section, Qt::Orientation, int role) const { if (role == Qt::DisplayRole) { switch (section) { case 0: return i18n("Event"); case 1: return i18n("Incl."); case 2: return i18n("Self"); case 3: return i18n("Short"); } } return QVariant(); } CallgrindFunctionCallersCalleesModel::CallgrindFunctionCallersCalleesModel(CallgrindFunctionsModel* baseModel, bool isCallerModel) : QAbstractTableModel(baseModel) , m_baseModel(baseModel) , m_isCallerModel(isCallerModel) , m_function(nullptr) { Q_ASSERT(m_baseModel); connect(m_baseModel, &CallgrindFunctionsModel::dataChanged, this, [this](const QModelIndex&, const QModelIndex&, const QVector&) { emitDataChanged(this); emit headerDataChanged(Qt::Horizontal, 0, 1); }); } -CallgrindFunctionCallersCalleesModel::~CallgrindFunctionCallersCalleesModel() -{ -} - void CallgrindFunctionCallersCalleesModel::setFunction(CallgrindFunction* function) { beginResetModel(); m_function = function; endResetModel(); } QModelIndex CallgrindFunctionCallersCalleesModel::index(int row, int column, const QModelIndex&) const { if (hasIndex(row, column)) { return createIndex(row, column); } return QModelIndex(); } int CallgrindFunctionCallersCalleesModel::rowCount(const QModelIndex&) const { if (!m_function) { return 0; } if (m_isCallerModel) { return m_function->callersInformation.size(); } return m_function->calleesInformation.size(); } int CallgrindFunctionCallersCalleesModel::columnCount(const QModelIndex&) const { return 4; } QVariant CallgrindFunctionCallersCalleesModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } int row = index.row(); int column = index.column(); if (role == Qt::TextAlignmentRole && column < 3) { return rightAlign; } auto info = m_isCallerModel ? m_function->callersInformation.at(row) : m_function->calleesInformation.at(row); int eventType = m_baseModel->currentEventType(); int intValue = info->eventValue(eventType); int callCount = info->callCount; if (column == 0) { if (role == SortRole) { return intValue; } if (role == Qt::DisplayRole) { return m_baseModel->displayValue(intValue, eventType); } } if (column == 1) { int perCallValue = intValue / callCount; if (role == SortRole) { return perCallValue; } if (role == Qt::DisplayRole) { return displayValue(perCallValue); } } if (column == 2) { if (role == SortRole || role == Qt::DisplayRole) { return callCount; } } if (column == 3) { if (role == SortRole || role == Qt::DisplayRole) { if (m_isCallerModel) { return info->caller->name; } return info->callee->name; } } return QVariant(); } QVariant CallgrindFunctionCallersCalleesModel::headerData(int section, Qt::Orientation, int role) const { if (role == Qt::DisplayRole) { const QString& eventType = m_baseModel->eventTypes().at(m_baseModel->currentEventType()); switch (section) { case 0: return eventType; case 1: return i18n("%1 per call", eventType); case 2: return i18n("Count"); case 3: if (m_isCallerModel) { return i18n("Caller"); } return i18n("Callee"); } } return QVariant(); } } diff --git a/tools/callgrind/callgrind_model.h b/tools/callgrind/callgrind_model.h index 06ad0a1..4a93ec8 100644 --- a/tools/callgrind/callgrind_model.h +++ b/tools/callgrind/callgrind_model.h @@ -1,173 +1,173 @@ /* This file is part of KDevelop * Copyright 2011 Mathieu Lornac * Copyright 2011 Damien Coppel * Copyright 2011 Lionel Duc * Copyright 2011 Lucas Sarie * Copyright 2017 Anton Anikin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include class QItemSelectionModel; namespace Valgrind { class CallgrindFunction; class CallgrindCallInformation { public: explicit CallgrindCallInformation(const QStringList& stringValues); CallgrindFunction* caller = nullptr; CallgrindFunction* callee = nullptr; int callCount = 0; int eventValue(int type); private: QVector m_eventValues; }; class CallgrindFunction { public: explicit CallgrindFunction(int eventsCount); QString name; QString binaryFile; QStringList sourceFiles; int callCount(); int eventValue(int type, bool inclusive); void addEventValues(const QStringList& stringValues); QList callersInformation; QList calleesInformation; private: QVector m_eventValues; }; class CallgrindFunctionsModel : public QAbstractTableModel { Q_OBJECT public: CallgrindFunctionsModel(); ~CallgrindFunctionsModel() override; const QStringList& eventTypes(); void setEventTypes(const QStringList& eventTypes); int currentEventType(); void setCurrentEventType(int type); void setEventTotals(const QStringList& stringValues); void setPercentageValues(bool value); CallgrindFunction* addFunction( const QString& name, const QString& sourceFile, const QString& binaryFile); void addCall( CallgrindFunction* caller, CallgrindFunction* callee, int callCount, const QStringList& eventValues); QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant eventData(int type, int intValue, int role) const; QString displayValue(int eventIntValue, int eventType) const; private: QStringList m_eventTypes; int m_currentEventType; QVector m_eventTotals; bool m_percentageValues; QList m_functions; QList m_information; }; class CallgrindFunctionEventsModel : public QAbstractTableModel { Q_OBJECT public: explicit CallgrindFunctionEventsModel(CallgrindFunctionsModel* baseModel); - ~CallgrindFunctionEventsModel() override; + ~CallgrindFunctionEventsModel() override = default; void setFunction(CallgrindFunction* function); QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; private: CallgrindFunctionsModel* m_baseModel; CallgrindFunction* m_function; }; class CallgrindFunctionCallersCalleesModel : public QAbstractTableModel { Q_OBJECT public: CallgrindFunctionCallersCalleesModel(CallgrindFunctionsModel* baseModel, bool isCallerModel); - ~CallgrindFunctionCallersCalleesModel() override; + ~CallgrindFunctionCallersCalleesModel() override = default; void setFunction(CallgrindFunction* function); QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; private: CallgrindFunctionsModel* m_baseModel; bool m_isCallerModel; CallgrindFunction* m_function; }; }