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/errorlistmodel.h \
|
||||||
xmlprotocol/stackmodel.h \
|
xmlprotocol/stackmodel.h \
|
||||||
xmlprotocol/modelhelpers.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 \
|
memcheck/memcheckrunner.h \
|
||||||
valgrindrunner.h \
|
valgrindrunner.h \
|
||||||
valgrindprocess.h
|
valgrindprocess.h
|
||||||
@@ -37,6 +52,20 @@ SOURCES += xmlprotocol/error.cpp \
|
|||||||
xmlprotocol/errorlistmodel.cpp \
|
xmlprotocol/errorlistmodel.cpp \
|
||||||
xmlprotocol/stackmodel.cpp \
|
xmlprotocol/stackmodel.cpp \
|
||||||
xmlprotocol/modelhelpers.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 \
|
memcheck/memcheckrunner.cpp \
|
||||||
valgrindrunner.cpp \
|
valgrindrunner.cpp \
|
||||||
valgrindprocess.cpp
|
valgrindprocess.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user