forked from qt-creator/qt-creator
Add callgrind support to valgrind library.
Merge-request: 284 Reviewed-by: hjk <qtc-committer@nokia.com>
This commit is contained in:
52
src/libs/valgrind/callgrind/callgrindabstractmodel.cpp
Normal file
52
src/libs/valgrind/callgrind/callgrindabstractmodel.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrinddatamodel.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
AbstractModel::AbstractModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AbstractModel::~AbstractModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
75
src/libs/valgrind/callgrind/callgrindabstractmodel.h
Normal file
75
src/libs/valgrind/callgrind/callgrindabstractmodel.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRINDABSTRACTMODEL_H
|
||||
#define LIBVALGRIND_CALLGRINDABSTRACTMODEL_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class ParseData;
|
||||
|
||||
class VALGRINDSHARED_EXPORT AbstractModel {
|
||||
public:
|
||||
AbstractModel();
|
||||
virtual ~AbstractModel();
|
||||
|
||||
virtual void setParseData(const ParseData *data) = 0;
|
||||
virtual const ParseData *parseData() const = 0;
|
||||
|
||||
/// Only one cost event column will be shown, this decides which one it is.
|
||||
/// By default it is the first event in the @c ParseData, i.e. 0.
|
||||
virtual int costEvent() const = 0;
|
||||
|
||||
//BEGIN SLOTS
|
||||
virtual void setCostEvent(int event) = 0;
|
||||
//END SLOTS
|
||||
|
||||
//BEGIN SIGNALS
|
||||
virtual void parseDataChanged(AbstractModel *model) = 0;
|
||||
//END SIGNALS
|
||||
|
||||
enum Roles {
|
||||
ParentCostRole = Qt::UserRole,
|
||||
RelativeTotalCostRole,
|
||||
RelativeParentCostRole,
|
||||
NextCustomRole
|
||||
};
|
||||
};
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRINDABSTRACTMODEL_H
|
||||
234
src/libs/valgrind/callgrind/callgrindcallmodel.cpp
Normal file
234
src/libs/valgrind/callgrind/callgrindcallmodel.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Instrumentation Tools
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "callgrindcallmodel.h"
|
||||
|
||||
#include "callgrindfunctioncall.h"
|
||||
#include "callgrindfunction.h"
|
||||
#include "callgrindparsedata.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN CallModel::Private
|
||||
|
||||
class CallModel::Private {
|
||||
public:
|
||||
Private();
|
||||
|
||||
const ParseData *m_data;
|
||||
QVector<const FunctionCall *> m_calls;
|
||||
int m_event;
|
||||
const Function *m_function;
|
||||
};
|
||||
|
||||
CallModel::Private::Private()
|
||||
: m_data(0)
|
||||
, m_event(0)
|
||||
, m_function(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//END CallModel::Private
|
||||
|
||||
//BEGIN CallModel
|
||||
CallModel::CallModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CallModel::~CallModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CallModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
d->m_function = 0;
|
||||
d->m_calls.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CallModel::setCalls(const QVector<const FunctionCall *> &calls, const Function *function)
|
||||
{
|
||||
beginResetModel();
|
||||
d->m_function = function;
|
||||
d->m_calls = calls;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVector<const FunctionCall *> CallModel::calls() const
|
||||
{
|
||||
return d->m_calls;
|
||||
}
|
||||
|
||||
const Function *CallModel::function() const
|
||||
{
|
||||
return d->m_function;
|
||||
}
|
||||
|
||||
void CallModel::setCostEvent(int event)
|
||||
{
|
||||
d->m_event = event;
|
||||
}
|
||||
|
||||
int CallModel::costEvent() const
|
||||
{
|
||||
return d->m_event;
|
||||
}
|
||||
|
||||
void CallModel::setParseData(const ParseData *data)
|
||||
{
|
||||
if (d->m_data == data)
|
||||
return;
|
||||
|
||||
if (!data)
|
||||
clear();
|
||||
|
||||
d->m_data = data;
|
||||
emit parseDataChanged(this);
|
||||
}
|
||||
|
||||
const ParseData *CallModel::parseData() const
|
||||
{
|
||||
return d->m_data;
|
||||
}
|
||||
|
||||
int CallModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);
|
||||
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return d->m_calls.count();
|
||||
}
|
||||
|
||||
int CallModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);
|
||||
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return ColumnCount;
|
||||
}
|
||||
|
||||
QModelIndex CallModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
QTC_ASSERT(!child.isValid() || child.model() == this, return QModelIndex());
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CallModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid() || parent.model() == this, return QModelIndex());
|
||||
|
||||
if (row == 0 && rowCount(parent) == 0) // happens with empty models
|
||||
return QModelIndex();
|
||||
|
||||
QTC_ASSERT(row >= 0 && row < rowCount(parent), return QModelIndex());
|
||||
|
||||
return createIndex(row, column);
|
||||
}
|
||||
|
||||
QVariant CallModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QTC_ASSERT(index.isValid() && index.model() == this, return QVariant());
|
||||
QTC_ASSERT(index.column() >= 0 && index.column() < columnCount(index.parent()), return QVariant());
|
||||
QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(index.parent()), return QVariant());
|
||||
|
||||
const FunctionCall *call = d->m_calls.at(index.row());
|
||||
const quint64 callCost = call->cost(d->m_event);
|
||||
const quint64 parentCost = d->m_function->inclusiveCost(d->m_event);
|
||||
if (role == ParentCostRole) {
|
||||
return parentCost;
|
||||
}
|
||||
else if (role == FunctionCallRole
|
||||
|| role == RelativeParentCostRole || role == RelativeTotalCostRole) {
|
||||
if (role == FunctionCallRole)
|
||||
return QVariant::fromValue(call);
|
||||
|
||||
if (role == RelativeTotalCostRole) {
|
||||
const quint64 totalCost = d->m_data->totalCost(d->m_event);
|
||||
return (float) callCost / totalCost;
|
||||
}
|
||||
|
||||
if (role == RelativeParentCostRole)
|
||||
return (float) callCost / parentCost;
|
||||
}
|
||||
else if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
|
||||
if (index.column() == CalleeColumn)
|
||||
return call->callee()->name();
|
||||
else if (index.column() == CallerColumn)
|
||||
return call->caller()->name();
|
||||
else if (index.column() == CostColumn && role != Qt::ToolTipRole)
|
||||
return callCost;
|
||||
else if (index.column() == CallsColumn && role != Qt::ToolTipRole)
|
||||
return call->calls();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant CallModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Vertical || role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
QTC_ASSERT(section >= 0 && section < columnCount(), return QVariant());
|
||||
|
||||
if (section == CalleeColumn)
|
||||
return tr("Callee");
|
||||
else if (section == CallerColumn)
|
||||
return tr("Caller");
|
||||
else if (section == CostColumn)
|
||||
return tr("Cost");
|
||||
else if (section == CallsColumn)
|
||||
return tr("Calls");
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
109
src/libs/valgrind/callgrind/callgrindcallmodel.h
Normal file
109
src/libs/valgrind/callgrind/callgrindcallmodel.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Instrumentation Tools
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#ifndef VALGRIND_CALLGRIND_CALLGRINDCALLMODEL_H
|
||||
#define VALGRIND_CALLGRIND_CALLGRINDCALLMODEL_H
|
||||
|
||||
#include <QtCore/QAbstractItemModel>
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
#include "callgrindabstractmodel.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class FunctionCall;
|
||||
class Function;
|
||||
|
||||
/**
|
||||
* Model to display list of function calls.
|
||||
*/
|
||||
class VALGRINDSHARED_EXPORT CallModel : public QAbstractItemModel, public AbstractModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CallModel(QObject *parent = 0);
|
||||
virtual ~CallModel();
|
||||
|
||||
void clear();
|
||||
|
||||
/// Only one cost event column will be shown, this decides which one it is.
|
||||
/// By default it is the first event in the @c ParseData, i.e. 0.
|
||||
virtual int costEvent() const;
|
||||
|
||||
virtual void setParseData(const ParseData *data);
|
||||
virtual const ParseData *parseData() const;
|
||||
|
||||
void setCalls(const QVector<const FunctionCall *> &calls, const Function *function);
|
||||
QVector<const FunctionCall *> calls() const;
|
||||
const Function *function() const;
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex parent(const QModelIndex &child) const;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
enum Columns {
|
||||
CallerColumn,
|
||||
CalleeColumn,
|
||||
CallsColumn,
|
||||
CostColumn,
|
||||
ColumnCount
|
||||
};
|
||||
|
||||
enum Roles {
|
||||
FunctionCallRole = AbstractModel::NextCustomRole
|
||||
};
|
||||
|
||||
public slots:
|
||||
/// Only one cost event column will be shown, this decides which one it is.
|
||||
/// By default it is the first event in the @c ParseData, i.e. 0.
|
||||
void setCostEvent(int event);
|
||||
|
||||
signals:
|
||||
void parseDataChanged(AbstractModel *model);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
|
||||
#endif // VALGRIND_CALLGRIND_CALLGRINDCALLMODEL_H
|
||||
268
src/libs/valgrind/callgrind/callgrindcontroller.cpp
Normal file
268
src/libs/valgrind/callgrind/callgrindcontroller.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Analyzer Tools
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindcontroller.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
#include <valgrind/valgrindprocess.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/ssh/sftpchannel.h>
|
||||
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#define CALLGRIND_CONTROL_DEBUG 0
|
||||
|
||||
const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control");
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
CallgrindController::CallgrindController(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_process(0)
|
||||
, m_valgrindProc(0)
|
||||
, m_lastOption(Unknown)
|
||||
{
|
||||
}
|
||||
|
||||
CallgrindController::~CallgrindController()
|
||||
{
|
||||
cleanupTempFile();
|
||||
}
|
||||
|
||||
QString toOptionString(CallgrindController::Option option)
|
||||
{
|
||||
/* Callgrind help from v3.6.0
|
||||
|
||||
Options:
|
||||
-h --help Show this help text
|
||||
--version Show version
|
||||
-l --long Show more information
|
||||
-s --stat Show statistics
|
||||
-b --back Show stack/back trace
|
||||
-e [<A>,...] Show event counters for <A>,... (default: all)
|
||||
--dump[=<s>] Request a dump optionally using <s> as description
|
||||
-z --zero Zero all event counters
|
||||
-k --kill Kill
|
||||
--instr=<on|off> Switch instrumentation state on/off
|
||||
-w=<dir> Specify the startup directory of an active Callgrind run
|
||||
*/
|
||||
|
||||
switch(option) {
|
||||
case CallgrindController::Dump:
|
||||
return "--dump";
|
||||
case CallgrindController::ResetEventCounters:
|
||||
return "--zero";
|
||||
case CallgrindController::Pause:
|
||||
return "--instr=off";
|
||||
case CallgrindController::UnPause:
|
||||
return "--instr=on";
|
||||
default:
|
||||
return ""; // never reached
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallgrindController::run(Option option)
|
||||
{
|
||||
if (m_process) {
|
||||
emit statusMessage(tr("Previous command has not yet finished."));
|
||||
return;
|
||||
}
|
||||
QTC_ASSERT(m_valgrindProc, return)
|
||||
|
||||
if (RemoteValgrindProcess *remote = qobject_cast<RemoteValgrindProcess *>(m_valgrindProc))
|
||||
m_process = new RemoteValgrindProcess(remote->connection(), this);
|
||||
else
|
||||
m_process = new LocalValgrindProcess(this);
|
||||
|
||||
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||
SLOT(processFinished(int,QProcess::ExitStatus)));
|
||||
connect(m_process, SIGNAL(error(QProcess::ProcessError)),
|
||||
SLOT(processError(QProcess::ProcessError)));
|
||||
|
||||
// save back current running operation
|
||||
m_lastOption = option;
|
||||
|
||||
const QString optionString = toOptionString(option);
|
||||
|
||||
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_process->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
#endif
|
||||
m_process->run(CALLGRIND_CONTROL_BINARY,
|
||||
QStringList() << optionString << QString::number(m_valgrindProc->pid()),
|
||||
QString(), QString());
|
||||
}
|
||||
|
||||
void CallgrindController::processError(QProcess::ProcessError processError)
|
||||
{
|
||||
QTC_ASSERT(m_process, return)
|
||||
const QString error = m_process->errorString();
|
||||
emit statusMessage(QString("An error occured while trying to run %1: %2").arg(CALLGRIND_CONTROL_BINARY).arg(error));
|
||||
|
||||
m_process->deleteLater();
|
||||
m_process = 0;
|
||||
}
|
||||
|
||||
void CallgrindController::processFinished(int rc, QProcess::ExitStatus status)
|
||||
{
|
||||
QTC_ASSERT(m_process, return);
|
||||
const QString error = m_process->errorString();
|
||||
|
||||
delete m_process;
|
||||
m_process = 0;
|
||||
|
||||
if (rc != 0 || status != QProcess::NormalExit) {
|
||||
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 resetted profiling info
|
||||
run(Dump);
|
||||
return;
|
||||
case Pause:
|
||||
// on pause, reset profiling info (for now)
|
||||
run(ResetEventCounters);
|
||||
return;
|
||||
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::setValgrindProcess(ValgrindProcess *proc)
|
||||
{
|
||||
m_valgrindProc = proc;
|
||||
}
|
||||
|
||||
void CallgrindController::getLocalDataFile()
|
||||
{
|
||||
QTC_ASSERT(m_valgrindProc, return);
|
||||
|
||||
// we look for callgrind.out.PID, but there may be updated ones called ~.PID.NUM
|
||||
QString baseFileName = QString("callgrind.out.%1").arg(m_valgrindProc->pid());
|
||||
const QString workingDir = m_valgrindProc->workingDirectory();
|
||||
// first, set the to-be-parsed file to callgrind.out.PID
|
||||
QString fileName = workingDir.isEmpty() ? baseFileName : (workingDir + QDir::separator() + baseFileName);
|
||||
|
||||
if (RemoteValgrindProcess *remote = qobject_cast<RemoteValgrindProcess *>(m_valgrindProc)) {
|
||||
///TODO: error handling
|
||||
emit statusMessage(tr("Downloading remote profile data..."));
|
||||
m_ssh = remote->connection();
|
||||
// if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
|
||||
QString cmd = QString("ls -t %1* | head -n 1").arg(fileName);
|
||||
m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8());
|
||||
connect(m_findRemoteFile.data(), SIGNAL(outputAvailable(QByteArray)),
|
||||
this, SLOT(foundRemoteFile(QByteArray)));
|
||||
m_findRemoteFile->start();
|
||||
} else {
|
||||
QDir dir(workingDir, QString("%1.*").arg(baseFileName), QDir::Time);
|
||||
QStringList outputFiles = dir.entryList();
|
||||
// if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
|
||||
if (!outputFiles.isEmpty())
|
||||
fileName = workingDir + QDir::separator() + dir.entryList().first();
|
||||
|
||||
emit localParseDataAvailable(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
void CallgrindController::foundRemoteFile(const QByteArray &file)
|
||||
{
|
||||
m_remoteFile = file.trimmed();
|
||||
|
||||
m_sftp = m_ssh->createSftpChannel();
|
||||
connect(m_sftp.data(), SIGNAL(finished(Utils::SftpJobId,QString)),
|
||||
this, SLOT(sftpJobFinished(Utils::SftpJobId,QString)));
|
||||
connect(m_sftp.data(), SIGNAL(initialized()), this, SLOT(sftpInitialized()));
|
||||
m_sftp->initialize();
|
||||
}
|
||||
|
||||
void CallgrindController::sftpInitialized()
|
||||
{
|
||||
cleanupTempFile();
|
||||
QTemporaryFile dataFile(QDir::tempPath() + QDir::separator() + "callgrind.out.");
|
||||
QTC_ASSERT(dataFile.open(), return);
|
||||
m_tempDataFile = dataFile.fileName();
|
||||
dataFile.setAutoRemove(false);
|
||||
dataFile.close();
|
||||
|
||||
m_downloadJob = m_sftp->downloadFile(m_remoteFile, m_tempDataFile, Utils::SftpOverwriteExisting);
|
||||
}
|
||||
|
||||
void CallgrindController::sftpJobFinished(Utils::SftpJobId job, const QString &error)
|
||||
{
|
||||
QTC_ASSERT(job == m_downloadJob, return);
|
||||
|
||||
m_sftp->closeChannel();
|
||||
|
||||
if (error.isEmpty())
|
||||
emit localParseDataAvailable(m_tempDataFile);
|
||||
}
|
||||
|
||||
void CallgrindController::cleanupTempFile()
|
||||
{
|
||||
if (!m_tempDataFile.isEmpty() && QFile::exists(m_tempDataFile))
|
||||
QFile::remove(m_tempDataFile);
|
||||
|
||||
m_tempDataFile = QString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
115
src/libs/valgrind/callgrind/callgrindcontroller.h
Normal file
115
src/libs/valgrind/callgrind/callgrindcontroller.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Analyzer Tools
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CALLGRINDCONTROLLER_H
|
||||
#define CALLGRINDCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <qprocess.h>
|
||||
#include <qmetatype.h>
|
||||
|
||||
#include <utils/ssh/sshconnection.h>
|
||||
#include <utils/ssh/sshremoteprocess.h>
|
||||
#include <utils/ssh/sftpchannel.h>
|
||||
|
||||
#include <valgrind/valgrind_global.h>
|
||||
|
||||
namespace Valgrind {
|
||||
|
||||
class ValgrindProcess;
|
||||
|
||||
namespace Callgrind {
|
||||
|
||||
class VALGRINDSHARED_EXPORT CallgrindController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Option);
|
||||
|
||||
public:
|
||||
enum Option {
|
||||
Unknown,
|
||||
Dump,
|
||||
ResetEventCounters,
|
||||
Pause, UnPause
|
||||
};
|
||||
|
||||
explicit CallgrindController(QObject *parent = 0);
|
||||
virtual ~CallgrindController();
|
||||
|
||||
void run(Valgrind::Callgrind::CallgrindController::Option option);
|
||||
|
||||
void setValgrindProcess(ValgrindProcess *process);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
Q_SIGNALS:
|
||||
void finished(Valgrind::Callgrind::CallgrindController::Option option);
|
||||
|
||||
void localParseDataAvailable(const QString &file);
|
||||
|
||||
void statusMessage(const QString &msg);
|
||||
|
||||
private Q_SLOTS:
|
||||
void processError(QProcess::ProcessError);
|
||||
void processFinished(int, QProcess::ExitStatus);
|
||||
|
||||
void foundRemoteFile(const QByteArray &file);
|
||||
void sftpInitialized();
|
||||
void sftpJobFinished(Utils::SftpJobId job, const QString &error);
|
||||
|
||||
private:
|
||||
void cleanupTempFile();
|
||||
|
||||
// callgrind_controll process
|
||||
Valgrind::ValgrindProcess *m_process;
|
||||
// valgrind process
|
||||
Valgrind::ValgrindProcess *m_valgrindProc;
|
||||
|
||||
Option m_lastOption;
|
||||
|
||||
// remote callgrind support
|
||||
Utils::SshConnection::Ptr m_ssh;
|
||||
QString m_tempDataFile;
|
||||
Utils::SshRemoteProcess::Ptr m_findRemoteFile;
|
||||
Utils::SftpChannel::Ptr m_sftp;
|
||||
Utils::SftpJobId m_downloadJob;
|
||||
QByteArray m_remoteFile;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CALLGRINDCONTROLLER_H
|
||||
147
src/libs/valgrind/callgrind/callgrindcostitem.cpp
Normal file
147
src/libs/valgrind/callgrind/callgrindcostitem.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindcostitem.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrindfunctioncall.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN CostItem::Private
|
||||
|
||||
class CostItem::Private {
|
||||
public:
|
||||
Private(ParseData *data);
|
||||
~Private();
|
||||
|
||||
QVector<quint64> m_positions;
|
||||
QVector<quint64> m_events;
|
||||
const FunctionCall *m_call;
|
||||
|
||||
const ParseData *m_data;
|
||||
qint64 m_differingFileId;
|
||||
};
|
||||
|
||||
CostItem::Private::Private(ParseData *data)
|
||||
: m_positions(data->positions().size(), 0)
|
||||
, m_events(data->events().size(), 0)
|
||||
, m_call(0)
|
||||
, m_data(data)
|
||||
, m_differingFileId(-1)
|
||||
{
|
||||
}
|
||||
|
||||
CostItem::Private::~Private()
|
||||
{
|
||||
delete m_call;
|
||||
}
|
||||
|
||||
|
||||
//BEGIN CostItem
|
||||
CostItem::CostItem(ParseData *data)
|
||||
: d(new Private(data))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CostItem::~CostItem()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
quint64 CostItem::position(int posIdx) const
|
||||
{
|
||||
return d->m_positions.at(posIdx);
|
||||
}
|
||||
|
||||
void CostItem::setPosition(int posIdx, quint64 position)
|
||||
{
|
||||
d->m_positions[posIdx] = position;
|
||||
}
|
||||
|
||||
QVector< quint64 > CostItem::positions() const
|
||||
{
|
||||
return d->m_positions;
|
||||
}
|
||||
|
||||
quint64 CostItem::cost(int event) const
|
||||
{
|
||||
return d->m_events.at(event);
|
||||
}
|
||||
|
||||
void CostItem::setCost(int event, quint64 cost)
|
||||
{
|
||||
d->m_events[event] = cost;
|
||||
}
|
||||
|
||||
QVector< quint64 > CostItem::costs() const
|
||||
{
|
||||
return d->m_events;
|
||||
}
|
||||
|
||||
const FunctionCall *CostItem::call() const
|
||||
{
|
||||
return d->m_call;
|
||||
}
|
||||
|
||||
void CostItem::setCall(const FunctionCall *call)
|
||||
{
|
||||
d->m_call = call;
|
||||
}
|
||||
|
||||
QString CostItem::differingFile() const
|
||||
{
|
||||
if (d->m_differingFileId != -1)
|
||||
return d->m_data->stringForFileCompression(d->m_differingFileId);
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
qint64 CostItem::differingFileId() const
|
||||
{
|
||||
return d->m_differingFileId;
|
||||
}
|
||||
|
||||
void CostItem::setDifferingFile(qint64 fileId)
|
||||
{
|
||||
d->m_differingFileId = fileId;
|
||||
}
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
103
src/libs/valgrind/callgrind/callgrindcostitem.h
Normal file
103
src/libs/valgrind/callgrind/callgrindcostitem.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRIND_COSTITEM_H
|
||||
#define LIBVALGRIND_CALLGRIND_COSTITEM_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QString;
|
||||
template<typename T> class QVector;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class FunctionCall;
|
||||
class ParseData;
|
||||
|
||||
/**
|
||||
* This class represents the cost(s) at given position(s).
|
||||
*/
|
||||
class VALGRINDSHARED_EXPORT CostItem {
|
||||
public:
|
||||
/// @p data the file data this cost item was parsed in.
|
||||
/// required for decompression of string data like differing source file information
|
||||
explicit CostItem(ParseData *data);
|
||||
~CostItem();
|
||||
|
||||
/**
|
||||
* Position data for the given position-index @p posIdx
|
||||
* @see ParseData::positions()
|
||||
*/
|
||||
quint64 position(int posIdx) const;
|
||||
void setPosition(int posIdx, quint64 position);
|
||||
QVector<quint64> positions() const;
|
||||
|
||||
/**
|
||||
* Cost data for the given event-index @p event
|
||||
* @see ParseData::events()
|
||||
*/
|
||||
quint64 cost(int event) const;
|
||||
void setCost(int event, quint64 cost);
|
||||
QVector<quint64> costs() const;
|
||||
|
||||
/**
|
||||
* If this cost item represents a function call, this will return the @c Callee.
|
||||
* Otherwise zero will be returned.
|
||||
*/
|
||||
const FunctionCall *call() const;
|
||||
///NOTE: @c CostItem will take ownership
|
||||
void setCall(const FunctionCall *call);
|
||||
|
||||
/**
|
||||
* If this cost item represents a jump to a different file, this will
|
||||
* return the path to that file. The string will be empty otherwise.
|
||||
*/
|
||||
QString differingFile() const;
|
||||
/// @return compressed file id or -1 if none is set
|
||||
qint64 differingFileId() const;
|
||||
void setDifferingFile(qint64 fileId);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(CostItem);
|
||||
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRIND_COSTITEM_H
|
||||
125
src/libs/valgrind/callgrind/callgrindcycledetection.cpp
Normal file
125
src/libs/valgrind/callgrind/callgrindcycledetection.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindcycledetection.h"
|
||||
|
||||
#include "callgrindfunction.h"
|
||||
#include "callgrindfunctioncall.h"
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrindfunctioncycle.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
namespace Internal {
|
||||
|
||||
CycleDetection::CycleDetection(ParseData *data)
|
||||
: m_data(data)
|
||||
, m_depth(0)
|
||||
, m_cycle(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QVector<const Function *> CycleDetection::run(const QVector<const Function *> &input)
|
||||
{
|
||||
foreach(const Function *function, input) {
|
||||
Node *node = new Node;
|
||||
node->function = function;
|
||||
node->dfs = -1;
|
||||
node->lowlink = -1;
|
||||
m_nodes.insert(function, node);
|
||||
}
|
||||
foreach(Node *node, m_nodes) {
|
||||
if (node->dfs == -1)
|
||||
tarjan(node);
|
||||
}
|
||||
qDeleteAll(m_nodes);
|
||||
return m_ret;
|
||||
}
|
||||
|
||||
void CycleDetection::tarjan(Node *node)
|
||||
{
|
||||
QTC_ASSERT(node->dfs == -1, return);
|
||||
node->dfs = m_depth;
|
||||
node->lowlink = m_depth;
|
||||
|
||||
m_depth++;
|
||||
m_stack.push(node);
|
||||
|
||||
foreach(const FunctionCall *call, node->function->outgoingCalls())
|
||||
tarjanForChildNode(node, m_nodes.value(call->callee()));
|
||||
|
||||
if (node->dfs == node->lowlink) {
|
||||
QVector<const Function *> functions;
|
||||
Node *n;
|
||||
do {
|
||||
n = m_stack.pop();
|
||||
functions << n->function;
|
||||
} while(n != node);
|
||||
|
||||
if (functions.size() == 1) {
|
||||
// not a real cycle
|
||||
m_ret.append(node->function);
|
||||
} else {
|
||||
// actual cycle
|
||||
FunctionCycle *cycle = new FunctionCycle(m_data);
|
||||
cycle->setFile(node->function->fileId());
|
||||
m_cycle++;
|
||||
qint64 id = -1;
|
||||
m_data->addCompressedFunction(QString("cycle %1").arg(m_cycle), id);
|
||||
cycle->setName(id);
|
||||
cycle->setObject(node->function->objectId());
|
||||
cycle->setFunctions(functions);
|
||||
m_ret.append(cycle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CycleDetection::tarjanForChildNode(Node *node, Node *childNode)
|
||||
{
|
||||
if (childNode->dfs == -1) {
|
||||
tarjan(childNode);
|
||||
if (childNode->lowlink < node->lowlink)
|
||||
node->lowlink = childNode->lowlink;
|
||||
} else if (childNode->dfs < node->lowlink && m_stack.contains(childNode)) {
|
||||
node->lowlink = childNode->dfs;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
85
src/libs/valgrind/callgrind/callgrindcycledetection.h
Normal file
85
src/libs/valgrind/callgrind/callgrindcycledetection.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRINDCYCLEDETECTION_H
|
||||
#define LIBVALGRIND_CALLGRINDCYCLEDETECTION_H
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QStack>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Function;
|
||||
class ParseData;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
/**
|
||||
* Implementation of Tarjan's strongly connected components algorithm, to find function cycles,
|
||||
* as suggested by the GProf paper:
|
||||
*
|
||||
* ``gprof: A Call Graph Execution Profiler'', by S. Graham, P. Kessler,
|
||||
* M. McKusick; Proceedings of the SIGPLAN '82 Symposium on Compiler Construction,
|
||||
* SIGPLAN Notices, Vol. 17, No 6, pp. 120-126, June 1982.
|
||||
*/
|
||||
class CycleDetection {
|
||||
public:
|
||||
explicit CycleDetection(ParseData *data);
|
||||
QVector<const Function *> run(const QVector<const Function *> &input);
|
||||
|
||||
private:
|
||||
ParseData *m_data;
|
||||
|
||||
struct Node {
|
||||
int dfs;
|
||||
int lowlink;
|
||||
const Function *function;
|
||||
};
|
||||
|
||||
void tarjan(Node *node);
|
||||
void tarjanForChildNode(Node *node, Node *childNode);
|
||||
|
||||
QHash<const Function *, Node *> m_nodes;
|
||||
QStack<Node *> m_stack;
|
||||
QVector<const Function *> m_ret;
|
||||
int m_depth;
|
||||
|
||||
int m_cycle;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRINDCYCLEDETECTION_H
|
||||
346
src/libs/valgrind/callgrind/callgrinddatamodel.cpp
Normal file
346
src/libs/valgrind/callgrind/callgrinddatamodel.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Instrumentation Tools
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "callgrinddatamodel.h"
|
||||
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrindfunction.h"
|
||||
#include "callgrindcostitem.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QDebug>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN Helper
|
||||
|
||||
namespace {
|
||||
// minimum amount of columns, i.e.:
|
||||
// function name
|
||||
// file name
|
||||
// object name
|
||||
// num called
|
||||
// Additional to this, 2 * ParseData::events().size will be shown (inclusive + self cost)
|
||||
const int MinColumnSize = 4;
|
||||
}
|
||||
|
||||
//BEGIN DataModel::Private
|
||||
|
||||
class DataModel::Private {
|
||||
public:
|
||||
Private()
|
||||
: m_data(0)
|
||||
, m_event(0)
|
||||
, m_cycleDetection(false)
|
||||
{
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
}
|
||||
|
||||
void updateFunctions();
|
||||
|
||||
const ParseData *m_data;
|
||||
int m_event;
|
||||
bool m_cycleDetection;
|
||||
QVector<const Function *> m_functions;
|
||||
};
|
||||
|
||||
struct SortFunctions {
|
||||
SortFunctions(int event)
|
||||
: m_event(event)
|
||||
{
|
||||
}
|
||||
bool operator()(const Function *left, const Function *right)
|
||||
{
|
||||
return left->inclusiveCost(m_event) > right->inclusiveCost(m_event);
|
||||
}
|
||||
int m_event;
|
||||
};
|
||||
|
||||
void DataModel::Private::updateFunctions()
|
||||
{
|
||||
if (m_data) {
|
||||
m_functions = m_data->functions(m_cycleDetection);
|
||||
qSort(m_functions.begin(), m_functions.end(), SortFunctions(m_event));
|
||||
} else {
|
||||
m_functions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//BEGIN DataModel
|
||||
|
||||
DataModel::DataModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DataModel::~DataModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void DataModel::setParseData(const ParseData *data)
|
||||
{
|
||||
if (d->m_data == data)
|
||||
return;
|
||||
|
||||
beginResetModel();
|
||||
d->m_data = data;
|
||||
d->m_event = 0;
|
||||
d->updateFunctions();
|
||||
endResetModel();
|
||||
emit parseDataChanged(this);
|
||||
}
|
||||
|
||||
const ParseData *DataModel::parseData() const
|
||||
{
|
||||
return d->m_data;
|
||||
}
|
||||
|
||||
void DataModel::setCostEvent(int event)
|
||||
{
|
||||
if (!d->m_data)
|
||||
return;
|
||||
|
||||
QTC_ASSERT(event >= 0 && d->m_data->events().size() > event, return)
|
||||
beginResetModel();
|
||||
d->m_event = event;
|
||||
d->updateFunctions();
|
||||
endResetModel();
|
||||
emit dataChanged(index(0, SelfCostColumn), index(qMax(0, rowCount() - 1), InclusiveCostColumn));
|
||||
}
|
||||
|
||||
int DataModel::costEvent() const
|
||||
{
|
||||
return d->m_event;
|
||||
}
|
||||
|
||||
int DataModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);
|
||||
|
||||
if (!d->m_data || parent.isValid())
|
||||
return 0;
|
||||
|
||||
return d->m_functions.size();
|
||||
}
|
||||
|
||||
int DataModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid() || parent.model() == this, return 0);
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return ColumnCount;
|
||||
}
|
||||
|
||||
QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid() || parent.model() == this, return QModelIndex());
|
||||
if (row == 0 && rowCount(parent) == 0) // happens with empty models
|
||||
return QModelIndex();
|
||||
QTC_ASSERT(row >= 0 && row < rowCount(parent), return QModelIndex());
|
||||
return createIndex(row, column);
|
||||
}
|
||||
|
||||
QModelIndex DataModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
QTC_ASSERT(!child.isValid() || child.model() == this, return QModelIndex());
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex DataModel::indexForObject(const Function *function) const
|
||||
{
|
||||
if (!function)
|
||||
return QModelIndex();
|
||||
|
||||
const int row = d->m_functions.indexOf(function);
|
||||
if (row < 0)
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(row, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evil workaround for http://bugreports.qt.nokia.com/browse/QTBUG-1135
|
||||
* Just replace the bad hyphens by a 'NON-BREAKING HYPHEN' unicode char
|
||||
*/
|
||||
static QString noWrap(const QString &str)
|
||||
{
|
||||
QString escapedStr = str;
|
||||
return escapedStr.replace("-", "‑");
|
||||
}
|
||||
|
||||
QVariant DataModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QTC_ASSERT(index.isValid() && index.model() == this, return QVariant());
|
||||
QTC_ASSERT(index.column() >= 0 && index.column() < columnCount(index.parent()), return QVariant());
|
||||
QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(index.parent()), return QVariant());
|
||||
|
||||
const Function *func = d->m_functions.at(index.row());
|
||||
const quint64 selfCost = func->selfCost(d->m_event);
|
||||
const quint64 inclusiveCost = func->inclusiveCost(d->m_event);
|
||||
const quint64 totalCost = d->m_data->totalCost(d->m_event);
|
||||
|
||||
if (role == FunctionRole) {
|
||||
return QVariant::fromValue(func);
|
||||
}
|
||||
else if (role == ParentCostRole) {
|
||||
return totalCost;
|
||||
}
|
||||
// the data model does not know about parent<->child relationship
|
||||
else if (role == RelativeParentCostRole || role == RelativeTotalCostRole) {
|
||||
if (index.column() == SelfCostColumn)
|
||||
return (float)selfCost / totalCost;
|
||||
else if (index.column() == InclusiveCostColumn)
|
||||
return (float)inclusiveCost / totalCost;
|
||||
}
|
||||
else if (role == LineNumberRole) {
|
||||
return func->lineNumber();
|
||||
}
|
||||
else if (role == FileNameRole) {
|
||||
return func->file();
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole) {
|
||||
if (index.column() == CalledColumn) {
|
||||
return Qt::AlignRight;
|
||||
}
|
||||
}
|
||||
else if (role == Qt::DisplayRole) {
|
||||
if (index.column() == NameColumn)
|
||||
return func->name();
|
||||
else if (index.column() == LocationColumn)
|
||||
return func->location();
|
||||
else if (index.column() == CalledColumn)
|
||||
return func->called();
|
||||
else if (index.column() == SelfCostColumn)
|
||||
return selfCost;
|
||||
else if (index.column() == InclusiveCostColumn)
|
||||
return inclusiveCost;
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
QString ret = "<html><head><style>\
|
||||
dt { font-weight: bold; }\
|
||||
dd { font-family: monospace; }\
|
||||
tr.head, td.head { font-weight: bold; }\
|
||||
tr.head { text-decoration: underline; }\
|
||||
td.group { padding-left: 20px; }\
|
||||
td { white-space: nowrap; }\
|
||||
</style></head>\n";
|
||||
|
||||
// body, function info first
|
||||
ret += "<body><dl>";
|
||||
ret += "<dt>" + tr("Function:") + "</dt><dd>" + func->name() + "</dd>\n";
|
||||
ret += "<dt>" + tr("File:") + "</dt><dd>" + func->file() + "</dd>\n";
|
||||
if (!func->costItems().isEmpty()) {
|
||||
const CostItem *firstItem = func->costItems().first();
|
||||
for(int i = 0; i < d->m_data->positions().size(); ++i) {
|
||||
ret += "<dt>" + ParseData::prettyStringForPosition(d->m_data->positions().at(i)) + "</dt>";
|
||||
ret += "<dd>" + QString::number(firstItem->position(i)) + "</dd>\n";
|
||||
}
|
||||
}
|
||||
ret += "<dt>" + tr("Object:") + "</dt><dd>" + func->object() + "</dd>\n";
|
||||
ret += "<dt>" + tr("Called:") + "</dt><dd>" + tr("%1 times").arg(func->called()) + "</dd>\n";
|
||||
ret += "</dl><p/>";
|
||||
|
||||
// self/inclusive costs
|
||||
ret += "<table>";
|
||||
ret += "<thead><tr class='head'><td>" + tr("Events") + "</td>";
|
||||
ret += "<td class='group'>" + tr("Self costs") + "</td><td>" + tr("(%)") + "</td>";
|
||||
ret += "<td class='group'>" + tr("Incl. costs") + "</td><td>" + tr("(%)") + "</td>";
|
||||
ret += "</tr></thead>";
|
||||
ret += "<tbody>";
|
||||
for(int i = 0; i < d->m_data->events().size(); ++i) {
|
||||
quint64 selfCost = func->selfCost(i);
|
||||
quint64 inclCost = func->inclusiveCost(i);
|
||||
quint64 totalCost = d->m_data->totalCost(i);
|
||||
// 0.00% format
|
||||
const float relSelfCost = (float)qRound((float)selfCost / totalCost * 10000) / 100;
|
||||
const float relInclCost = (float)qRound((float)inclCost / totalCost * 10000) / 100;
|
||||
|
||||
ret += "<tr>";
|
||||
ret += "<td class='head'><nobr>" + noWrap(ParseData::prettyStringForEvent(d->m_data->events().at(i))) + "</nobr></td>";
|
||||
ret += "<td class='group'>" + tr("%1").arg(selfCost) + "</td>";
|
||||
ret += "<td>" + tr("(%1%)").arg(relSelfCost) + "</td>";
|
||||
ret += "<td class='group'>" + tr("%1").arg(inclCost) + "</td>";
|
||||
ret += "<td>" + tr("(%1%)").arg(relInclCost) + "</td>";
|
||||
ret += "</tr>";
|
||||
}
|
||||
ret += "</tbody></table>";
|
||||
ret += "</body></html>";
|
||||
return ret;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Vertical || role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
QTC_ASSERT(section >= 0 && section < columnCount(), return QVariant());
|
||||
|
||||
if (section == NameColumn)
|
||||
return tr("Function");
|
||||
else if (section == LocationColumn)
|
||||
return tr("Location");
|
||||
else if (section == CalledColumn)
|
||||
return tr("Called");
|
||||
else if (section == SelfCostColumn)
|
||||
return tr("Self Cost: %1").arg(d->m_data ? d->m_data->events().value(d->m_event) : QString());
|
||||
else if (section == InclusiveCostColumn)
|
||||
return tr("Incl. Cost: %1").arg(d->m_data ? d->m_data->events().value(d->m_event) : QString());
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void DataModel::enableCycleDetection(bool enabled)
|
||||
{
|
||||
beginResetModel();
|
||||
d->m_cycleDetection = enabled;
|
||||
d->updateFunctions();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
109
src/libs/valgrind/callgrind/callgrinddatamodel.h
Normal file
109
src/libs/valgrind/callgrind/callgrinddatamodel.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Instrumentation Tools
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#ifndef VALGRIND_CALLGRIND_CALLGRINDDATAMODEL_H
|
||||
#define VALGRIND_CALLGRIND_CALLGRINDDATAMODEL_H
|
||||
|
||||
#include <QtCore/QAbstractItemModel>
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
#include "callgrindabstractmodel.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Function;
|
||||
class ParseData;
|
||||
|
||||
class VALGRINDSHARED_EXPORT DataModel : public QAbstractItemModel, public AbstractModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DataModel(QObject *parent = 0);
|
||||
virtual ~DataModel();
|
||||
|
||||
virtual void setParseData(const ParseData *data);
|
||||
virtual const ParseData *parseData() const;
|
||||
|
||||
/// Only one cost event column will be shown, this decides which one it is.
|
||||
/// By default it is the first event in the @c ParseData, i.e. 0.
|
||||
virtual int costEvent() const;
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex parent(const QModelIndex &child) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
|
||||
QModelIndex indexForObject(const Function *function) const;
|
||||
|
||||
enum Columns {
|
||||
NameColumn,
|
||||
LocationColumn,
|
||||
CalledColumn,
|
||||
SelfCostColumn,
|
||||
InclusiveCostColumn,
|
||||
ColumnCount
|
||||
};
|
||||
|
||||
enum Roles {
|
||||
FunctionRole = AbstractModel::NextCustomRole,
|
||||
LineNumberRole,
|
||||
FileNameRole
|
||||
};
|
||||
|
||||
public slots:
|
||||
/// enable/disable cycle detection
|
||||
void enableCycleDetection(bool enabled);
|
||||
|
||||
/// Only one cost event column will be shown, this decides which one it is.
|
||||
/// By default it is the first event in the @c ParseData, i.e. 0.
|
||||
virtual void setCostEvent(int event);
|
||||
|
||||
signals:
|
||||
void parseDataChanged(AbstractModel *model);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
|
||||
#endif // VALGRIND_CALLGRIND_CALLGRINDDATAMODEL_H
|
||||
337
src/libs/valgrind/callgrind/callgrindfunction.cpp
Normal file
337
src/libs/valgrind/callgrind/callgrindfunction.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindfunction.h"
|
||||
|
||||
#include "callgrindfunctioncall.h"
|
||||
#include "callgrindcostitem.h"
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrindfunction_p.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN Function::Private
|
||||
|
||||
Function::Private::Private(const ParseData *data)
|
||||
: m_data(data)
|
||||
, m_fileId(-1)
|
||||
, m_objectId(-1)
|
||||
, m_nameId(-1)
|
||||
, m_selfCost(data->events().size(), 0)
|
||||
, m_inclusiveCost(data->events().size(), 0)
|
||||
, m_called(0)
|
||||
{
|
||||
}
|
||||
|
||||
Function::Private::~Private()
|
||||
{
|
||||
// we don't own m_callers
|
||||
// we own the costitem which in turn owns the callees,
|
||||
// so only delete the former
|
||||
qDeleteAll(m_costItems);
|
||||
|
||||
qDeleteAll(m_outgoingCalls);
|
||||
}
|
||||
|
||||
void Function::Private::accumulateCost(QVector<quint64> &base, const QVector<quint64> &add)
|
||||
{
|
||||
if (base.isEmpty()) {
|
||||
base = add;
|
||||
} else {
|
||||
///TODO: see whether .data() is noticably faster (less detaching)
|
||||
int i = 0;
|
||||
foreach(quint64 cost, add)
|
||||
base[i++] += cost;
|
||||
}
|
||||
}
|
||||
|
||||
FunctionCall *Function::Private::accumulateCall(const FunctionCall *call, CallType type)
|
||||
{
|
||||
const Function *key = (type == Incoming) ? call->caller() : call->callee();
|
||||
QHash<const Function *, FunctionCall *> &callMap = (type == Incoming) ? m_incomingCallMap : m_outgoingCallMap;
|
||||
|
||||
FunctionCall *accumulatedCall = callMap.value(key, 0);
|
||||
if (!accumulatedCall) {
|
||||
accumulatedCall = new FunctionCall;
|
||||
if (type == Incoming)
|
||||
m_incomingCalls << accumulatedCall;
|
||||
else
|
||||
m_outgoingCalls << accumulatedCall;
|
||||
|
||||
accumulatedCall->setCallee(call->callee());
|
||||
accumulatedCall->setCaller(call->caller());
|
||||
///TODO: could the destinations differ from call to call? they should not, or?
|
||||
accumulatedCall->setDestinations(call->destinations());
|
||||
callMap.insert(key, accumulatedCall);
|
||||
|
||||
accumulatedCall->setCosts(call->costs());
|
||||
} else {
|
||||
QVector<quint64> costs = accumulatedCall->costs();
|
||||
accumulateCost(costs, call->costs());
|
||||
accumulatedCall->setCosts(costs);
|
||||
}
|
||||
|
||||
accumulatedCall->setCalls(accumulatedCall->calls() + call->calls());
|
||||
return accumulatedCall;
|
||||
}
|
||||
|
||||
//BEGIN Function
|
||||
Function::Function(const ParseData *data)
|
||||
: d(new Private(data))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Function::Function(Function::Private *d)
|
||||
: d(d)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Function::~Function()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
qint64 Function::nameId() const
|
||||
{
|
||||
return d->m_nameId;
|
||||
}
|
||||
|
||||
QString Function::name() const
|
||||
{
|
||||
if (d->m_nameId != -1)
|
||||
return d->m_data->stringForFunctionCompression(d->m_nameId);
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
void Function::setName(qint64 id)
|
||||
{
|
||||
d->m_nameId = id;
|
||||
}
|
||||
|
||||
qint64 Function::fileId() const
|
||||
{
|
||||
return d->m_fileId;
|
||||
}
|
||||
|
||||
QString Function::file() const
|
||||
{
|
||||
if (d->m_fileId != -1)
|
||||
return d->m_data->stringForFileCompression(d->m_fileId);
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
void Function::setFile(qint64 id)
|
||||
{
|
||||
d->m_fileId = id;
|
||||
}
|
||||
|
||||
qint64 Function::objectId() const
|
||||
{
|
||||
return d->m_objectId;
|
||||
}
|
||||
|
||||
QString Function::object() const
|
||||
{
|
||||
if (d->m_objectId != -1)
|
||||
return d->m_data->stringForObjectCompression(d->m_objectId);
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
void Function::setObject(qint64 id)
|
||||
{
|
||||
d->m_objectId = id;
|
||||
}
|
||||
|
||||
QString Function::location() const
|
||||
{
|
||||
QString pos;
|
||||
foreach(const CostItem *costItem, d->m_costItems) {
|
||||
if (costItem->differingFileId() != -1) {
|
||||
QTextStream stream(&pos);
|
||||
stream << '(';
|
||||
for(int i = 0, c = costItem->positions().count(); i < c; ++i) {
|
||||
///TODO: remember what was hex formatted
|
||||
stream << costItem->position(i);
|
||||
if (i != c - 1)
|
||||
stream << ", ";
|
||||
}
|
||||
stream << ')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
QString f = file();
|
||||
|
||||
if (!f.isEmpty()) {
|
||||
QFileInfo info(f);
|
||||
if (info.exists()) {
|
||||
f = info.canonicalFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
QString o = object();
|
||||
if (o.isEmpty())
|
||||
return QString();
|
||||
if (f.isEmpty() || f == "???")
|
||||
return o;
|
||||
if (pos.isEmpty())
|
||||
return QObject::tr("%1 in %2").arg(f, o);
|
||||
|
||||
return QObject::tr("%1:%2 in %3").arg(f, pos, o);
|
||||
}
|
||||
|
||||
int Function::lineNumber() const
|
||||
{
|
||||
const int lineIdx = d->m_data->lineNumberPositionIndex();
|
||||
if (lineIdx == -1)
|
||||
return -1;
|
||||
|
||||
foreach(const CostItem *costItem, d->m_costItems) {
|
||||
if (costItem->differingFileId() == -1)
|
||||
return costItem->position(lineIdx);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
quint64 Function::selfCost(int event) const
|
||||
{
|
||||
return d->m_selfCost.at(event);
|
||||
}
|
||||
|
||||
QVector< quint64 > Function::selfCosts() const
|
||||
{
|
||||
return d->m_selfCost;
|
||||
}
|
||||
|
||||
quint64 Function::inclusiveCost(int event) const
|
||||
{
|
||||
return d->m_inclusiveCost.at(event) + d->m_selfCost.at(event);
|
||||
}
|
||||
|
||||
QVector<const FunctionCall *> Function::outgoingCalls() const
|
||||
{
|
||||
return d->m_outgoingCalls;
|
||||
}
|
||||
|
||||
void Function::addOutgoingCall(const FunctionCall *call)
|
||||
{
|
||||
QTC_ASSERT(call->caller() == this, return);
|
||||
|
||||
d->accumulateCall(call, Private::Outgoing);
|
||||
}
|
||||
|
||||
QVector<const FunctionCall *> Function::incomingCalls() const
|
||||
{
|
||||
return d->m_incomingCalls;
|
||||
}
|
||||
|
||||
void Function::addIncomingCall(const FunctionCall *call)
|
||||
{
|
||||
QTC_ASSERT(call->callee() == this, return);
|
||||
d->m_called += call->calls();
|
||||
d->accumulateCall(call, Private::Incoming);
|
||||
}
|
||||
|
||||
quint64 Function::called() const
|
||||
{
|
||||
return d->m_called;
|
||||
}
|
||||
|
||||
QVector<const CostItem *> Function::costItems() const
|
||||
{
|
||||
return d->m_costItems;
|
||||
}
|
||||
|
||||
void Function::addCostItem(const CostItem *item)
|
||||
{
|
||||
QTC_ASSERT(!d->m_costItems.contains(item), return);
|
||||
|
||||
d->m_costItems.append(item);
|
||||
|
||||
// accumulate costs
|
||||
if (item->call()) {
|
||||
d->accumulateCost(d->m_inclusiveCost, item->costs());
|
||||
} else {
|
||||
d->accumulateCost(d->m_selfCost, item->costs());
|
||||
}
|
||||
}
|
||||
|
||||
void Function::finalize()
|
||||
{
|
||||
bool recursive = false;
|
||||
foreach(const FunctionCall *call, d->m_incomingCalls) {
|
||||
if (call->caller() == this) {
|
||||
recursive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (recursive) {
|
||||
// now handle recursive calls by setting the incl cost to the sum of all (external) calls
|
||||
// to this function
|
||||
// e.g.: A -> B -> B ..., C -> B -> B ...
|
||||
// cost of B = cost of call to B in A + cost of call to B in C + ...
|
||||
d->m_inclusiveCost.fill(0);
|
||||
foreach(const FunctionCall *call, d->m_incomingCalls) {
|
||||
if (call->caller() != this) {
|
||||
foreach(const CostItem *costItem, call->caller()->costItems()) {
|
||||
if (costItem->call() && costItem->call()->callee() == this)
|
||||
d->accumulateCost(d->m_inclusiveCost, costItem->costs());
|
||||
}
|
||||
}
|
||||
}
|
||||
/// now substract self cost (see @c inclusiveCost() implementation)
|
||||
for(int i = 0, c = d->m_inclusiveCost.size(); i < c; ++i) {
|
||||
if (d->m_inclusiveCost.at(i) < d->m_selfCost.at(i))
|
||||
d->m_inclusiveCost[i] = 0;
|
||||
else
|
||||
d->m_inclusiveCost[i] -= d->m_selfCost.at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
162
src/libs/valgrind/callgrind/callgrindfunction.h
Normal file
162
src/libs/valgrind/callgrind/callgrindfunction.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRIND_FUNCTION_H
|
||||
#define LIBVALGRIND_CALLGRIND_FUNCTION_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QString;
|
||||
template <typename T> class QVector;
|
||||
template <typename T> class QSet;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class FunctionCall;
|
||||
class CostItem;
|
||||
class ParseData;
|
||||
|
||||
class VALGRINDSHARED_EXPORT Function {
|
||||
public:
|
||||
/// @p data the ParseData for the file this function was part of
|
||||
/// required for the decompression of string data like function name etc.
|
||||
explicit Function(const ParseData *data);
|
||||
virtual ~Function();
|
||||
|
||||
/// @return the compressed function name id
|
||||
qint64 nameId() const;
|
||||
/// @return the function name.
|
||||
QString name() const;
|
||||
/**
|
||||
* Set function name to internal string id @p id.
|
||||
* @see ParseData::stringForFunction()
|
||||
*/
|
||||
void setName(qint64 id);
|
||||
|
||||
/// @return the compressed file id
|
||||
qint64 fileId() const;
|
||||
/// @return the file path where this function was defined
|
||||
QString file() const;
|
||||
/**
|
||||
* Set function name to internal string id @p id.
|
||||
* @see ParseData::stringForFunction()
|
||||
*/
|
||||
void setFile(qint64 id);
|
||||
|
||||
/// @return the compressed object id
|
||||
qint64 objectId() const;
|
||||
/// @return the object where this function was defined
|
||||
QString object() const;
|
||||
/**
|
||||
* Set function name to internal string id @p id.
|
||||
* @see ParseData::stringForFunction()
|
||||
*/
|
||||
void setObject(qint64 id);
|
||||
|
||||
/**
|
||||
* @return a string representing the location of this function
|
||||
* It is a combination of file, object and line of the first CostItem.
|
||||
*/
|
||||
QString location() const;
|
||||
|
||||
/**
|
||||
* @return the line number of the function or -1 if not known
|
||||
*/
|
||||
int lineNumber() const;
|
||||
|
||||
/**
|
||||
* total accumulated self cost of @p event
|
||||
* @see ParseData::events()
|
||||
*/
|
||||
quint64 selfCost(int event) const;
|
||||
QVector<quint64> selfCosts() const;
|
||||
|
||||
/**
|
||||
* total accumulated inclusive cost of @p event
|
||||
* @see ParseData::events()
|
||||
*/
|
||||
quint64 inclusiveCost(int event) const;
|
||||
|
||||
/// calls from other functions to this function
|
||||
QVector<const FunctionCall *> incomingCalls() const;
|
||||
void addIncomingCall(const FunctionCall *call);
|
||||
/// @return how often this function was called in total
|
||||
quint64 called() const;
|
||||
|
||||
/**
|
||||
* The detailed list of cost items, which could e.g. be used for
|
||||
* a detailed view of the function's source code annotated with
|
||||
* cost per line.
|
||||
*/
|
||||
QVector<const CostItem *> costItems() const;
|
||||
|
||||
/**
|
||||
* Add parsed @c CostItem @p item to this function.
|
||||
*
|
||||
* NOTE: The @c Function will take ownership.
|
||||
*/
|
||||
void addCostItem(const CostItem *item);
|
||||
|
||||
/**
|
||||
* Function calls from this function to others.
|
||||
*/
|
||||
QVector<const FunctionCall *> outgoingCalls() const;
|
||||
void addOutgoingCall(const FunctionCall *call);
|
||||
|
||||
/**
|
||||
* Gets called after all functions where looked up, required
|
||||
* to properly calculate inclusive cost of recursive functions
|
||||
* for example
|
||||
*/
|
||||
void finalize();
|
||||
protected:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
||||
explicit Function(Private *d);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Function)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(const Valgrind::Callgrind::Function *);
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRIND_FUNCTION_H
|
||||
82
src/libs/valgrind/callgrind/callgrindfunction_p.h
Normal file
82
src/libs/valgrind/callgrind/callgrindfunction_p.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRINDFUNCTION_P_H
|
||||
#define LIBVALGRIND_CALLGRINDFUNCTION_P_H
|
||||
|
||||
#include "callgrindfunction.h"
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrindcostitem.h"
|
||||
#include "callgrindfunctioncall.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QHash>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Function::Private {
|
||||
public:
|
||||
Private(const ParseData *data);
|
||||
~Private();
|
||||
|
||||
static void accumulateCost(QVector<quint64> &base, const QVector<quint64> &add);
|
||||
enum CallType {
|
||||
Incoming,
|
||||
Outgoing
|
||||
};
|
||||
///@return accumulated call
|
||||
FunctionCall *accumulateCall(const FunctionCall *call, CallType type);
|
||||
|
||||
const ParseData *m_data;
|
||||
qint64 m_fileId;
|
||||
qint64 m_objectId;
|
||||
qint64 m_nameId;
|
||||
|
||||
QVector<quint64> m_selfCost;
|
||||
QVector<quint64> m_inclusiveCost;
|
||||
|
||||
QVector<const CostItem *> m_costItems;
|
||||
// used to accumulate, hence values not const
|
||||
QHash<const Function *, FunctionCall *> m_outgoingCallMap;
|
||||
QHash<const Function *, FunctionCall *> m_incomingCallMap;
|
||||
// used in public api, hence const
|
||||
QVector<const FunctionCall *> m_outgoingCalls;
|
||||
QVector<const FunctionCall *> m_incomingCalls;
|
||||
quint64 m_called;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRINDFUNCTION_P_H
|
||||
143
src/libs/valgrind/callgrind/callgrindfunctioncall.cpp
Normal file
143
src/libs/valgrind/callgrind/callgrindfunctioncall.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindfunctioncall.h"
|
||||
|
||||
#include "callgrindfunction.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN FunctionCall::Private
|
||||
class FunctionCall::Private {
|
||||
public:
|
||||
explicit Private();
|
||||
|
||||
const Function *m_callee;
|
||||
const Function *m_caller;
|
||||
quint64 m_calls;
|
||||
quint64 m_totalInclusiveCost;
|
||||
QVector<quint64> m_destinations;
|
||||
QVector<quint64> m_costs;
|
||||
};
|
||||
|
||||
FunctionCall::Private::Private()
|
||||
: m_callee(0)
|
||||
, m_caller(0)
|
||||
, m_calls(0)
|
||||
, m_totalInclusiveCost(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//BEGIN FunctionCall
|
||||
|
||||
FunctionCall::FunctionCall()
|
||||
: d(new Private)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FunctionCall::~FunctionCall()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
const Function *FunctionCall::callee() const
|
||||
{
|
||||
return d->m_callee;
|
||||
}
|
||||
|
||||
void FunctionCall::setCallee(const Function *function)
|
||||
{
|
||||
d->m_callee = function;
|
||||
}
|
||||
|
||||
const Function *FunctionCall::caller() const
|
||||
{
|
||||
return d->m_caller;
|
||||
}
|
||||
|
||||
void FunctionCall::setCaller(const Function *function)
|
||||
{
|
||||
d->m_caller = function;
|
||||
}
|
||||
|
||||
quint64 FunctionCall::calls() const
|
||||
{
|
||||
return d->m_calls;
|
||||
}
|
||||
|
||||
void FunctionCall::setCalls(quint64 calls)
|
||||
{
|
||||
d->m_calls = calls;
|
||||
}
|
||||
|
||||
quint64 FunctionCall::destination(int posIdx) const
|
||||
{
|
||||
return d->m_destinations.at(posIdx);
|
||||
}
|
||||
|
||||
QVector<quint64> FunctionCall::destinations() const
|
||||
{
|
||||
return d->m_destinations;
|
||||
}
|
||||
|
||||
void FunctionCall::setDestinations(const QVector<quint64> &destinations)
|
||||
{
|
||||
d->m_destinations = destinations;
|
||||
}
|
||||
|
||||
quint64 FunctionCall::cost(int event) const
|
||||
{
|
||||
QTC_ASSERT(event >= 0 && event < d->m_costs.size(), return 0);
|
||||
return d->m_costs.at(event);
|
||||
}
|
||||
|
||||
QVector<quint64> FunctionCall::costs() const
|
||||
{
|
||||
return d->m_costs;
|
||||
}
|
||||
|
||||
void FunctionCall::setCosts(const QVector<quint64> &costs)
|
||||
{
|
||||
d->m_costs = costs;
|
||||
}
|
||||
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
98
src/libs/valgrind/callgrind/callgrindfunctioncall.h
Normal file
98
src/libs/valgrind/callgrind/callgrindfunctioncall.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRIND_CALLEE_H
|
||||
#define LIBVALGRIND_CALLGRIND_CALLEE_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
template <typename T> class QVector;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Function;
|
||||
|
||||
/**
|
||||
* This represents a function call.
|
||||
*/
|
||||
class VALGRINDSHARED_EXPORT FunctionCall {
|
||||
public:
|
||||
explicit FunctionCall();
|
||||
~FunctionCall();
|
||||
|
||||
/// the called function
|
||||
const Function *callee() const;
|
||||
void setCallee(const Function *function);
|
||||
|
||||
/// the calling function
|
||||
const Function *caller() const;
|
||||
void setCaller(const Function *function);
|
||||
|
||||
/// how often the function was called
|
||||
quint64 calls() const;
|
||||
void setCalls(quint64 calls);
|
||||
|
||||
/**
|
||||
* Destination position data for the given position-index @p posIdx
|
||||
* @see ParseData::positions()
|
||||
*/
|
||||
quint64 destination(int posIdx) const;
|
||||
QVector<quint64> destinations() const;
|
||||
void setDestinations(const QVector<quint64> &destinations);
|
||||
|
||||
/**
|
||||
* Inclusive cost of the function call.
|
||||
* @see ParseData::events()
|
||||
*/
|
||||
quint64 cost(int event) const;
|
||||
QVector<quint64> costs() const;
|
||||
void setCosts(const QVector<quint64> &costs);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(FunctionCall);
|
||||
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
|
||||
Q_DECLARE_METATYPE(const Valgrind::Callgrind::FunctionCall *);
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRIND_CALLEE_H
|
||||
119
src/libs/valgrind/callgrind/callgrindfunctioncycle.cpp
Normal file
119
src/libs/valgrind/callgrind/callgrindfunctioncycle.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindfunctioncycle.h"
|
||||
#include "callgrindfunction_p.h"
|
||||
|
||||
#include "callgrindfunctioncall.h"
|
||||
#include "callgrindparsedata.h"
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN FunctionCycle::Private
|
||||
|
||||
class FunctionCycle::Private : public Function::Private {
|
||||
public:
|
||||
Private(const ParseData *data);
|
||||
QVector<const Function *> m_functions;
|
||||
};
|
||||
|
||||
FunctionCycle::Private::Private(const ParseData *data)
|
||||
: Function::Private(data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#define CYCLE_D static_cast<FunctionCycle::Private *>(this->d)
|
||||
|
||||
//BEGIN FunctionCycle
|
||||
|
||||
FunctionCycle::FunctionCycle(const ParseData *data)
|
||||
: Function(new Private(data))
|
||||
{
|
||||
}
|
||||
|
||||
FunctionCycle::~FunctionCycle()
|
||||
{
|
||||
// d should be deleted by Function::~Function()
|
||||
}
|
||||
|
||||
void FunctionCycle::setFunctions(const QVector<const Function *> functions)
|
||||
{
|
||||
Private *d = CYCLE_D;
|
||||
|
||||
d->m_functions = functions;
|
||||
|
||||
d->m_incomingCallMap.clear();
|
||||
d->m_outgoingCallMap.clear();
|
||||
d->m_called = 0;
|
||||
d->m_selfCost.fill(0, d->m_data->events().size());
|
||||
d->m_inclusiveCost.fill(0, d->m_data->events().size());
|
||||
|
||||
foreach(const Function *func, functions) {
|
||||
// just add up self cost
|
||||
d->accumulateCost(d->m_selfCost, func->selfCosts());
|
||||
// add outgoing calls to functions that are not part of the cycle
|
||||
foreach(const FunctionCall *call, func->outgoingCalls()) {
|
||||
if (!functions.contains(call->callee()))
|
||||
d->accumulateCall(call, Function::Private::Outgoing);
|
||||
}
|
||||
// add incoming calls from functions that are not part of the cycle
|
||||
foreach(const FunctionCall *call, func->incomingCalls()) {
|
||||
if (!functions.contains(call->caller())) {
|
||||
d->accumulateCall(call, Function::Private::Incoming);
|
||||
d->m_called += call->calls();
|
||||
d->accumulateCost(d->m_inclusiveCost, call->costs());
|
||||
}
|
||||
}
|
||||
}
|
||||
// now substract self from incl. cost (see implementation of inclusiveCost())
|
||||
/// now substract self cost (see @c inclusiveCost() implementation)
|
||||
for(int i = 0, c = d->m_inclusiveCost.size(); i < c; ++i) {
|
||||
if (d->m_inclusiveCost.at(i) < d->m_selfCost.at(i))
|
||||
d->m_inclusiveCost[i] = 0;
|
||||
else
|
||||
d->m_inclusiveCost[i] -= d->m_selfCost.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
QVector<const Function *> FunctionCycle::functions() const
|
||||
{
|
||||
return CYCLE_D->m_functions;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
69
src/libs/valgrind/callgrind/callgrindfunctioncycle.h
Normal file
69
src/libs/valgrind/callgrind/callgrindfunctioncycle.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRINDFUNCTIONCYCLE_H
|
||||
#define LIBVALGRIND_CALLGRINDFUNCTIONCYCLE_H
|
||||
|
||||
#include "callgrindfunction.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
/**
|
||||
* self cost of a function cycle: sum of self costs of functions in the cycle
|
||||
* callers of a function cycle: set of callers to functions in the cycle
|
||||
* excluding calls inside the cycle
|
||||
* callees of a function cycle: set of callees from functions in the cycle
|
||||
* excluding calees inside the cycle
|
||||
* inclusive cost of a function cycle: sum of inclusive cost of callees of the cycle (see above)
|
||||
*/
|
||||
class VALGRINDSHARED_EXPORT FunctionCycle : public Function {
|
||||
public:
|
||||
explicit FunctionCycle(const ParseData *data);
|
||||
virtual ~FunctionCycle();
|
||||
|
||||
/// sets the list of functions that make up this cycle
|
||||
/// NOTE: ownership is *not* transferred to the cycle
|
||||
void setFunctions(const QVector<const Function *> functions);
|
||||
/// @return the functions that make up this cycle
|
||||
QVector<const Function *> functions() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRINDFUNCTIONCYCLE_H
|
||||
377
src/libs/valgrind/callgrind/callgrindparsedata.cpp
Normal file
377
src/libs/valgrind/callgrind/callgrindparsedata.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindparsedata.h"
|
||||
|
||||
#include "callgrindfunction.h"
|
||||
#include "callgrindcycledetection.h"
|
||||
#include "callgrindfunctioncycle.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QHash>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
//BEGIN ParseData::Private
|
||||
|
||||
class ParseData::Private {
|
||||
public:
|
||||
Private(ParseData *q)
|
||||
: m_lineNumberPositionIndex(-1)
|
||||
, m_pid(0)
|
||||
, m_part(0)
|
||||
, m_version(0)
|
||||
, m_cycleCacheValid(false)
|
||||
, m_q(q)
|
||||
{
|
||||
}
|
||||
|
||||
~Private();
|
||||
|
||||
QStringList m_events;
|
||||
QStringList m_positions;
|
||||
int m_lineNumberPositionIndex;
|
||||
QVector<quint64> m_totalCosts;
|
||||
QVector<const Function *> m_functions;
|
||||
QString m_command;
|
||||
quint64 m_pid;
|
||||
uint m_part;
|
||||
QStringList m_descriptions;
|
||||
int m_version;
|
||||
QString m_creator;
|
||||
|
||||
QHash<qint64, QHash<qint64, QVector<Function *> > > functionLookup;
|
||||
|
||||
typedef QHash<qint64, QString> NameLookupTable;
|
||||
QString stringForCompression(const NameLookupTable &lookup, qint64 id);
|
||||
void addCompressedString(NameLookupTable &lookup, const QString &string, qint64 &id);
|
||||
|
||||
NameLookupTable m_objectCompression;
|
||||
NameLookupTable m_fileCompression;
|
||||
NameLookupTable m_functionCompression;
|
||||
|
||||
void cycleDetection();
|
||||
void cleanupFunctionCycles();
|
||||
bool m_cycleCacheValid;
|
||||
QVector<const Function *> m_cycleCache;
|
||||
|
||||
ParseData *m_q;
|
||||
};
|
||||
|
||||
ParseData::Private::~Private()
|
||||
{
|
||||
cleanupFunctionCycles();
|
||||
qDeleteAll(m_functions);
|
||||
}
|
||||
|
||||
void ParseData::Private::cleanupFunctionCycles()
|
||||
{
|
||||
m_cycleCacheValid = false;
|
||||
foreach(const Function *func, m_cycleCache) {
|
||||
if (dynamic_cast<const FunctionCycle *>(func))
|
||||
delete func;
|
||||
}
|
||||
m_cycleCache.clear();
|
||||
}
|
||||
|
||||
QString ParseData::Private::stringForCompression(const NameLookupTable &lookup, qint64 id)
|
||||
{
|
||||
if (id == -1) {
|
||||
return QString();
|
||||
} else {
|
||||
QTC_ASSERT(lookup.contains(id), return QString());
|
||||
return lookup.value(id);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseData::Private::addCompressedString(NameLookupTable &lookup, const QString &string,
|
||||
qint64 &id)
|
||||
{
|
||||
QTC_ASSERT(!string.isEmpty(), return);
|
||||
|
||||
if (id == -1) {
|
||||
// for uncompressed files, use a hash of the string
|
||||
id = qHash(string);
|
||||
|
||||
if (lookup.contains(id)) {
|
||||
QTC_ASSERT(lookup.value(id) == string, return);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QTC_ASSERT(!lookup.contains(id), return);
|
||||
lookup.insert(id, string);
|
||||
}
|
||||
|
||||
void ParseData::Private::cycleDetection()
|
||||
{
|
||||
if (m_cycleCacheValid) {
|
||||
return;
|
||||
}
|
||||
cleanupFunctionCycles();
|
||||
Internal::CycleDetection algorithm(m_q);
|
||||
m_cycleCache = algorithm.run(m_functions);
|
||||
m_cycleCacheValid = true;
|
||||
}
|
||||
|
||||
//BEGIN ParseData
|
||||
|
||||
ParseData::ParseData()
|
||||
: d(new Private(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ParseData::~ParseData()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString ParseData::prettyStringForEvent(const QString &event)
|
||||
{
|
||||
/*
|
||||
From Callgrind documentation, see: http://valgrind.org/docs/manual/cg-manual.html#cg-manual.overview
|
||||
|
||||
I cache reads (Ir, which equals the number of instructions executed),
|
||||
I1 cache read misses (I1mr) and LL cache instruction read misses (ILmr).
|
||||
D cache reads (Dr, which equals the number of memory reads),
|
||||
D1 cache read misses (D1mr), and LL cache data read misses (DLmr).
|
||||
D cache writes (Dw, which equals the number of memory writes),
|
||||
D1 cache write misses (D1mw), and LL cache data write misses (DLmw).
|
||||
Conditional branches executed (Bc) and conditional branches mispredicted (Bcm).
|
||||
Indirect branches executed (Bi) and indirect branches mispredicted (Bim)
|
||||
*/
|
||||
|
||||
QTC_ASSERT(event.size() >= 2, return event) // should not happen
|
||||
|
||||
bool isMiss = event.contains("m"); // else hit
|
||||
bool isRead = event.contains("r"); // else write
|
||||
|
||||
QString type;
|
||||
if (event.contains("L"))
|
||||
type = QT_TR_NOOP("Last-level"); // first, "L" overwrites the others
|
||||
else if (event.at(0) == 'I')
|
||||
type = QT_TR_NOOP("Instruction");
|
||||
else if (event.at(0) == 'D')
|
||||
type = QT_TR_NOOP("Cache");
|
||||
else if (event.leftRef(2) == "Bc")
|
||||
type = QT_TR_NOOP("Conditional branches");
|
||||
else if (event.leftRef(2) == "Bi")
|
||||
type = QT_TR_NOOP("Indirect branches");
|
||||
|
||||
QStringList prettyString;
|
||||
prettyString << type;
|
||||
|
||||
if (event.at(1).isNumber())
|
||||
prettyString << QString("level %1").arg(event.at(1));
|
||||
prettyString << (isRead ? QT_TR_NOOP("read") : QT_TR_NOOP("write"));
|
||||
|
||||
if (event.at(0) == 'B')
|
||||
prettyString << (isMiss ? QT_TR_NOOP("mispredicted") : QT_TR_NOOP("executed"));
|
||||
else
|
||||
prettyString << (isMiss ? QT_TR_NOOP("miss") : QT_TR_NOOP("access"));
|
||||
|
||||
// add original abbreviation
|
||||
prettyString << QString("(%1)").arg(event);
|
||||
|
||||
return prettyString.join(" ");
|
||||
}
|
||||
|
||||
QStringList ParseData::events() const
|
||||
{
|
||||
return d->m_events;
|
||||
}
|
||||
|
||||
void ParseData::setEvents(const QStringList &events)
|
||||
{
|
||||
d->m_events = events;
|
||||
d->m_totalCosts.fill(0, d->m_events.size());
|
||||
}
|
||||
|
||||
QString ParseData::prettyStringForPosition(const QString &position)
|
||||
{
|
||||
if (position == "line")
|
||||
return QT_TR_NOOP("Line:"); // as in: "line number"
|
||||
else if (position == "instr")
|
||||
return QT_TR_NOOP("Instruction"); // as in: "instruction address"
|
||||
return QT_TR_NOOP("Position:"); // never reached, in theory
|
||||
}
|
||||
|
||||
QStringList ParseData::positions() const
|
||||
{
|
||||
return d->m_positions;
|
||||
}
|
||||
|
||||
int ParseData::lineNumberPositionIndex() const
|
||||
{
|
||||
return d->m_lineNumberPositionIndex;
|
||||
}
|
||||
|
||||
void ParseData::setPositions(const QStringList &positions)
|
||||
{
|
||||
d->m_positions = positions;
|
||||
d->m_lineNumberPositionIndex = -1;
|
||||
for(int i = 0; i < positions.size(); ++i) {
|
||||
if (positions.at(i) == "line") {
|
||||
d->m_lineNumberPositionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quint64 ParseData::totalCost(uint event) const
|
||||
{
|
||||
return d->m_totalCosts.at(event);
|
||||
}
|
||||
|
||||
void ParseData::setTotalCost(uint event, quint64 cost)
|
||||
{
|
||||
d->m_totalCosts[event] = cost;
|
||||
}
|
||||
|
||||
QVector<const Function *> ParseData::functions(bool detectCycles) const
|
||||
{
|
||||
if (detectCycles) {
|
||||
d->cycleDetection();
|
||||
return d->m_cycleCache;
|
||||
}
|
||||
return d->m_functions;
|
||||
}
|
||||
|
||||
void ParseData::addFunction(const Function *function)
|
||||
{
|
||||
d->m_cycleCacheValid = false;
|
||||
d->m_functions.append(function);
|
||||
}
|
||||
|
||||
QString ParseData::command() const
|
||||
{
|
||||
return d->m_command;
|
||||
}
|
||||
|
||||
void ParseData::setCommand(const QString &command)
|
||||
{
|
||||
d->m_command = command;
|
||||
}
|
||||
|
||||
quint64 ParseData::pid() const
|
||||
{
|
||||
return d->m_pid;
|
||||
}
|
||||
|
||||
void ParseData::setPid(quint64 pid)
|
||||
{
|
||||
d->m_pid = pid;
|
||||
}
|
||||
|
||||
uint ParseData::part() const
|
||||
{
|
||||
return d->m_part;
|
||||
}
|
||||
|
||||
void ParseData::setPart(uint part) const
|
||||
{
|
||||
d->m_part = part;
|
||||
}
|
||||
|
||||
QStringList ParseData::descriptions() const
|
||||
{
|
||||
return d->m_descriptions;
|
||||
}
|
||||
|
||||
void ParseData::addDescription(const QString &description)
|
||||
{
|
||||
d->m_descriptions.append(description);
|
||||
}
|
||||
|
||||
void ParseData::setDescriptions(const QStringList &descriptions)
|
||||
{
|
||||
d->m_descriptions = descriptions;
|
||||
}
|
||||
|
||||
int ParseData::version() const
|
||||
{
|
||||
return d->m_version;
|
||||
}
|
||||
|
||||
void ParseData::setVersion(int version)
|
||||
{
|
||||
d->m_version = version;
|
||||
}
|
||||
|
||||
QString ParseData::creator() const
|
||||
{
|
||||
return d->m_creator;
|
||||
}
|
||||
|
||||
void ParseData::setCreator(const QString &creator)
|
||||
{
|
||||
d->m_creator = creator;
|
||||
}
|
||||
|
||||
QString ParseData::stringForObjectCompression(qint64 id) const
|
||||
{
|
||||
return d->stringForCompression(d->m_objectCompression, id);
|
||||
}
|
||||
|
||||
void ParseData::addCompressedObject(const QString &object, qint64 &id)
|
||||
{
|
||||
d->addCompressedString(d->m_objectCompression, object, id);
|
||||
}
|
||||
|
||||
QString ParseData::stringForFileCompression(qint64 id) const
|
||||
{
|
||||
return d->stringForCompression(d->m_fileCompression, id);
|
||||
}
|
||||
|
||||
void ParseData::addCompressedFile(const QString &file, qint64 &id)
|
||||
{
|
||||
d->addCompressedString(d->m_fileCompression, file, id);
|
||||
}
|
||||
|
||||
QString ParseData::stringForFunctionCompression(qint64 id) const
|
||||
{
|
||||
return d->stringForCompression(d->m_functionCompression, id);
|
||||
}
|
||||
|
||||
void ParseData::addCompressedFunction(const QString &function, qint64 &id)
|
||||
{
|
||||
d->addCompressedString(d->m_functionCompression, function, id);
|
||||
}
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
145
src/libs/valgrind/callgrind/callgrindparsedata.h
Normal file
145
src/libs/valgrind/callgrind/callgrindparsedata.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRIND_PARSEDATA_P_H
|
||||
#define LIBVALGRIND_CALLGRIND_PARSEDATA_P_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QString;
|
||||
template <typename T> class QVector;
|
||||
class QStringList;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Function;
|
||||
|
||||
/**
|
||||
* Represents all the information extracted from a callgrind data file.
|
||||
*/
|
||||
class VALGRINDSHARED_EXPORT ParseData {
|
||||
public:
|
||||
explicit ParseData();
|
||||
~ParseData();
|
||||
|
||||
static QString prettyStringForEvent(const QString &event);
|
||||
/// List of events reported in the data file.
|
||||
QStringList events() const;
|
||||
void setEvents(const QStringList &events);
|
||||
|
||||
static QString prettyStringForPosition(const QString &position);
|
||||
/// List of positions reported in the data file.
|
||||
QStringList positions() const;
|
||||
void setPositions(const QStringList &positions);
|
||||
|
||||
/// the index of the line number in @c positions()
|
||||
/// or -1 if no line numbers where reported.
|
||||
int lineNumberPositionIndex() const;
|
||||
|
||||
/**
|
||||
* Total cost of @p event reported in the data file.
|
||||
*
|
||||
* @see events()
|
||||
*/
|
||||
quint64 totalCost(uint event) const;
|
||||
void setTotalCost(uint event, quint64 cost);
|
||||
|
||||
/**
|
||||
* When @p detectCycles is set to true, the returned list will have all @c Function's in call
|
||||
* cycles replaced with @c FunctionCycle.
|
||||
*
|
||||
* @return All functions that where reported in the data file.
|
||||
*/
|
||||
QVector<const Function *> functions(bool detectCycles = false) const;
|
||||
/// NOTE: The @c ParseData will take ownership.
|
||||
void addFunction(const Function *function);
|
||||
|
||||
/// @return executed command with arguments
|
||||
QString command() const;
|
||||
void setCommand(const QString &command);
|
||||
|
||||
/// @return pid of executed command
|
||||
quint64 pid() const;
|
||||
void setPid(quint64 pid);
|
||||
|
||||
/// @return number of data, if callgrind_control --dump was used
|
||||
uint part() const;
|
||||
void setPart(uint part) const;
|
||||
|
||||
/// @return list of desc: lines in the data
|
||||
QStringList descriptions() const;
|
||||
void addDescription(const QString &description);
|
||||
void setDescriptions(const QStringList &descriptions);
|
||||
|
||||
/// @return version of the callgrind data format
|
||||
int version() const;
|
||||
void setVersion(int version);
|
||||
|
||||
/// @return creator of the data
|
||||
QString creator() const;
|
||||
void setCreator(const QString &creator);
|
||||
|
||||
/**
|
||||
* Internal name compression lookup table.
|
||||
*
|
||||
* We save the @c QString representations of the compressed data format only once here.
|
||||
* This should make sure the memory consumption doesn't skyrocket as long
|
||||
* as these strings are only displayed without applying detaching operations on them.
|
||||
*/
|
||||
|
||||
/// for Objects
|
||||
QString stringForObjectCompression(qint64 id) const;
|
||||
/// @p id if it is -1, an uncompressed string is assumed and it will be compressed internally
|
||||
void addCompressedObject(const QString &object, qint64 &id);
|
||||
|
||||
/// for Files
|
||||
QString stringForFileCompression(qint64 id) const;
|
||||
/// @p id if it is -1, an uncompressed string is assumed and it will be compressed internally
|
||||
void addCompressedFile(const QString &file, qint64 &id);
|
||||
|
||||
/// for Functions
|
||||
QString stringForFunctionCompression(qint64 id) const;
|
||||
/// @p id if it is -1, an uncompressed string is assumed and it will be compressed internally
|
||||
void addCompressedFunction(const QString &function, qint64 &id);
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LIBVALGRIND_CALLGRIND_PARSEDATA_P_H
|
||||
681
src/libs/valgrind/callgrind/callgrindparser.cpp
Normal file
681
src/libs/valgrind/callgrind/callgrindparser.cpp
Normal file
@@ -0,0 +1,681 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Instrumentation Tools
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindparser.h"
|
||||
|
||||
#include "callgrindparsedata.h"
|
||||
#include "callgrindfunctioncall.h"
|
||||
#include "callgrindcostitem.h"
|
||||
#include "callgrindfunction.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
// #define DEBUG_PARSER
|
||||
|
||||
namespace {
|
||||
|
||||
static void skipSpace(const char **current, const char *end)
|
||||
{
|
||||
const char *b = *current;
|
||||
while (b < end) {
|
||||
if (*b == ' ' || *b == '\t')
|
||||
b++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*current = b;
|
||||
}
|
||||
|
||||
// set *ok to true if at least one digit was parsed; "garbage" after the number is not considered
|
||||
// an error.
|
||||
// *current is moved to one char after the last digit
|
||||
static qint64 parseDecimal(const char **current, const char *end, bool *ok)
|
||||
{
|
||||
const char *b = *current;
|
||||
bool parsedDigit = false;
|
||||
qint64 ret = 0;
|
||||
while (b < end) {
|
||||
const char c = *b;
|
||||
if (c >= '0' && c <= '9') {
|
||||
b++;
|
||||
ret *= 10;
|
||||
ret += c - '0';
|
||||
parsedDigit = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*ok = parsedDigit;
|
||||
*current = b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//like parseDecimal, but for 0xabcd-style hex encoding (without the leading 0x)
|
||||
static qint64 parseHex(const char **current, const char *end, bool *ok)
|
||||
{
|
||||
const char *b = *current;
|
||||
bool parsedDigit = false;
|
||||
qint64 ret = 0;
|
||||
while (b < end) {
|
||||
char c = *b;
|
||||
if (c >= '0' && c <= '9')
|
||||
c &= 0x0f;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
c = c - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
b++;
|
||||
ret <<= 4;
|
||||
ret += c;
|
||||
parsedDigit = true;
|
||||
}
|
||||
|
||||
*ok = parsedDigit;
|
||||
*current = b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static quint64 parseAddr(const char **current, const char *end, bool *ok)
|
||||
{
|
||||
if (**current == '0' && *(*current + 1) == 'x') {
|
||||
*current += 2;
|
||||
return parseHex(current, end, ok);
|
||||
} else {
|
||||
return parseDecimal(current, end, ok);
|
||||
}
|
||||
}
|
||||
|
||||
// this function expects that *current already points one past the opening parenthesis
|
||||
static int parseNameShorthand(const char **current, const char *end)
|
||||
{
|
||||
bool ok;
|
||||
int ret = parseDecimal(current, end, &ok);
|
||||
if (ok) {
|
||||
if (**current == ')') {
|
||||
(*current)++;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return -1; // invalid
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Parser::Private
|
||||
{
|
||||
Parser *const q;
|
||||
public:
|
||||
|
||||
explicit Private(Parser *qq)
|
||||
: q(qq),
|
||||
addressValuesCount(0),
|
||||
costValuesCount(0),
|
||||
data(0),
|
||||
currentFunction(0),
|
||||
lastObject(-1),
|
||||
lastFile(-1),
|
||||
currentDifferingFile(-1),
|
||||
isParsingFunctionCall(false),
|
||||
callsCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
void parse(QIODevice *device);
|
||||
void parseHeader(QIODevice *device);
|
||||
|
||||
typedef QPair<qint64, QString> NamePair;
|
||||
NamePair parseName(const char *begin, const char *end);
|
||||
|
||||
void dispatchLine(const QByteArray &line);
|
||||
void parseCostItem(const char *begin, const char *end);
|
||||
void parseFunction(const char *begin, const char *end);
|
||||
void parseSourceFile(const char *begin, const char *end);
|
||||
void parseDifferingSourceFile(const char *begin, const char *end);
|
||||
void parseObjectFile(const char *begin, const char *end);
|
||||
void parseCalls(const char *begin, const char *end);
|
||||
void parseCalledFunction(const char *begin, const char *end);
|
||||
void parseCalledSourceFile(const char *begin, const char *end);
|
||||
void parseCalledObjectFile(const char *begin, const char *end);
|
||||
|
||||
int addressValuesCount;
|
||||
int costValuesCount;
|
||||
|
||||
ParseData *data;
|
||||
Function *currentFunction;
|
||||
qint64 lastObject;
|
||||
qint64 lastFile;
|
||||
qint64 currentDifferingFile;
|
||||
|
||||
bool isParsingFunctionCall;
|
||||
quint64 callsCount;
|
||||
struct CallData {
|
||||
CallData()
|
||||
: calledFunction(-1)
|
||||
, calledObject(-1)
|
||||
, calledFile(-1)
|
||||
, call(0)
|
||||
{
|
||||
}
|
||||
|
||||
qint64 calledFunction;
|
||||
qint64 calledObject;
|
||||
qint64 calledFile;
|
||||
FunctionCall *call;
|
||||
};
|
||||
CallData currentCallData;
|
||||
QVector<quint64> callDestinations;
|
||||
|
||||
// we can only resolve callees after parsing the whole file so save that data here for now
|
||||
QVector<CallData> pendingCallees;
|
||||
|
||||
// id(s) for the ??? file
|
||||
QVector<quint64> unknownFiles;
|
||||
|
||||
// functions which call themselves
|
||||
QSet<Function *> recursiveFunctions;
|
||||
};
|
||||
|
||||
void Parser::Private::parse(QIODevice *device)
|
||||
{
|
||||
// be sure to clean up existing data before re-allocating
|
||||
// the callee might not have taken the parse data
|
||||
delete data;
|
||||
data = 0;
|
||||
|
||||
data = new ParseData;
|
||||
parseHeader(device);
|
||||
while (!device->atEnd()) {
|
||||
QByteArray line = device->readLine();
|
||||
// empty lines actually have no meaning - only fn= starts a new function
|
||||
if (line.length() > 1)
|
||||
dispatchLine(line);
|
||||
}
|
||||
|
||||
// build fast lookup of functions by their nameId
|
||||
QHash<qint64, QList<const Function *> > functionLookup;
|
||||
foreach(const Function *function, data->functions()) {
|
||||
functionLookup[function->nameId()].append(function);
|
||||
}
|
||||
|
||||
// functions that need to accumulate their calees
|
||||
QSet<Function *> pendingFunctions;
|
||||
foreach(const CallData &callData, pendingCallees) {
|
||||
Function *calledFunction = 0;
|
||||
QTC_ASSERT(callData.call, continue);
|
||||
QTC_ASSERT(callData.call->caller(), continue);
|
||||
foreach(const Function *function, functionLookup.value(callData.calledFunction)) {
|
||||
QTC_ASSERT(function->nameId() == callData.calledFunction, continue);
|
||||
if (function->objectId() == callData.calledObject
|
||||
&& function->fileId() == callData.calledFile)
|
||||
{
|
||||
calledFunction = const_cast<Function *>(function);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_PARSER
|
||||
if (!calledFunction) {
|
||||
qDebug() << unknownFiles;
|
||||
qDebug() << "could not find called function:" << data->stringForFunctionCompression(callData.calledFunction) << callData.calledFunction;
|
||||
qDebug() << "caller is:" << callData.call->caller()->name() << callData.call->caller()->nameId();
|
||||
qDebug() << "called file:" << callData.calledFile << "object:" << callData.calledObject;
|
||||
qDebug() << data->stringForFileCompression(callData.calledFile) << data->stringForObjectCompression(callData.calledObject);
|
||||
foreach(const Function *function, functionLookup.value(callData.calledFunction)) {
|
||||
qDebug() << "available function file:" << function->fileId() << function->file() << "object:" << function->objectId() << function->object();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
QTC_ASSERT(calledFunction, continue)
|
||||
callData.call->setCallee(calledFunction);
|
||||
calledFunction->addIncomingCall(callData.call);
|
||||
|
||||
Function *caller = const_cast<Function *>(callData.call->caller());
|
||||
caller->addOutgoingCall(callData.call);
|
||||
pendingFunctions.insert(caller);
|
||||
}
|
||||
|
||||
pendingCallees.clear();
|
||||
// lookup done
|
||||
|
||||
// now accumulate callees
|
||||
foreach(Function *func, pendingFunctions)
|
||||
func->finalize();
|
||||
|
||||
q->parserDataReady(); // emit
|
||||
}
|
||||
|
||||
inline QString getValue(const QByteArray &line, const int prefixLength)
|
||||
{
|
||||
// we are not interested in the trailing newline
|
||||
// TODO: \r\n ?
|
||||
return QString::fromLatin1(line.mid(prefixLength, line.length() - 1 - prefixLength).constData());
|
||||
}
|
||||
|
||||
void Parser::Private::parseHeader(QIODevice *device)
|
||||
{
|
||||
QTC_ASSERT(device->isOpen(), return);
|
||||
QTC_ASSERT(device->isReadable(), return);
|
||||
|
||||
// parse expected headers until we hit the first non-empty line
|
||||
while (!device->atEnd()) {
|
||||
QByteArray line = device->readLine();
|
||||
|
||||
// now that we're done checking if we're done (heh) with the header, parse the address
|
||||
// and cost column descriptions. speed is unimportant here.
|
||||
if (line.startsWith("positions: ")) {
|
||||
QString values = getValue(line, 11);
|
||||
data->setPositions(values.split(QLatin1Char(' '), QString::SkipEmptyParts));
|
||||
addressValuesCount = data->positions().count();
|
||||
} else if (line.startsWith("events: ")) {
|
||||
QString values = getValue(line, 8);
|
||||
data->setEvents(values.split(QLatin1Char(' '), QString::SkipEmptyParts));
|
||||
costValuesCount = data->events().count();
|
||||
} else if (line.startsWith("version: ")) {
|
||||
QString value = getValue(line, 9);
|
||||
data->setVersion(value.toInt());
|
||||
} else if (line.startsWith("creator: ")) {
|
||||
QString value = getValue(line, 9);
|
||||
data->setCreator(value);
|
||||
} else if (line.startsWith("pid: ")) {
|
||||
QString value = getValue(line, 5);
|
||||
data->setPid(value.toULongLong());
|
||||
} else if (line.startsWith("cmd: ")) {
|
||||
QString value = getValue(line, 5);
|
||||
data->setCommand(value);
|
||||
} else if (line.startsWith("part: ")) {
|
||||
QString value = getValue(line, 6);
|
||||
data->setPart(value.toUInt());
|
||||
} else if (line.startsWith("desc: ")) {
|
||||
QString value = getValue(line, 6);
|
||||
data->addDescription(value);
|
||||
} else if (line.startsWith("summary: ")) {
|
||||
QString values = getValue(line, 9);
|
||||
uint i = 0;
|
||||
foreach(const QString value, values.split(QLatin1Char(' '), QString::SkipEmptyParts))
|
||||
data->setTotalCost(i++, value.toULongLong());
|
||||
} else if (!line.trimmed().isEmpty()) {
|
||||
// handle line and exit parseHeader
|
||||
dispatchLine(line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Parser::Private::NamePair Parser::Private::parseName(const char *begin, const char *end)
|
||||
{
|
||||
const char *current = begin;
|
||||
qint64 nameShorthand = -1;
|
||||
if (*current == '(') {
|
||||
current++;
|
||||
if ((nameShorthand = parseNameShorthand(¤t, end)) == -1)
|
||||
return qMakePair(qint64(-1), QString()); // error
|
||||
}
|
||||
|
||||
skipSpace(¤t, end);
|
||||
return qMakePair(nameShorthand, QString::fromUtf8(QByteArray(current, end - current)));
|
||||
}
|
||||
|
||||
/*
|
||||
* fl means source file
|
||||
* ob means object file
|
||||
* fn means function
|
||||
* fe, fi means different source file
|
||||
* cfi or cfl means called source file
|
||||
* cob means called object file
|
||||
* cfn means called function
|
||||
*/
|
||||
|
||||
void Parser::Private::dispatchLine(const QByteArray &line)
|
||||
{
|
||||
const char *const begin = line.constData();
|
||||
const char *const end = begin + line.length() - 1; // we're not interested in the '\n'
|
||||
const char *current = begin;
|
||||
|
||||
// shortest possible line is "1 1" - a cost item line
|
||||
QTC_ASSERT(end - begin >= 3, return);
|
||||
|
||||
const char first = *begin;
|
||||
|
||||
if ((first >= '0' && first <= '9') || first == '+' || first == '*' || first =='-') {
|
||||
parseCostItem(begin, end);
|
||||
if (isParsingFunctionCall)
|
||||
isParsingFunctionCall = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QTC_ASSERT(!isParsingFunctionCall, return);
|
||||
|
||||
current++;
|
||||
const char second = *current++;
|
||||
const char third = *current++;
|
||||
// current now points to the fourth char...
|
||||
|
||||
if (first == 'c') {
|
||||
// information about a callee
|
||||
const char fourth = *current++;
|
||||
// current now points to the fifth char...
|
||||
|
||||
switch (second) {
|
||||
// comments show the shortest possible line for every case
|
||||
case 'a':
|
||||
{
|
||||
// "calls=1 1", length 9
|
||||
QTC_ASSERT(end - begin >= 9, return);
|
||||
const char fifth = *current++;
|
||||
const char sixth = *current++;
|
||||
if (third == 'l' && fourth == 'l' && fifth == 's' && sixth == '=')
|
||||
parseCalls(current, end);
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
QTC_ASSERT(end - begin >= 5, return);
|
||||
// "cfi=a" / "cfl=a", length 5
|
||||
// "cfn=a", length 5
|
||||
if (fourth == '=') {
|
||||
if (third == 'i' || third == 'l')
|
||||
parseCalledSourceFile(current, end);
|
||||
else if (third == 'n')
|
||||
parseCalledFunction(current, end);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
QTC_ASSERT(end - begin >= 5, return);
|
||||
// "cob=a", length 5
|
||||
if (third == 'b' && fourth == '=')
|
||||
parseCalledObjectFile(current, end);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// information about this function
|
||||
// shortest possible line is always four chars here, of the type "fl=a"
|
||||
QTC_ASSERT(end - begin >= 4, return);
|
||||
if (third == '=') {
|
||||
if (first == 'f') {
|
||||
if (second == 'l')
|
||||
parseSourceFile(current, end);
|
||||
else if (second == 'n')
|
||||
parseFunction(current, end);
|
||||
else if (second == 'i' || second == 'e')
|
||||
parseDifferingSourceFile(current, end);
|
||||
} else if (first == 'o' && second == 'b') {
|
||||
parseObjectFile(current, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::Private::parseCostItem(const char *begin, const char *end)
|
||||
{
|
||||
QTC_ASSERT(currentFunction, return);
|
||||
|
||||
bool ok;
|
||||
const char *current = begin;
|
||||
|
||||
CostItem *costItem = new CostItem(data);
|
||||
QTC_ASSERT(currentDifferingFile == -1 || currentDifferingFile != currentFunction->fileId(), return);
|
||||
costItem->setDifferingFile(currentDifferingFile);
|
||||
FunctionCall *call = 0;
|
||||
if (isParsingFunctionCall) {
|
||||
call = new FunctionCall;
|
||||
call->setCaller(currentFunction);
|
||||
|
||||
currentCallData.call = call;
|
||||
costItem->setCall(call);
|
||||
call->setCalls(callsCount);
|
||||
callsCount = 0;
|
||||
|
||||
call->setDestinations(callDestinations);
|
||||
callDestinations.clear();
|
||||
|
||||
if (currentCallData.calledFile == -1) {
|
||||
currentCallData.calledFile = currentDifferingFile != -1 ? currentDifferingFile : lastFile;
|
||||
//HACK: workaround issue where sometimes fi=??? lines are prepended to function calls
|
||||
if (unknownFiles.contains(currentCallData.calledFile))
|
||||
currentCallData.calledFile = lastFile;
|
||||
}
|
||||
if (currentCallData.calledObject == -1)
|
||||
currentCallData.calledObject = lastObject;
|
||||
|
||||
|
||||
if (currentCallData.calledFunction == currentFunction->nameId() &&
|
||||
currentCallData.calledFile == currentFunction->fileId() &&
|
||||
currentCallData.calledObject == currentFunction->objectId() )
|
||||
{
|
||||
// recursive call,
|
||||
recursiveFunctions << currentFunction;
|
||||
}
|
||||
|
||||
pendingCallees.append(currentCallData);
|
||||
currentCallData = CallData();
|
||||
}
|
||||
|
||||
const CostItem *lastCostItem = 0;
|
||||
if (!currentFunction->costItems().isEmpty())
|
||||
lastCostItem = currentFunction->costItems().last();
|
||||
|
||||
// parse positions ("where")
|
||||
for (int i = 0; i < addressValuesCount; ++i) {
|
||||
char c = *current;
|
||||
// TODO overflow checks
|
||||
quint64 position = 0;
|
||||
if (c == '*') {
|
||||
// leave the old value unchanged
|
||||
current++;
|
||||
QTC_ASSERT(lastCostItem, continue);
|
||||
position = lastCostItem->position(i);
|
||||
} else {
|
||||
if (c == '+' || c == '-')
|
||||
current++;
|
||||
|
||||
quint64 addr = parseAddr(¤t, end, &ok);
|
||||
|
||||
if (!ok)
|
||||
break; /// TODO: error reporting
|
||||
|
||||
if (c == '+') {
|
||||
QTC_ASSERT(lastCostItem, continue);
|
||||
position = lastCostItem->position(i) + addr;
|
||||
} else if (c == '-') {
|
||||
QTC_ASSERT(lastCostItem, continue);
|
||||
position = lastCostItem->position(i) - addr;
|
||||
} else
|
||||
position = addr;
|
||||
}
|
||||
costItem->setPosition(i, position);
|
||||
skipSpace(¤t, end);
|
||||
}
|
||||
|
||||
// parse events ("what")
|
||||
for (int i = 0; i < costValuesCount; ++i) {
|
||||
quint64 parsedCost = parseDecimal(¤t, end, &ok);
|
||||
if (!ok)
|
||||
break; /// TODO: error reporting
|
||||
costItem->setCost(i, parsedCost);
|
||||
skipSpace(¤t, end);
|
||||
}
|
||||
|
||||
if (call) {
|
||||
call->setCosts(costItem->costs());
|
||||
}
|
||||
|
||||
currentFunction->addCostItem(costItem);
|
||||
}
|
||||
|
||||
void Parser::Private::parseSourceFile(const char *begin, const char *end)
|
||||
{
|
||||
NamePair name = parseName(begin, end);
|
||||
|
||||
if (!name.second.isEmpty()) {
|
||||
data->addCompressedFile(name.second, name.first);
|
||||
if (name.second == QLatin1String("???"))
|
||||
unknownFiles << name.first;
|
||||
}
|
||||
|
||||
lastFile = name.first;
|
||||
currentDifferingFile = -1;
|
||||
}
|
||||
|
||||
void Parser::Private::parseFunction(const char *begin, const char *end)
|
||||
{
|
||||
currentFunction = new Function(data);
|
||||
currentFunction->setFile(lastFile);
|
||||
currentFunction->setObject(lastObject);
|
||||
|
||||
data->addFunction(currentFunction);
|
||||
|
||||
NamePair name = parseName(begin, end);
|
||||
|
||||
if (!name.second.isEmpty())
|
||||
data->addCompressedFunction(name.second, name.first);
|
||||
|
||||
currentFunction->setName(name.first);
|
||||
}
|
||||
|
||||
void Parser::Private::parseDifferingSourceFile(const char *begin, const char *end)
|
||||
{
|
||||
NamePair name = parseName(begin, end);
|
||||
|
||||
if (!name.second.isEmpty()) {
|
||||
data->addCompressedFile(name.second, name.first);
|
||||
if (name.second == QLatin1String("???"))
|
||||
unknownFiles << name.first;
|
||||
}
|
||||
|
||||
if (name.first == currentFunction->fileId())
|
||||
currentDifferingFile = -1;
|
||||
else
|
||||
currentDifferingFile = name.first;
|
||||
}
|
||||
|
||||
void Parser::Private::parseObjectFile(const char *begin, const char *end)
|
||||
{
|
||||
NamePair name = parseName(begin, end);
|
||||
if (!name.second.isEmpty())
|
||||
data->addCompressedObject(name.second, name.first);
|
||||
|
||||
lastObject = name.first;
|
||||
}
|
||||
|
||||
void Parser::Private::parseCalls(const char *begin, const char *end)
|
||||
{
|
||||
const char *current = begin;
|
||||
bool ok;
|
||||
callsCount = parseDecimal(¤t, end, &ok);
|
||||
skipSpace(¤t, end);
|
||||
|
||||
callDestinations.fill(0, addressValuesCount);
|
||||
for(int i = 0; i < addressValuesCount; ++i) {
|
||||
callDestinations[i] = parseAddr(¤t, end, &ok);
|
||||
if (!ok)
|
||||
break; // TODO error handling?
|
||||
skipSpace(¤t, end);
|
||||
}
|
||||
|
||||
isParsingFunctionCall = true;
|
||||
}
|
||||
|
||||
void Parser::Private::parseCalledFunction(const char *begin, const char *end)
|
||||
{
|
||||
NamePair name = parseName(begin, end);
|
||||
if (!name.second.isEmpty())
|
||||
data->addCompressedFunction(name.second, name.first);
|
||||
|
||||
currentCallData.calledFunction = name.first;
|
||||
}
|
||||
|
||||
void Parser::Private::parseCalledSourceFile(const char *begin, const char *end)
|
||||
{
|
||||
NamePair name = parseName(begin, end);
|
||||
if (!name.second.isEmpty()) {
|
||||
data->addCompressedFile(name.second, name.first);
|
||||
if (name.second == QLatin1String("???"))
|
||||
unknownFiles << name.first;
|
||||
}
|
||||
|
||||
currentCallData.calledFile = name.first;
|
||||
}
|
||||
|
||||
void Parser::Private::parseCalledObjectFile(const char *begin, const char *end)
|
||||
{
|
||||
NamePair name = parseName(begin, end);
|
||||
if (!name.second.isEmpty())
|
||||
data->addCompressedObject(name.second, name.first);
|
||||
|
||||
currentCallData.calledObject = name.first;
|
||||
}
|
||||
|
||||
//BEGIN Parser
|
||||
|
||||
void Parser::parse(QIODevice *device)
|
||||
{
|
||||
d->parse(device);
|
||||
}
|
||||
|
||||
Parser::Parser(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Parser::~Parser()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ParseData *Parser::takeData()
|
||||
{
|
||||
ParseData *data = d->data;
|
||||
d->data = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
} //Callgrind
|
||||
} //Valgrind
|
||||
85
src/libs/valgrind/callgrind/callgrindparser.h
Normal file
85
src/libs/valgrind/callgrind/callgrindparser.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Instrumentation Tools
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LIBVALGRIND_CALLGRIND_PARSER_H
|
||||
#define LIBVALGRIND_CALLGRIND_PARSER_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QIODevice;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class ParseData;
|
||||
|
||||
/**
|
||||
* Parser for Valgrind --tool=callgrind output
|
||||
* most of the format is documented at http://kcachegrind.sourceforge.net/html/CallgrindFormat.html
|
||||
*
|
||||
* FIXME: most length asserts are not correct, see documentation 1.2:
|
||||
* "If a cost line specifies less event counts than given in the "events" line,
|
||||
* the rest is assumed to be zero."
|
||||
*
|
||||
*/
|
||||
class VALGRINDSHARED_EXPORT Parser : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Parser(QObject *parent=0);
|
||||
~Parser();
|
||||
|
||||
// get and take ownership of the parsing results. If this method is not called the repository
|
||||
// will be destroyed when the parser is destroyed. Subsequent calls return null.
|
||||
ParseData *takeData();
|
||||
|
||||
signals:
|
||||
void parserDataReady();
|
||||
|
||||
public Q_SLOTS:
|
||||
void parse(QIODevice *stream);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Parser)
|
||||
|
||||
class Private;
|
||||
Private *const d;
|
||||
};
|
||||
|
||||
} // Callgrind
|
||||
} // Valgrind
|
||||
|
||||
#endif //LIBVALGRIND_CALLGRIND_PARSER_H
|
||||
162
src/libs/valgrind/callgrind/callgrindproxymodel.cpp
Normal file
162
src/libs/valgrind/callgrind/callgrindproxymodel.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Analyzer Tools
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindproxymodel.h"
|
||||
|
||||
#include "callgrinddatamodel.h"
|
||||
#include "callgrindfunction.h"
|
||||
#include "callgrindfunctioncall.h"
|
||||
#include "callgrindparsedata.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Valgrind::Callgrind;
|
||||
|
||||
DataProxyModel::DataProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_function(0)
|
||||
, m_maxRows(0)
|
||||
, m_minimumInclusiveCostRatio(0.0)
|
||||
{
|
||||
setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
const Function *DataProxyModel::filterFunction() const
|
||||
{
|
||||
return m_function;
|
||||
}
|
||||
|
||||
void DataProxyModel::setFilterBaseDir ( const QString &baseDir )
|
||||
{
|
||||
if (m_baseDir == baseDir)
|
||||
return;
|
||||
|
||||
m_baseDir = baseDir;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void DataProxyModel::setFilterFunction(const Function *function)
|
||||
{
|
||||
if (m_function == function)
|
||||
return;
|
||||
|
||||
const Function *previousFunction = m_function;
|
||||
m_function = function;
|
||||
invalidateFilter();
|
||||
emit filterFunctionChanged(previousFunction, function);
|
||||
}
|
||||
|
||||
void DataProxyModel::setFilterMaximumRows(int rows)
|
||||
{
|
||||
if (m_maxRows == rows)
|
||||
return;
|
||||
|
||||
m_maxRows = rows;
|
||||
invalidateFilter();
|
||||
emit filterMaximumRowsChanged(rows);
|
||||
}
|
||||
|
||||
void DataProxyModel::setMinimumInclusiveCostRatio(double minimumInclusiveCost)
|
||||
{
|
||||
if (m_minimumInclusiveCostRatio == minimumInclusiveCost)
|
||||
return;
|
||||
|
||||
m_minimumInclusiveCostRatio = minimumInclusiveCost;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void DataProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
if (!qobject_cast<DataModel *>(sourceModel)) {
|
||||
qWarning() << Q_FUNC_INFO << "accepts DataModel instances only";
|
||||
return;
|
||||
}
|
||||
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
DataModel *DataProxyModel::dataModel() const
|
||||
{
|
||||
return qobject_cast<DataModel *>(sourceModel());
|
||||
}
|
||||
|
||||
bool DataProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
const QModelIndex source_index = sourceModel()->index( source_row, 0, source_parent );
|
||||
if (!source_index.isValid())
|
||||
return false;
|
||||
|
||||
// if the filter regexp is a non-empty string, ignore our filters
|
||||
if (!filterRegExp().isEmpty()) {
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
|
||||
// check max rows
|
||||
if (m_maxRows > 0 && source_row > m_maxRows)
|
||||
return false;
|
||||
|
||||
const Function *func = source_index.data(DataModel::FunctionRole).value<const Function *>();
|
||||
|
||||
// check if func is located in the specific base directory, if any
|
||||
if (func && !m_baseDir.isEmpty()) {
|
||||
if (!func->location().startsWith(m_baseDir))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if the function from this index is a child of (called by) the filter function
|
||||
if (func && m_function) {
|
||||
bool isValid = false;
|
||||
foreach(const FunctionCall *call, func->incomingCalls()) {
|
||||
if (call->caller() == m_function) {
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check minimum inclusive costs
|
||||
DataModel *model = dataModel();
|
||||
QTC_ASSERT(model, return false) // as always: this should never happen
|
||||
const ParseData *data = model->parseData();
|
||||
QTC_ASSERT(data, return false)
|
||||
if (m_minimumInclusiveCostRatio != 0.0) {
|
||||
const quint64 totalCost = data->totalCost(0);
|
||||
const quint64 inclusiveCost = func->inclusiveCost(0);
|
||||
const float inclusiveCostRatio = (float)inclusiveCost / totalCost;
|
||||
if (inclusiveCostRatio < m_minimumInclusiveCostRatio)
|
||||
return false;
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
88
src/libs/valgrind/callgrind/callgrindproxymodel.h
Normal file
88
src/libs/valgrind/callgrind/callgrindproxymodel.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Analyzer Tools
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef VALGRIND_CALLGRIND_CALLGRINDPROXYMODEL_H
|
||||
#define VALGRIND_CALLGRIND_CALLGRINDPROXYMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class DataModel;
|
||||
class Function;
|
||||
|
||||
class VALGRINDSHARED_EXPORT DataProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DataProxyModel(QObject *parent = 0);
|
||||
|
||||
virtual void setSourceModel(QAbstractItemModel *sourceModel);
|
||||
|
||||
QString filterBaseDir() const { return m_baseDir; }
|
||||
const Function *filterFunction() const;
|
||||
int filterMaximumRows() const { return m_maxRows; }
|
||||
|
||||
/// Only functions with an inclusive cost ratio above this minimum will be shown in the model
|
||||
double minimumInclusiveCostRatio() const { return m_minimumInclusiveCostRatio; }
|
||||
|
||||
public Q_SLOTS:
|
||||
/// This will filter out all entries that are not located within \param baseDir
|
||||
void setFilterBaseDir(const QString& baseDir);
|
||||
void setFilterFunction(const Function *call);
|
||||
void setFilterMaximumRows(int rows);
|
||||
|
||||
/// Only rows with a inclusive cost ratio above @p minimumInclusiveCost will be shown
|
||||
/// by this model. If @c 0 is passed as argument, all rows will be shown.
|
||||
void setMinimumInclusiveCostRatio(double minimumInclusiveCost);
|
||||
|
||||
Q_SIGNALS:
|
||||
void filterFunctionChanged(const Function *previous, const Function *current);
|
||||
void filterMaximumRowsChanged(int rows);
|
||||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
|
||||
|
||||
private:
|
||||
DataModel *dataModel() const;
|
||||
|
||||
QString m_baseDir;
|
||||
const Function *m_function;
|
||||
int m_maxRows;
|
||||
double m_minimumInclusiveCostRatio;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALGRIND_CALLGRIND_CALLGRINDPROXYMODEL_H
|
||||
134
src/libs/valgrind/callgrind/callgrindrunner.cpp
Normal file
134
src/libs/valgrind/callgrind/callgrindrunner.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindrunner.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include "callgrindparser.h"
|
||||
|
||||
using namespace Valgrind::Callgrind;
|
||||
|
||||
CallgrindRunner::CallgrindRunner(QObject *parent)
|
||||
: ValgrindRunner(parent)
|
||||
, m_controller(new CallgrindController(this))
|
||||
, m_parser(new Parser(this))
|
||||
, m_paused(false)
|
||||
{
|
||||
connect(m_controller,
|
||||
SIGNAL(finished(Valgrind::Callgrind::CallgrindController::Option)),
|
||||
SLOT(controllerFinished(Valgrind::Callgrind::CallgrindController::Option)));
|
||||
connect(m_controller, SIGNAL(localParseDataAvailable(QString)),
|
||||
this, SLOT(localParseDataAvailable(QString)));
|
||||
connect(m_controller, SIGNAL(statusMessage(QString)),
|
||||
this, SIGNAL(statusMessage(QString)));
|
||||
}
|
||||
|
||||
QString CallgrindRunner::tool() const
|
||||
{
|
||||
return QString("callgrind");
|
||||
}
|
||||
|
||||
Parser *CallgrindRunner::parser() const
|
||||
{
|
||||
return m_parser;
|
||||
}
|
||||
|
||||
CallgrindController *CallgrindRunner::controller() const
|
||||
{
|
||||
return m_controller;
|
||||
}
|
||||
|
||||
void CallgrindRunner::start()
|
||||
{
|
||||
ValgrindRunner::start();
|
||||
m_controller->setValgrindProcess(valgrindProcess());
|
||||
}
|
||||
|
||||
void CallgrindRunner::startRemotely(const Utils::SshConnectionParameters &sshParams)
|
||||
{
|
||||
ValgrindRunner::startRemotely(sshParams);
|
||||
m_controller->setValgrindProcess(valgrindProcess());
|
||||
}
|
||||
|
||||
void CallgrindRunner::processFinished(int ret, QProcess::ExitStatus status)
|
||||
{
|
||||
triggerParse();
|
||||
m_controller->setValgrindProcess(0);
|
||||
|
||||
ValgrindRunner::processFinished(ret, status); // call base class method
|
||||
}
|
||||
|
||||
bool CallgrindRunner::isPaused() const
|
||||
{
|
||||
return m_paused;
|
||||
}
|
||||
|
||||
void CallgrindRunner::triggerParse()
|
||||
{
|
||||
m_controller->getLocalDataFile();
|
||||
}
|
||||
|
||||
void CallgrindRunner::localParseDataAvailable(const QString &file)
|
||||
{
|
||||
// parse the callgrind file
|
||||
QTC_ASSERT(!file.isEmpty(), return);
|
||||
QFile outputFile(file);
|
||||
QTC_ASSERT(outputFile.exists(), return);
|
||||
if (outputFile.open(QIODevice::ReadOnly)) {
|
||||
emit statusMessage(tr("Parsing Profile Data..."));
|
||||
m_parser->parse(&outputFile);
|
||||
} else {
|
||||
qWarning() << "Could not open file for parsing:" << outputFile.fileName();
|
||||
}
|
||||
}
|
||||
|
||||
void CallgrindRunner::controllerFinished(CallgrindController::Option option)
|
||||
{
|
||||
switch(option)
|
||||
{
|
||||
case CallgrindController::Pause:
|
||||
m_paused = true;
|
||||
break;
|
||||
case CallgrindController::UnPause:
|
||||
m_paused = false;
|
||||
break;
|
||||
case CallgrindController::Dump:
|
||||
triggerParse();
|
||||
break;
|
||||
default:
|
||||
break; // do nothing
|
||||
}
|
||||
}
|
||||
88
src/libs/valgrind/callgrind/callgrindrunner.h
Normal file
88
src/libs/valgrind/callgrind/callgrindrunner.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** No Commercial Usage
|
||||
**
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef VALGRIND_CALLGRIND_CALLGRINDRUNNER_H
|
||||
#define VALGRIND_CALLGRIND_CALLGRINDRUNNER_H
|
||||
|
||||
#include <valgrind/valgrindrunner.h>
|
||||
#include <valgrind/valgrind_global.h>
|
||||
|
||||
#include "callgrindcontroller.h"
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Parser;
|
||||
class CallgrindController;
|
||||
|
||||
class VALGRINDSHARED_EXPORT CallgrindRunner : public ValgrindRunner
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CallgrindRunner(QObject *parent = 0);
|
||||
|
||||
Parser *parser() const;
|
||||
|
||||
CallgrindController *controller() const;
|
||||
|
||||
bool isPaused() const;
|
||||
|
||||
virtual void start();
|
||||
virtual void startRemotely(const Utils::SshConnectionParameters &sshParams);
|
||||
|
||||
signals:
|
||||
void statusMessage(const QString &message);
|
||||
|
||||
private slots:
|
||||
void localParseDataAvailable(const QString &file);
|
||||
|
||||
void controllerFinished(Valgrind::Callgrind::CallgrindController::Option);
|
||||
|
||||
void processFinished(int, QProcess::ExitStatus);
|
||||
|
||||
private:
|
||||
void triggerParse();
|
||||
|
||||
QString tool() const;
|
||||
|
||||
CallgrindController *m_controller;
|
||||
Parser *m_parser;
|
||||
|
||||
bool m_paused;
|
||||
};
|
||||
|
||||
} // namespace Callgrind
|
||||
} // namespace Valgrind
|
||||
|
||||
#endif // VALGRIND_CALLGRIND_CALLGRINDRUNNER_H
|
||||
101
src/libs/valgrind/callgrind/callgrindstackbrowser.cpp
Normal file
101
src/libs/valgrind/callgrind/callgrindstackbrowser.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Analyzer Tools
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "callgrindstackbrowser.h"
|
||||
|
||||
using namespace Valgrind::Callgrind;
|
||||
|
||||
HistoryItem::HistoryItem(StackBrowser *stack)
|
||||
{
|
||||
if (stack)
|
||||
stack->select(this);
|
||||
}
|
||||
|
||||
HistoryItem::~HistoryItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
FunctionHistoryItem::FunctionHistoryItem(const Function *function, StackBrowser *stack)
|
||||
: HistoryItem(stack)
|
||||
, m_function(function)
|
||||
{
|
||||
}
|
||||
|
||||
FunctionHistoryItem::~FunctionHistoryItem()
|
||||
{
|
||||
}
|
||||
|
||||
StackBrowser::StackBrowser(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
StackBrowser::~StackBrowser()
|
||||
{
|
||||
qDeleteAll(m_stack);
|
||||
m_stack.clear();
|
||||
}
|
||||
|
||||
void StackBrowser::clear()
|
||||
{
|
||||
qDeleteAll(m_stack);
|
||||
m_stack.clear();
|
||||
emit currentChanged();
|
||||
}
|
||||
|
||||
int StackBrowser::size() const
|
||||
{
|
||||
return m_stack.size();
|
||||
}
|
||||
|
||||
void StackBrowser::select(HistoryItem *item)
|
||||
{
|
||||
if (!m_stack.isEmpty() && m_stack.top() == item)
|
||||
return;
|
||||
|
||||
m_stack.push(item);
|
||||
emit currentChanged();
|
||||
}
|
||||
|
||||
HistoryItem *StackBrowser::current() const
|
||||
{
|
||||
return m_stack.isEmpty() ? 0 : m_stack.top();
|
||||
}
|
||||
|
||||
void StackBrowser::goBack()
|
||||
{
|
||||
if (m_stack.isEmpty())
|
||||
return;
|
||||
|
||||
HistoryItem *item = m_stack.pop();
|
||||
delete item;
|
||||
emit currentChanged();
|
||||
}
|
||||
90
src/libs/valgrind/callgrind/callgrindstackbrowser.h
Normal file
90
src/libs/valgrind/callgrind/callgrindstackbrowser.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator Analyzer Tools
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CALLGRINDSTACKBROWSER_H
|
||||
#define CALLGRINDSTACKBROWSER_H
|
||||
|
||||
#include "../valgrind_global.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QStack>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
class Function;
|
||||
class StackBrowser;
|
||||
|
||||
class VALGRINDSHARED_EXPORT HistoryItem
|
||||
{
|
||||
public:
|
||||
HistoryItem(StackBrowser *stack = 0);
|
||||
virtual ~HistoryItem();
|
||||
};
|
||||
|
||||
class VALGRINDSHARED_EXPORT FunctionHistoryItem : public HistoryItem
|
||||
{
|
||||
public:
|
||||
FunctionHistoryItem(const Function *function, StackBrowser *stack = 0);
|
||||
virtual ~FunctionHistoryItem();
|
||||
|
||||
const Function *function() const { return m_function; }
|
||||
|
||||
private:
|
||||
const Function *m_function;
|
||||
};
|
||||
|
||||
class VALGRINDSHARED_EXPORT StackBrowser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit StackBrowser(QObject *parent = 0);
|
||||
virtual ~StackBrowser();
|
||||
|
||||
void select(HistoryItem *item);
|
||||
HistoryItem *current() const;
|
||||
|
||||
void clear();
|
||||
int size() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void goBack();
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentChanged();
|
||||
|
||||
private:
|
||||
QStack<HistoryItem *> m_stack;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CALLGRINDSTACKBROWSER_H
|
||||
@@ -22,6 +22,21 @@ HEADERS += valgrind_global.h \
|
||||
xmlprotocol/errorlistmodel.h \
|
||||
xmlprotocol/stackmodel.h \
|
||||
xmlprotocol/modelhelpers.h \
|
||||
callgrind/callgrindparser.h \
|
||||
callgrind/callgrindparsedata.h \
|
||||
callgrind/callgrindfunction.h \
|
||||
callgrind/callgrindfunction_p.h \
|
||||
callgrind/callgrindfunctioncycle.h \
|
||||
callgrind/callgrindfunctioncall.h \
|
||||
callgrind/callgrindcostitem.h \
|
||||
callgrind/callgrinddatamodel.h \
|
||||
callgrind/callgrindabstractmodel.h \
|
||||
callgrind/callgrindcallmodel.h \
|
||||
callgrind/callgrindcontroller.h \
|
||||
callgrind/callgrindcycledetection.h \
|
||||
callgrind/callgrindproxymodel.h \
|
||||
callgrind/callgrindstackbrowser.h \
|
||||
callgrind/callgrindrunner.h \
|
||||
memcheck/memcheckrunner.h \
|
||||
valgrindrunner.h \
|
||||
valgrindprocess.h
|
||||
@@ -37,6 +52,20 @@ SOURCES += xmlprotocol/error.cpp \
|
||||
xmlprotocol/errorlistmodel.cpp \
|
||||
xmlprotocol/stackmodel.cpp \
|
||||
xmlprotocol/modelhelpers.cpp \
|
||||
callgrind/callgrindparser.cpp \
|
||||
callgrind/callgrindparsedata.cpp \
|
||||
callgrind/callgrindfunction.cpp \
|
||||
callgrind/callgrindfunctioncycle.cpp \
|
||||
callgrind/callgrindfunctioncall.cpp \
|
||||
callgrind/callgrindcostitem.cpp \
|
||||
callgrind/callgrindabstractmodel.cpp \
|
||||
callgrind/callgrinddatamodel.cpp \
|
||||
callgrind/callgrindcallmodel.cpp \
|
||||
callgrind/callgrindcontroller.cpp \
|
||||
callgrind/callgrindcycledetection.cpp \
|
||||
callgrind/callgrindproxymodel.cpp \
|
||||
callgrind/callgrindrunner.cpp \
|
||||
callgrind/callgrindstackbrowser.cpp \
|
||||
memcheck/memcheckrunner.cpp \
|
||||
valgrindrunner.cpp \
|
||||
valgrindprocess.cpp
|
||||
|
||||
Reference in New Issue
Block a user