diff --git a/src/plugins/callgrind/Callgrind.pluginspec.in b/src/plugins/callgrind/Callgrind.pluginspec.in new file mode 100644 index 00000000000..e2ca63846b0 --- /dev/null +++ b/src/plugins/callgrind/Callgrind.pluginspec.in @@ -0,0 +1,22 @@ + + Nokia Corporation + (C) 2011 Nokia Corporation + +Commercial Usage + +Licensees holding valid Qt Commercial licenses may use this plugin 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 plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 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. + + Code Analyzer + Valgrind Callgrind Tool Plugin + http://qt.nokia.com + + + + + + + diff --git a/src/plugins/callgrind/callgrind.pri b/src/plugins/callgrind/callgrind.pri new file mode 100644 index 00000000000..3453c695081 --- /dev/null +++ b/src/plugins/callgrind/callgrind.pri @@ -0,0 +1,5 @@ +include(callgrind_dependencies.pri) + +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +LIBS *= -l$$qtLibraryName(Callgrind) diff --git a/src/plugins/callgrind/callgrind.pro b/src/plugins/callgrind/callgrind.pro new file mode 100644 index 00000000000..c3fd62e3478 --- /dev/null +++ b/src/plugins/callgrind/callgrind.pro @@ -0,0 +1,43 @@ +TEMPLATE = lib +TARGET = Callgrind + +DEFINES += CALLGRIND_LIBRARY + +include(../../qtcreatorplugin.pri) +include(callgrind_dependencies.pri) + +# Callgrind files + +HEADERS += \ + callgrindplugin.h \ + callgrind_global.h \ + callgrindconfigwidget.h \ + callgrindcostdelegate.h \ + callgrindcostview.h \ + callgrindhelper.h \ + callgrindnamedelegate.h \ + callgrindsettings.h \ + callgrindtool.h \ + callgrindvisualisation.h \ + callgrindwidgethandler.h \ + callgrindengine.h \ + workarounds.h \ + callgrindtextmark.h + +SOURCES += \ + callgrindplugin.cpp \ + callgrindconfigwidget.cpp \ + callgrindcostdelegate.cpp \ + callgrindcostview.cpp \ + callgrindhelper.cpp \ + callgrindnamedelegate.cpp \ + callgrindsettings.cpp \ + callgrindtool.cpp \ + callgrindvisualisation.cpp \ + callgrindwidgethandler.cpp \ + callgrindengine.cpp \ + workarounds.cpp \ + callgrindtextmark.cpp + +FORMS += \ + callgrindconfigwidget.ui diff --git a/src/plugins/callgrind/callgrind_dependencies.pri b/src/plugins/callgrind/callgrind_dependencies.pri new file mode 100644 index 00000000000..532881cea96 --- /dev/null +++ b/src/plugins/callgrind/callgrind_dependencies.pri @@ -0,0 +1,5 @@ +include(../../plugins/coreplugin/coreplugin.pri) +include(../../plugins/texteditor/texteditor.pri) +include(../../plugins/analyzerbase/analyzerbase.pri) +include(../../plugins/valgrindtoolbase/valgrindtoolbase.pri) +include(../../libs/cplusplus/cplusplus.pri) diff --git a/src/plugins/callgrind/callgrind_global.h b/src/plugins/callgrind/callgrind_global.h new file mode 100644 index 00000000000..a74f297eb9c --- /dev/null +++ b/src/plugins/callgrind/callgrind_global.h @@ -0,0 +1,45 @@ +/************************************************************************** +** +** 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 CALLGRIND_GLOBAL_H +#define CALLGRIND_GLOBAL_H + +#include + +#if defined(CALLGRIND_LIBRARY) +# define CALLGRINDSHARED_EXPORT Q_DECL_EXPORT +#else +# define CALLGRINDSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // CALLGRIND_GLOBAL_H diff --git a/src/plugins/callgrind/callgrindconfigwidget.cpp b/src/plugins/callgrind/callgrindconfigwidget.cpp new file mode 100644 index 00000000000..77cf248270f --- /dev/null +++ b/src/plugins/callgrind/callgrindconfigwidget.cpp @@ -0,0 +1,77 @@ +/************************************************************************** +** +** 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 "callgrindconfigwidget.h" + +#include "ui_callgrindconfigwidget.h" + +#include "callgrindsettings.h" + +using namespace Callgrind::Internal; + +CallgrindConfigWidget::CallgrindConfigWidget(AbstractCallgrindSettings *settings, QWidget *parent) + : QWidget(parent) + , m_ui(new Ui::CallgrindConfigWidget) + , m_settings(settings) +{ + m_ui->setupUi(this); + + m_ui->enableCacheSim->setChecked(m_settings->enableCacheSim()); + connect(m_ui->enableCacheSim, SIGNAL(toggled(bool)), + m_settings, SLOT(setEnableCacheSim(bool))); + connect(m_settings, SIGNAL(enableCacheSimChanged(bool)), + m_ui->enableCacheSim, SLOT(setChecked(bool))); + + m_ui->enableBranchSim->setChecked(m_settings->enableBranchSim()); + connect(m_ui->enableBranchSim, SIGNAL(toggled(bool)), + m_settings, SLOT(setEnableBranchSim(bool))); + connect(m_settings, SIGNAL(enableBranchSimChanged(bool)), + m_ui->enableBranchSim, SLOT(setChecked(bool))); + + m_ui->collectSystime->setChecked(m_settings->collectSystime()); + connect(m_ui->collectSystime, SIGNAL(toggled(bool)), + m_settings, SLOT(setCollectSystime(bool))); + connect(m_settings, SIGNAL(collectSystimeChanged(bool)), + m_ui->collectSystime, SLOT(setChecked(bool))); + + m_ui->collectBusEvents->setChecked(m_settings->collectBusEvents()); + connect(m_ui->collectBusEvents, SIGNAL(toggled(bool)), + m_settings, SLOT(setCollectBusEvents(bool))); + connect(m_settings, SIGNAL(collectBusEventsChanged(bool)), + m_ui->collectBusEvents, SLOT(setChecked(bool))); +} + +CallgrindConfigWidget::~CallgrindConfigWidget() +{ + delete m_ui; +} diff --git a/src/plugins/callgrind/callgrindconfigwidget.h b/src/plugins/callgrind/callgrindconfigwidget.h new file mode 100644 index 00000000000..9949c307161 --- /dev/null +++ b/src/plugins/callgrind/callgrindconfigwidget.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** 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 ANALYZER_INTERNAL_CALLGRINDCONFIGWIDGET_H +#define ANALYZER_INTERNAL_CALLGRINDCONFIGWIDGET_H + +#include + +namespace Callgrind { +namespace Internal { + +namespace Ui { +class CallgrindConfigWidget; +} + +class AbstractCallgrindSettings; + +class CallgrindConfigWidget : public QWidget +{ + Q_OBJECT + +public: + CallgrindConfigWidget(AbstractCallgrindSettings *settings, QWidget *parent); + virtual ~CallgrindConfigWidget(); + +private: + Ui::CallgrindConfigWidget *m_ui; + + AbstractCallgrindSettings *m_settings; +}; + +} +} + +#endif // ANALYZER_INTERNAL_CALLGRINDCONFIGWIDGET_H diff --git a/src/plugins/callgrind/callgrindconfigwidget.ui b/src/plugins/callgrind/callgrindconfigwidget.ui new file mode 100644 index 00000000000..8147c03ff7c --- /dev/null +++ b/src/plugins/callgrind/callgrindconfigwidget.ui @@ -0,0 +1,110 @@ + + + Callgrind::Internal::CallgrindConfigWidget + + + + 0 + 0 + 416 + 565 + + + + + + + + 0 + 0 + + + + Profiling Options + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> +<p>Specify if you want to do full cache simulation.</p> +<p>By default, only instruction read accesses will be counted ("Ir").</p> + +<p> +With cache simulation, further event counters are enabled: +<ul><li>Cache misses on instruction reads ("I1mr"/"I2mr")</li> +<li>Data read accesses ("Dr") and related cache misses ("D1mr"/"D2mr")</li> +<li>Data write accesses ("Dw") and related cache misses ("D1mw"/"D2mw")</li></ul> +</p> + +For more information, see ???.</p></body></html> + + + Enable cache simulation + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p>Specify if you want to do branch prediction simulation.</p> +<p>Further event counters are enabled: </p> +<ul><li>Number of executed conditional branches and related predictor misses ( +"Bc"/"Bcm")</li> +<li>Executed indirect jumps and related misses of the jump address predictor ( +"Bi"/"Bim")</li></ul></body></html> + + + Enable branch prediction simulation + + + + + + + This specifies whether information for system call times should be collected. + + + Collect system call time + + + + + + + This specifies whether the number of global bus events executed should be collected. The event type "Ge" is used for these events. + + + Collect global bus events + + + + + + + + + + + diff --git a/src/plugins/callgrind/callgrindconstants.h b/src/plugins/callgrind/callgrindconstants.h new file mode 100644 index 00000000000..698fb141caa --- /dev/null +++ b/src/plugins/callgrind/callgrindconstants.h @@ -0,0 +1,41 @@ +/************************************************************************** +** +** 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 CALLGRINDCONSTANTS_H +#define CALLGRINDCONSTANTS_H + +namespace Callgrind { +namespace Constants { + +const char * const A_SHOWCOSTSOFFUNCTION = "Analyzer.Callgrind.ShowCostsOfFunction"; + +} +} + +#endif // CALLGRINDCONSTANTS_H diff --git a/src/plugins/callgrind/callgrindcostdelegate.cpp b/src/plugins/callgrind/callgrindcostdelegate.cpp new file mode 100644 index 00000000000..d3336da251a --- /dev/null +++ b/src/plugins/callgrind/callgrindcostdelegate.cpp @@ -0,0 +1,192 @@ +/************************************************************************** +** +** 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 "callgrindcostdelegate.h" + +#include "callgrindcostview.h" +#include "callgrindhelper.h" + +#include +#include + +#include + +#include +#include +#include + +using namespace Valgrind::Callgrind; + +namespace Callgrind { +namespace Internal { + +//BEGIN CostDelegate::Private +class CostDelegate::Private { +public: + Private(); + ~Private(); + + Valgrind::Callgrind::AbstractModel *m_model; + CostDelegate::CostFormat m_format; + + static int toNativeRole(CostFormat format); + float relativeCost(const QModelIndex &index) const; + QString displayText(const QModelIndex &index, const QLocale &locale) const; +}; + +CostDelegate::Private::Private() +: m_model(0) +, m_format(CostDelegate::FormatAbsolute) +{ + +} + +CostDelegate::Private::~Private() +{ + +} + +int CostDelegate::Private::toNativeRole(CostDelegate::CostFormat format) +{ + switch(format) + { + case FormatAbsolute: + case FormatRelative: + return Valgrind::Callgrind::AbstractModel::RelativeTotalCostRole; + case FormatRelativeToParent: + return Valgrind::Callgrind::AbstractModel::RelativeParentCostRole; + default: + return -1; + } +} + +float CostDelegate::Private::relativeCost(const QModelIndex &index) const +{ + bool ok = false; + float cost = index.data(toNativeRole(m_format)).toFloat(&ok); + QTC_ASSERT(ok, return 0); + return cost; +} + +QString CostDelegate::Private::displayText(const QModelIndex &index, const QLocale &locale) const +{ + switch (m_format) { + case FormatAbsolute: + return locale.toString(index.data().toULongLong()); + case FormatRelative: + case FormatRelativeToParent: + if (!m_model) + break; + float cost = relativeCost(index) * 100.0f; + return CallgrindHelper::toPercent(cost, locale); + } + + return QString(); +} +//END CostDelegate::Private + +//BEGIN CostDelegate +CostDelegate::CostDelegate(QObject *parent) + : QStyledItemDelegate(parent) + , d(new Private) +{ + +} + +CostDelegate::~CostDelegate() +{ + delete d; +} + +void CostDelegate::setModel(Valgrind::Callgrind::AbstractModel *model) +{ + d->m_model = model; +} + +void CostDelegate::setFormat(CostFormat format) +{ + d->m_format = format; +} + +CostDelegate::CostFormat CostDelegate::format() const +{ + return d->m_format; +} + +void CostDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + // init + QStyleOptionViewItemV4 opt(option); + initStyleOption(&opt, index); + + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + + // draw controls, but no text + opt.text.clear(); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter); + + painter->save(); + + // draw bar + float ratio = qBound(0.0f, d->relativeCost(index), 1.0f); + QRect barRect = opt.rect; + barRect.setWidth(opt.rect.width() * ratio); + painter->setPen(Qt::NoPen); + painter->setBrush(CallgrindHelper::colorForCostRatio(ratio)); + painter->drawRect(barRect); + + // draw text + const QString text = d->displayText(index, opt.locale); + const QBrush &textBrush = (option.state & QStyle::State_Selected ? opt.palette.highlightedText() : opt.palette.text()); + painter->setBrush(Qt::NoBrush); + painter->setPen(textBrush.color()); + painter->drawText(opt.rect, Qt::AlignRight, text); + + painter->restore(); +} + +QSize CostDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt(option); + initStyleOption(&opt, index); + + const QString text = d->displayText(index, opt.locale); + const QSize size = QSize(option.fontMetrics.width(text), + option.fontMetrics.height()); + return size; +} + +} // Internal +} // Callgrind diff --git a/src/plugins/callgrind/callgrindcostdelegate.h b/src/plugins/callgrind/callgrindcostdelegate.h new file mode 100644 index 00000000000..f93349c0370 --- /dev/null +++ b/src/plugins/callgrind/callgrindcostdelegate.h @@ -0,0 +1,86 @@ +/************************************************************************** +** +** 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 CALLGRINDCOSTDELEGATE_H +#define CALLGRINDCOSTDELEGATE_H + +#include + +namespace Valgrind { +namespace Callgrind { +class AbstractModel; +} +} + +namespace Callgrind { +namespace Internal { + + +class CostDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit CostDelegate(QObject *parent = 0); + virtual ~CostDelegate(); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + + void setModel(Valgrind::Callgrind::AbstractModel *model); + + enum CostFormat { + /// show absolute numbers + FormatAbsolute, + /// show percentages relative to the total inclusive cost + FormatRelative, + /// show percentages relative to the parent cost + FormatRelativeToParent + }; + + void setFormat(CostFormat format); + CostFormat format() const; + +private: + class Private; + Private *d; +}; + + +} // Internal +} // Callgrind + +Q_DECLARE_METATYPE(Callgrind::Internal::CostDelegate::CostFormat) + +#endif // CALLGRINDCOSTDELEGATE_H diff --git a/src/plugins/callgrind/callgrindcostview.cpp b/src/plugins/callgrind/callgrindcostview.cpp new file mode 100644 index 00000000000..468d607914a --- /dev/null +++ b/src/plugins/callgrind/callgrindcostview.cpp @@ -0,0 +1,152 @@ +/************************************************************************** +** +** 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 "callgrindcostview.h" + +#include "callgrindnamedelegate.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace Valgrind::Callgrind; + +namespace Callgrind { +namespace Internal { + +//BEGIN CostView::Private + +class CostView::Private { +public: + explicit Private(CostView *qq); + ~Private(); + + CostDelegate *m_costDelegate; + NameDelegate *m_nameDelegate; +}; + +CostView::Private::Private(CostView *qq) + : m_costDelegate(new CostDelegate(qq)) + , m_nameDelegate(new NameDelegate(qq)) +{ +} + +CostView::Private::~Private() +{ +} + +//END CostView::Private + +//BEGIN CostView + +CostView::CostView(QWidget *parent) + : QTreeView(parent) + , d(new Private(this)) +{ + setSelectionMode(QAbstractItemView::ExtendedSelection); + setSelectionBehavior(QAbstractItemView::SelectRows); + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + setAutoScroll(false); + setSortingEnabled(true); + setRootIsDecorated(false); +} + +CostView::~CostView() +{ + delete d; +} + +void CostView::setModel(QAbstractItemModel *model) +{ + QTreeView::setModel(model); + + AbstractModel *abstractModel = 0; + forever { + abstractModel = dynamic_cast(model); + if (abstractModel) + break; + + QAbstractProxyModel *proxy = qobject_cast(model); + if (proxy) + model = proxy->sourceModel(); + else + break; + } + + QHeaderView *headerView = header(); + setItemDelegate(new QStyledItemDelegate(this)); + headerView->setResizeMode(QHeaderView::Interactive); + headerView->setStretchLastSection(false); + + if (dynamic_cast(abstractModel)) { + setItemDelegateForColumn(CallModel::CostColumn, d->m_costDelegate); + headerView->setResizeMode(CallModel::CostColumn, QHeaderView::ResizeToContents); + headerView->setResizeMode(CallModel::CallsColumn, QHeaderView::ResizeToContents); + headerView->setResizeMode(CallModel::CalleeColumn, QHeaderView::Stretch); + setItemDelegateForColumn(CallModel::CalleeColumn, d->m_nameDelegate); + headerView->setResizeMode(CallModel::CallerColumn, QHeaderView::Stretch); + setItemDelegateForColumn(CallModel::CallerColumn, d->m_nameDelegate); + } else if(dynamic_cast(abstractModel)) { + setItemDelegateForColumn(DataModel::SelfCostColumn, d->m_costDelegate); + headerView->setResizeMode(DataModel::SelfCostColumn, QHeaderView::ResizeToContents); + setItemDelegateForColumn(DataModel::InclusiveCostColumn, d->m_costDelegate); + headerView->setResizeMode(DataModel::InclusiveCostColumn, QHeaderView::ResizeToContents); + setItemDelegateForColumn(DataModel::NameColumn, d->m_nameDelegate); + headerView->setResizeMode(DataModel::NameColumn, QHeaderView::Stretch); + headerView->setResizeMode(DataModel::LocationColumn, QHeaderView::Stretch); + } + + d->m_costDelegate->setModel(abstractModel); +} + +void CostView::setCostFormat(CostDelegate::CostFormat format) +{ + d->m_costDelegate->setFormat(format); + viewport()->update(); +} + +CostDelegate::CostFormat CostView::costFormat() const +{ + return d->m_costDelegate->format(); +} + +//END CostView + +} // Internal +} // Callgrind diff --git a/src/plugins/callgrind/callgrindcostview.h b/src/plugins/callgrind/callgrindcostview.h new file mode 100644 index 00000000000..d30c8d9a300 --- /dev/null +++ b/src/plugins/callgrind/callgrindcostview.h @@ -0,0 +1,72 @@ +/************************************************************************** +** +** 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 CALLGRINDCOSTVIEW_H +#define CALLGRINDCOSTVIEW_H + +#include + +#include "callgrindcostdelegate.h" + +namespace Callgrind { +namespace Internal { + +class CostView : public QTreeView +{ + Q_OBJECT + +public: + explicit CostView(QWidget *parent = 0); + virtual ~CostView(); + + /** + * Overload automatically updates the cost delegate + * and sets it for the cost columns of DataModel and CallModel. + */ + virtual void setModel(QAbstractItemModel *model); + + /** + * How to format cost data columns in the view. + */ + void setCostFormat(CostDelegate::CostFormat format); + CostDelegate::CostFormat costFormat() const; + +private: + class Private; + Private *d; +}; + +} // Internal +} // Callgrind + +#endif // CALLGRINDCOSTVIEW_H \ No newline at end of file diff --git a/src/plugins/callgrind/callgrindengine.cpp b/src/plugins/callgrind/callgrindengine.cpp new file mode 100644 index 00000000000..70c399283b0 --- /dev/null +++ b/src/plugins/callgrind/callgrindengine.cpp @@ -0,0 +1,173 @@ +/************************************************************************** +** +** 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 "callgrindengine.h" + +#include "callgrindsettings.h" + +#include +#include + +#include + +#include + +using namespace Analyzer; +using namespace Callgrind; +using namespace Callgrind::Internal; + +CallgrindEngine::CallgrindEngine(const AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration) + : ValgrindEngine(sp, runConfiguration) + , m_markAsPaused(false) +{ + connect(&m_runner, SIGNAL(finished()), this, SLOT(slotFinished())); + connect(&m_runner, SIGNAL(started()), this, SLOT(slotStarted())); + + connect(m_runner.parser(), SIGNAL(parserDataReady()), this, SLOT(slotFinished())); + + connect(&m_runner, SIGNAL(statusMessage(QString)), + Analyzer::AnalyzerManager::instance(), SLOT(showStatusMessage(QString))); + + m_progress->setProgressRange(0, 2); +} + +CallgrindEngine::~CallgrindEngine() +{ +} + +QStringList CallgrindEngine::toolArguments() const +{ + QStringList arguments; + + AbstractCallgrindSettings *callgrindSettings = m_settings->subConfig(); + QTC_ASSERT(callgrindSettings, return arguments); + + if (callgrindSettings->enableCacheSim()) + arguments << "--cache-sim=yes"; + + if (callgrindSettings->enableBranchSim()) + arguments << "--branch-sim=yes"; + + if (callgrindSettings->collectBusEvents()) + arguments << "--collect-bus=yes"; + + if (callgrindSettings->collectSystime()) + arguments << "--collect-systime=yes"; + + if (m_markAsPaused) + arguments << "--instr-atstart=no"; + + // add extra arguments + arguments << extraArguments(); + + return arguments; +} + +QString CallgrindEngine::progressTitle() const +{ + return tr("Profiling"); +} + +Valgrind::ValgrindRunner * CallgrindEngine::runner() +{ + return &m_runner; +} + +void CallgrindEngine::start() +{ + emit standardOutputReceived(tr("Profiling %1").arg(executable())); + ValgrindEngine::start(); +} + +void CallgrindEngine::dump() +{ + m_runner.controller()->run(Valgrind::Callgrind::CallgrindController::Dump); +} + +void CallgrindEngine::setExtraArguments(const QStringList &extraArguments) +{ + m_extraArguments = extraArguments; +} + +void CallgrindEngine::setPaused(bool paused) +{ + if (m_markAsPaused == paused) + return; + + m_markAsPaused = paused; + + // call controller + if (paused) + pause(); + else + unpause(); +} + +void CallgrindEngine::setToggleCollectFunction(const QString &toggleCollectFunction) +{ + if (toggleCollectFunction.isEmpty()) + return; + + m_extraArguments << QString("--toggle-collect=%1").arg(toggleCollectFunction); +} + +void CallgrindEngine::reset() +{ + m_runner.controller()->run(Valgrind::Callgrind::CallgrindController::ResetEventCounters); +} + +void CallgrindEngine::pause() +{ + m_runner.controller()->run(Valgrind::Callgrind::CallgrindController::Pause); +} + +void CallgrindEngine::unpause() +{ + m_runner.controller()->run(Valgrind::Callgrind::CallgrindController::UnPause); +} + +Valgrind::Callgrind::ParseData *CallgrindEngine::takeParserData() +{ + return m_runner.parser()->takeData(); +} + +void CallgrindEngine::slotFinished() +{ + emit parserDataReady(this); +} + +void CallgrindEngine::slotStarted() +{ + m_progress->setProgressValue(1);; +} diff --git a/src/plugins/callgrind/callgrindengine.h b/src/plugins/callgrind/callgrindengine.h new file mode 100644 index 00000000000..756459c6501 --- /dev/null +++ b/src/plugins/callgrind/callgrindengine.h @@ -0,0 +1,92 @@ +/************************************************************************** +** +** 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 CALLGRINDENGINE_H +#define CALLGRINDENGINE_H + +#include + +#include +#include + +namespace Callgrind { +namespace Internal { + +class CallgrindEngine : public Valgrind::Internal::ValgrindEngine +{ + Q_OBJECT +public: + explicit CallgrindEngine(const Analyzer::AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration); + virtual ~CallgrindEngine(); + + void start(); + + Valgrind::Callgrind::ParseData *takeParserData(); + +public slots: + // controller actions + void dump(); + void reset(); + void pause(); + void unpause(); + + void setPaused(bool paused); + void setToggleCollectFunction(const QString &toggleCollectFunction); + +protected: + void setExtraArguments(const QStringList &extraArguments); + inline QStringList extraArguments() const { return m_extraArguments; } + + virtual QStringList toolArguments() const; + virtual QString progressTitle() const; + virtual Valgrind::ValgrindRunner *runner(); + +signals: + void parserDataReady(CallgrindEngine *engine); + +private: + Valgrind::Callgrind::CallgrindRunner m_runner; + bool m_markAsPaused; + + QStringList m_extraArguments; + +private slots: + void slotFinished(); + void slotStarted(); +}; + +} // namespace Internal +} // namespace Callgrind + +#endif // CALLGRINDENGINE_H diff --git a/src/plugins/callgrind/callgrindhelper.cpp b/src/plugins/callgrind/callgrindhelper.cpp new file mode 100644 index 00000000000..9a7f604acb7 --- /dev/null +++ b/src/plugins/callgrind/callgrindhelper.cpp @@ -0,0 +1,71 @@ +/************************************************************************** +** +** 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 "callgrindhelper.h" + +#include + +#include +#include +#include + +using namespace Callgrind::Internal; + +QColor CallgrindHelper::colorForString(const QString &text) +{ + static QMap colorCache; + + if (colorCache.contains(text)) + return colorCache.value(text); + + // Minimum lightness of 100 to be readable with black text. + const QColor color = QColor::fromHsl(((qreal)qrand() / RAND_MAX * 359), + ((qreal)qrand() / RAND_MAX * 255), + ((qreal)qrand() / RAND_MAX * 127) + 128); + colorCache[text] = color; + return color; +} + +QColor CallgrindHelper::colorForCostRatio(qreal ratio) +{ + ratio = qBound(0.0, ratio, 1.0); + return QColor::fromHsv(120 - ratio * 120, 255, 255, (-((ratio-1) * (ratio-1))) * 120 + 120); +} + +QString CallgrindHelper::toPercent(float costs, const QLocale &locale) +{ + if (costs > 99.9f) + return locale.toString(100) + locale.percent(); + else if (costs > 9.99f) + return locale.toString(costs, 'f', 1) + locale.percent(); + else if (costs > 0.009f) + return locale.toString(costs, 'f', 2) + locale.percent(); + else + return QString("<") + locale.toString(0.01f) + locale.percent(); +} diff --git a/src/plugins/callgrind/callgrindhelper.h b/src/plugins/callgrind/callgrindhelper.h new file mode 100644 index 00000000000..061857d9250 --- /dev/null +++ b/src/plugins/callgrind/callgrindhelper.h @@ -0,0 +1,65 @@ +/************************************************************************** +** +** 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 CALLGRINDHELPER_H +#define CALLGRINDHELPER_H + +#include + +QT_BEGIN_NAMESPACE +class QColor; +class QString; +QT_END_NAMESPACE + +namespace Callgrind { +namespace Internal { + +namespace CallgrindHelper +{ + /** + * Returns color for a specific string, the string<->color mapping is cached + */ + QColor colorForString(const QString &text); + + /** + * Returns color for a specific cost ratio + * \param ratio The cost ratio, ratio should be of [0,1] + */ + QColor colorForCostRatio(qreal ratio); + + /** + * Returns a proper percent representation of a float limited to 5 chars + */ + QString toPercent(float costs, const QLocale &locale = QLocale()); +} + +} +} + +#endif // CALLGRINDHELPER_H diff --git a/src/plugins/callgrind/callgrindnamedelegate.cpp b/src/plugins/callgrind/callgrindnamedelegate.cpp new file mode 100644 index 00000000000..45cb6b52f7a --- /dev/null +++ b/src/plugins/callgrind/callgrindnamedelegate.cpp @@ -0,0 +1,92 @@ +/************************************************************************** +** +** 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 "callgrindnamedelegate.h" + +#include "callgrindhelper.h" + +#include +#include + +namespace Callgrind { +namespace Internal { + +NameDelegate::NameDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ + +} + +NameDelegate::~NameDelegate() +{ +} + +void NameDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + // init + QStyleOptionViewItemV4 opt(option); + initStyleOption(&opt, index); + + const int margin = 2; + const int size = 10; + + const QString text = index.data().toString(); + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + + // draw controls, but no text + opt.text.clear(); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter); + + // draw bar in the first few pixels + painter->save(); + const QRectF barRect = opt.rect.adjusted( + margin, margin, -opt.rect.width() + size - margin, -margin); + painter->setPen(Qt::black); + painter->setBrush(CallgrindHelper::colorForString(text)); + painter->drawRect(barRect); + + // move cell rect to right + opt.rect.adjust(size+margin, 0, 0, 0); + + // draw text + const QString elidedText = painter->fontMetrics().elidedText(text, Qt::ElideRight, + opt.rect.width()); + + const QBrush &textBrush = (option.state & QStyle::State_Selected) + ? opt.palette.highlightedText() + : opt.palette.text(); + painter->setBrush(Qt::NoBrush); + painter->setPen(textBrush.color()); + painter->drawText(opt.rect, elidedText); + painter->restore(); +} + +} // Internal +} // Callgrind diff --git a/src/plugins/callgrind/callgrindnamedelegate.h b/src/plugins/callgrind/callgrindnamedelegate.h new file mode 100644 index 00000000000..1e18c54f0bb --- /dev/null +++ b/src/plugins/callgrind/callgrindnamedelegate.h @@ -0,0 +1,53 @@ +/************************************************************************** +** +** 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 CALLGRINDNAMEDELEGATE_H +#define CALLGRINDNAMEDELEGATE_H + +#include + +namespace Callgrind { +namespace Internal { + +class NameDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit NameDelegate(QObject *parent = 0); + virtual ~NameDelegate(); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; +}; + +} // Internal +} // Callgrind + +#endif // CALLGRINDNAMEDELEGATE_H diff --git a/src/plugins/callgrind/callgrindplugin.cpp b/src/plugins/callgrind/callgrindplugin.cpp new file mode 100644 index 00000000000..e2d58edc4b1 --- /dev/null +++ b/src/plugins/callgrind/callgrindplugin.cpp @@ -0,0 +1,73 @@ +/************************************************************************** +** +** 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 "callgrindplugin.h" + +#include "callgrindtool.h" +#include "callgrindsettings.h" + +#include + +#include +#include + +using namespace Analyzer; +using namespace Callgrind; +using namespace Callgrind::Internal; + +CallgrindPlugin::CallgrindPlugin() +{ + +} + +CallgrindPlugin::~CallgrindPlugin() +{ + +} + +bool CallgrindPlugin::initialize(const QStringList &/*arguments*/, QString */*errorString*/) +{ + typedef AnalyzerSubConfigFactory CallgrindConfigFactory; + AnalyzerGlobalSettings::instance()->registerSubConfigFactory(new CallgrindConfigFactory); + AnalyzerManager::instance()->addTool(new CallgrindTool(this)); + + return true; +} + + +void CallgrindPlugin::extensionsInitialized() +{ + +} + +Q_EXPORT_PLUGIN(CallgrindPlugin) \ No newline at end of file diff --git a/src/plugins/callgrind/callgrindplugin.h b/src/plugins/callgrind/callgrindplugin.h new file mode 100644 index 00000000000..2045021c7b8 --- /dev/null +++ b/src/plugins/callgrind/callgrindplugin.h @@ -0,0 +1,57 @@ +/************************************************************************** +** +** 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 CALLGRINDPLUGIN_H +#define CALLGRINDPLUGIN_H + +#include + +namespace Callgrind { +namespace Internal { + +class CallgrindPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + CallgrindPlugin(); + ~CallgrindPlugin(); + + virtual bool initialize(const QStringList &arguments, QString *errorString); + virtual void extensionsInitialized(); +}; + +} // namespace Internal +} // namespace Callgrind + +#endif // CALLGRINDPLUGIN_H diff --git a/src/plugins/callgrind/callgrindsettings.cpp b/src/plugins/callgrind/callgrindsettings.cpp new file mode 100644 index 00000000000..e6d4ef6618e --- /dev/null +++ b/src/plugins/callgrind/callgrindsettings.cpp @@ -0,0 +1,229 @@ +/************************************************************************** +** +** 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 "callgrindsettings.h" + +#include "callgrindconfigwidget.h" + +#include + +using namespace Analyzer; +using namespace Callgrind::Internal; +using namespace Callgrind; + +static const QLatin1String callgrindEnableCacheSimC("Analyzer.Valgrind.Callgrind.EnableCacheSim"); +static const QLatin1String callgrindEnableBranchSimC("Analyzer.Valgrind.Callgrind.EnableBranchSim"); +static const QLatin1String callgrindCollectSystimeC("Analyzer.Valgrind.Callgrind.CollectSystime"); +static const QLatin1String callgrindCollectBusEventsC("Analyzer.Valgrind.Callgrind.CollectBusEvents"); + +static const QLatin1String callgrindCycleDetectionC("Analyzer.Valgrind.Callgrind.CycleDetection"); +static const QLatin1String callgrindCostFormatC("Analyzer.Valgrind.Callgrind.CostFormat"); +static const QLatin1String callgrindMinimumCostRatioC("Analyzer.Valgrind.Callgrind.MinimumCostRatio"); + +AbstractCallgrindSettings::AbstractCallgrindSettings(QObject *parent) + : AbstractAnalyzerSubConfig(parent) +{ + +} + +AbstractCallgrindSettings::~AbstractCallgrindSettings() +{ + +} + +void AbstractCallgrindSettings::setEnableCacheSim(bool enable) +{ + if (m_enableCacheSim == enable) + return; + + m_enableCacheSim = enable; + emit enableCacheSimChanged(enable); +} + +void AbstractCallgrindSettings::setEnableBranchSim(bool enable) +{ + if (m_enableBranchSim == enable) + return; + + m_enableBranchSim = enable; + emit enableBranchSimChanged(enable); +} + +void AbstractCallgrindSettings::setCollectSystime(bool collect) +{ + if (m_collectSystime == collect) + return; + + m_collectSystime = collect; + emit collectSystimeChanged(collect); +} + +void AbstractCallgrindSettings::setCollectBusEvents(bool collect) +{ + if (m_collectBusEvents == collect) + return; + + m_collectBusEvents = collect; + emit collectBusEventsChanged(collect); +} + +QVariantMap AbstractCallgrindSettings::defaults() const +{ + QVariantMap map; + map.insert(callgrindEnableCacheSimC, false); + map.insert(callgrindEnableBranchSimC, false); + map.insert(callgrindCollectSystimeC, false); + map.insert(callgrindCollectBusEventsC, false); + return map; +} + +bool AbstractCallgrindSettings::fromMap(const QVariantMap &map) +{ + setIfPresent(map, callgrindEnableCacheSimC, &m_enableCacheSim); + setIfPresent(map, callgrindEnableBranchSimC, &m_enableBranchSim); + setIfPresent(map, callgrindCollectSystimeC, &m_collectSystime); + setIfPresent(map, callgrindCollectBusEventsC, &m_collectBusEvents); + return true; +} + +QVariantMap AbstractCallgrindSettings::toMap() const +{ + QVariantMap map; + map.insert(callgrindEnableCacheSimC, m_enableCacheSim); + map.insert(callgrindEnableBranchSimC, m_enableBranchSim); + map.insert(callgrindCollectSystimeC, m_collectSystime); + map.insert(callgrindCollectBusEventsC, m_collectBusEvents); + + return map; +} + +QString AbstractCallgrindSettings::id() const +{ + return "Analyzer.Valgrind.Settings.Callgrind"; +} + +QString AbstractCallgrindSettings::displayName() const +{ + return tr("Profiling"); +} + +QWidget *AbstractCallgrindSettings::createConfigWidget(QWidget *parent) +{ + return new CallgrindConfigWidget(this, parent); +} + + +CallgrindGlobalSettings::CallgrindGlobalSettings(QObject *parent) + : AbstractCallgrindSettings(parent) +{ + +} + +CallgrindGlobalSettings::~CallgrindGlobalSettings() +{ + +} + +QVariantMap CallgrindGlobalSettings::defaults() const +{ + QVariantMap map = AbstractCallgrindSettings::defaults(); + map.insert(callgrindCostFormatC, CostDelegate::FormatRelative); + map.insert(callgrindCycleDetectionC, true); + map.insert(callgrindMinimumCostRatioC, 0.0001); + return map; +} + +bool CallgrindGlobalSettings::fromMap(const QVariantMap &map) +{ + AbstractCallgrindSettings::fromMap(map); + // special code as the default one does not cope with the enum properly + if (map.contains(callgrindCostFormatC)) { + m_costFormat = static_cast(map.value(callgrindCostFormatC).toInt()); + } + setIfPresent(map, callgrindCycleDetectionC, &m_detectCycles); + setIfPresent(map, callgrindMinimumCostRatioC, &m_minimumInclusiveCostRatio); + return true; +} + +QVariantMap CallgrindGlobalSettings::toMap() const +{ + QVariantMap map = AbstractCallgrindSettings::toMap(); + map.insert(callgrindCostFormatC, m_costFormat); + map.insert(callgrindCycleDetectionC, m_detectCycles); + map.insert(callgrindMinimumCostRatioC, m_minimumInclusiveCostRatio); + return map; +} + +CostDelegate::CostFormat CallgrindGlobalSettings::costFormat() const +{ + return m_costFormat; +} + +void CallgrindGlobalSettings::setCostFormat(CostDelegate::CostFormat format) +{ + m_costFormat = format; + AnalyzerGlobalSettings::instance()->writeSettings(); +} + +bool CallgrindGlobalSettings::detectCycles() const +{ + return m_detectCycles; +} + +void CallgrindGlobalSettings::setDetectCycles(bool detect) +{ + m_detectCycles = detect; + AnalyzerGlobalSettings::instance()->writeSettings(); +} + +double CallgrindGlobalSettings::minimumInclusiveCostRatio() const +{ + return m_minimumInclusiveCostRatio; +} + +void CallgrindGlobalSettings::setMinimumInclusiveCostRatio(double minimumInclusiveCost) +{ + m_minimumInclusiveCostRatio = minimumInclusiveCost; + AnalyzerGlobalSettings::instance()->writeSettings(); +} + +CallgrindProjectSettings::CallgrindProjectSettings(QObject *parent) + : AbstractCallgrindSettings(parent) +{ + +} + +CallgrindProjectSettings::~CallgrindProjectSettings() +{ + +} diff --git a/src/plugins/callgrind/callgrindsettings.h b/src/plugins/callgrind/callgrindsettings.h new file mode 100644 index 00000000000..873fa7ddc6b --- /dev/null +++ b/src/plugins/callgrind/callgrindsettings.h @@ -0,0 +1,139 @@ +/************************************************************************** +** +** 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 ANALYZER_INTERNAL_CALLGRINDSETTINGS_H +#define ANALYZER_INTERNAL_CALLGRINDSETTINGS_H + +#include + +#include +#include "callgrindcostdelegate.h" + +namespace Callgrind { +namespace Internal { + +/** + * Generic callgrind settings + */ +class AbstractCallgrindSettings : public Analyzer::AbstractAnalyzerSubConfig +{ + Q_OBJECT + +public: + AbstractCallgrindSettings(QObject *parent = 0); + virtual ~AbstractCallgrindSettings(); + + inline bool enableCacheSim() const { return m_enableCacheSim; } + inline bool enableBranchSim() const { return m_enableBranchSim; } + inline bool collectSystime() const { return m_collectSystime; } + inline bool collectBusEvents() const { return m_collectBusEvents; } + + // abstract virtual methods from base class + virtual bool fromMap(const QVariantMap &map); + + virtual QVariantMap defaults() const; + + virtual QString id() const; + virtual QString displayName() const; + virtual QWidget *createConfigWidget(QWidget *parent); + +public Q_SLOTS: + void setEnableCacheSim(bool enable); + void setEnableBranchSim(bool enable); + void setCollectSystime(bool collect); + void setCollectBusEvents(bool collect); + +Q_SIGNALS: + void enableCacheSimChanged(bool); + void enableBranchSimChanged(bool); + void collectSystimeChanged(bool); + void collectBusEventsChanged(bool); + +protected: + virtual QVariantMap toMap() const; + +private: + bool m_enableCacheSim; + bool m_collectSystime; + bool m_collectBusEvents; + bool m_enableBranchSim; +}; + +/** + * Global callgrind settings + */ +class CallgrindGlobalSettings : public AbstractCallgrindSettings +{ + Q_OBJECT + +public: + CallgrindGlobalSettings(QObject *parent = 0); + virtual ~CallgrindGlobalSettings(); + + virtual bool fromMap(const QVariantMap &map); + virtual QVariantMap defaults() const; + + CostDelegate::CostFormat costFormat() const; + bool detectCycles() const; + double minimumInclusiveCostRatio() const; + +public slots: + void setCostFormat(Callgrind::Internal::CostDelegate::CostFormat format); + void setDetectCycles(bool detect); + void setMinimumInclusiveCostRatio(double minimumInclusiveCost); + +protected: + virtual QVariantMap toMap() const; + +private: + CostDelegate::CostFormat m_costFormat; + bool m_detectCycles; + double m_minimumInclusiveCostRatio; +}; + +/** + * Per-project callgrind settings, saves a diff to the global suppression files list + */ +class CallgrindProjectSettings : public AbstractCallgrindSettings +{ + Q_OBJECT + +public: + CallgrindProjectSettings(QObject *parent = 0); + virtual ~CallgrindProjectSettings(); +}; + +} +} + +#endif // ANALYZER_INTERNAL_CALLGRINDSETTINGS_H diff --git a/src/plugins/callgrind/callgrindtextmark.cpp b/src/plugins/callgrind/callgrindtextmark.cpp new file mode 100644 index 00000000000..b365f3cc029 --- /dev/null +++ b/src/plugins/callgrind/callgrindtextmark.cpp @@ -0,0 +1,108 @@ +/************************************************************************** +** +** 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 "callgrindtextmark.h" + +#include "callgrindhelper.h" + +#include +#include + +#include +#include + +#include + +using namespace Callgrind::Internal; +using namespace Valgrind::Callgrind; + +CallgrindTextMark::CallgrindTextMark(const QPersistentModelIndex &index, + const QString &fileName, int lineNumber) + : m_modelIndex(index) +{ + setLocation(fileName, lineNumber); + setPriority(TextEditor::ITextMark::HighPriority); +} + +CallgrindTextMark::~CallgrindTextMark() +{ +} + +void CallgrindTextMark::paint(QPainter *painter, const QRect &paintRect) const +{ + if (!m_modelIndex.isValid()) + return; + + bool ok; + qreal costs = m_modelIndex.data(DataModel::RelativeTotalCostRole).toReal(&ok); + QTC_ASSERT(ok, return) + QTC_ASSERT(costs >= 0.0 && costs <= 100.0, return) + + painter->save(); + + // set up + painter->setPen(Qt::black); + + // draw bar + QRect fillRect = paintRect; + fillRect.setWidth(paintRect.width() * costs); + painter->fillRect(paintRect, Qt::white); + painter->fillRect(fillRect, CallgrindHelper::colorForCostRatio(costs)); + painter->drawRect(paintRect); + + // draw text + const QTextOption flags = Qt::AlignHCenter | Qt::AlignVCenter; + const QString text = CallgrindHelper::toPercent(costs * 100.0f); + + // decrease font size if paint rect is too small (very unlikely, but may happen) + QFont font = painter->font(); + QFontMetrics fm = font; + while (fm.boundingRect(text).width() > paintRect.width()) { + font.setPointSize(font.pointSize() - 1); + fm = font; + } + painter->setFont(font); + + painter->drawText(paintRect, text, flags); + + painter->restore(); +} + +const Function* CallgrindTextMark::function() const +{ + if (!m_modelIndex.isValid()) + return 0; + + return m_modelIndex.data(DataModel::FunctionRole).value(); +} + +double CallgrindTextMark::widthFactor() const +{ + return 4.0; +} diff --git a/src/plugins/callgrind/callgrindtextmark.h b/src/plugins/callgrind/callgrindtextmark.h new file mode 100644 index 00000000000..d03ceee67b7 --- /dev/null +++ b/src/plugins/callgrind/callgrindtextmark.h @@ -0,0 +1,76 @@ +/************************************************************************** +** +** 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 CALLGRINDTEXTMARK_H +#define CALLGRINDTEXTMARK_H + +#include + +#include + +QT_BEGIN_NAMESPACE +QT_END_NAMESPACE + +namespace Valgrind { +namespace Callgrind { +class Function; +} +} + +namespace Callgrind { +namespace Internal { + +class CallgrindTextMark : public TextEditor::BaseTextMark +{ + Q_OBJECT + +public: + /** + * This creates a callgrind text mark for a specific Function + * + * \param index DataModel model index + * \note The index parameter must refer to one of the DataModel cost columns + */ + explicit CallgrindTextMark(const QPersistentModelIndex &index, + const QString &fileName, int lineNumber); + virtual ~CallgrindTextMark(); + + const Valgrind::Callgrind::Function *function() const; + + virtual double widthFactor() const; + virtual void paint(QPainter *painter, const QRect &paintRect) const; + +private: + QPersistentModelIndex m_modelIndex; +}; + +} // namespace Internal +} // namespace Callgrind + +#endif // CALLGRINDTEXTMARK_H diff --git a/src/plugins/callgrind/callgrindtool.cpp b/src/plugins/callgrind/callgrindtool.cpp new file mode 100644 index 00000000000..32c1ffe3a64 --- /dev/null +++ b/src/plugins/callgrind/callgrindtool.cpp @@ -0,0 +1,506 @@ +/************************************************************************** +** +** 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 "callgrindtool.h" + +#include "callgrindconstants.h" +#include "callgrindcostview.h" +#include "callgrindengine.h" +#include "callgrindwidgethandler.h" +#include "callgrindtextmark.h" +#include "callgrindvisualisation.h" +#include "callgrindsettings.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// shared/cplusplus includes +#include + +using namespace Callgrind; + +using namespace Analyzer; +using namespace Core; +using namespace Valgrind::Callgrind; + +namespace Callgrind { +namespace Internal { + +// Adapter for output pane. +class CallgrindOutputPaneAdapter : public Analyzer::ListItemViewOutputPaneAdapter +{ +public: + explicit CallgrindOutputPaneAdapter(CallgrindTool *mct) : + ListItemViewOutputPaneAdapter(mct), m_tool(mct) {} + + virtual QWidget *toolBarWidget() { return m_tool->createPaneToolBarWidget(); } + virtual void clearContents() { m_tool->clearErrorView(); } + +protected: + virtual QAbstractItemView *createItemView() + { + return m_tool->callgrindWidgetHandler()->flatView(); + } + +private: + CallgrindTool *m_tool; +}; + +static QToolButton *createToolButton(QAction *action) +{ + QToolButton *button = new QToolButton; + button->setDefaultAction(action); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + return button; +} + +CallgrindTool::CallgrindTool(QObject *parent) +: Analyzer::IAnalyzerTool(parent) +, m_callgrindWidgetHandler(0) +, m_dumpAction(0) +, m_resetAction(0) +, m_pauseAction(0) +, m_showCostsOfFunctionAction(0) +, m_outputPaneAdapter(0) +{ + Core::ICore *core = Core::ICore::instance(); + + // EditorManager + QObject *editorManager = core->editorManager(); + connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)), + SLOT(editorOpened(Core::IEditor*))); +} + +CallgrindTool::~CallgrindTool() +{ + qDeleteAll(m_textMarks); +} + +QString CallgrindTool::id() const +{ + return "Callgrind"; +} + +QString CallgrindTool::displayName() const +{ + return tr("Profile"); +} + +IAnalyzerTool::ToolMode CallgrindTool::mode() const +{ + return ReleaseMode; +} + +void CallgrindTool::initialize(ExtensionSystem::IPlugin */*plugin*/) +{ + AnalyzerManager *am = AnalyzerManager::instance(); + + CallgrindWidgetHandler *handler = new CallgrindWidgetHandler(am->mainWindow()); + m_callgrindWidgetHandler = handler; + + QDockWidget *visDock = am->createDockWidget(this, tr("Visualisation"), + handler->visualisation(), Qt::LeftDockWidgetArea); + + QDockWidget *calleesDock = am->createDockWidget(this, tr("Callees"), + handler->calleesView(), Qt::BottomDockWidgetArea); + QDockWidget *callersDock = am->createDockWidget(this, tr("Callers"), + handler->callersView(), Qt::BottomDockWidgetArea); + + am->mainWindow()->tabifyDockWidget(callersDock, calleesDock); + am->mainWindow()->tabifyDockWidget(calleesDock, visDock); + + connect(m_callgrindWidgetHandler, SIGNAL(functionSelected(const Valgrind::Callgrind::Function*)), + this, SLOT(slotFunctionSelected(const Valgrind::Callgrind::Function*))); +} + +void CallgrindTool::extensionsInitialized() +{ + Core::ICore *core = Core::ICore::instance(); + Core::ActionManager *actionManager = core->actionManager(); + + Core::Context analyzerContext = Core::Context(Analyzer::Constants::C_ANALYZEMODE); + + // check if there is a CppEditor context menu, if true, add our own context menu actions + if (Core::ActionContainer *editorContextMenu = + actionManager->actionContainer(CppEditor::Constants::M_CONTEXT)) { + QAction *action = 0; + Core::Command *cmd = 0; + + action = new QAction(this); + action->setSeparator(true); + cmd = actionManager->registerAction(action, "Analyzer.Callgrind.ContextMenu.Sep", + analyzerContext); + editorContextMenu->addAction(cmd); + + action = new QAction(tr("Profile costs of this function and its callees"), this); + action->setIcon(QIcon(Analyzer::Constants::ANALYZER_CONTROL_START_ICON)); + connect(action, SIGNAL(triggered()), SLOT(handleShowCostsOfFunction())); + cmd = actionManager->registerAction(action, Callgrind::Constants::A_SHOWCOSTSOFFUNCTION, + analyzerContext); + editorContextMenu->addAction(cmd); + cmd->setAttribute(Core::Command::CA_Hide); + cmd->setAttribute(Core::Command::CA_NonConfigurable); + m_showCostsOfFunctionAction = action; + } +} + +IAnalyzerEngine *CallgrindTool::createEngine(const AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration) +{ + CallgrindEngine *engine = new CallgrindEngine(sp, runConfiguration); + + connect(engine, SIGNAL(parserDataReady(CallgrindEngine *)), SLOT(takeParserData(CallgrindEngine *))); + + connect(engine, SIGNAL(starting(const Analyzer::IAnalyzerEngine*)), + this, SLOT(engineStarting(const Analyzer::IAnalyzerEngine*))); + connect(engine, SIGNAL(finished()), + this, SLOT(engineFinished())); + + connect(this, SIGNAL(dumpRequested()), engine, SLOT(dump())); + connect(this, SIGNAL(resetRequested()), engine, SLOT(reset())); + connect(this, SIGNAL(pauseToggled(bool)), engine, SLOT(setPaused(bool))); + + // initialize engine + engine->setPaused(m_pauseAction->isChecked()); + + // we may want to toggle collect for one function only in this run + engine->setToggleCollectFunction(m_toggleCollectFunction); + m_toggleCollectFunction.clear(); + + AnalyzerManager::instance()->showStatusMessage(AnalyzerManager::msgToolStarted(displayName())); + + return engine; +} + +QWidget *CallgrindTool::createControlWidget() +{ + QWidget *widget = new QWidget; + QHBoxLayout *layout = new QHBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + widget->setLayout(layout); + + // dump action + m_dumpAction = new QAction(this); + m_dumpAction->setDisabled(true); + m_dumpAction->setIcon(QIcon(QLatin1String(Core::Constants::ICON_REDO))); + m_dumpAction->setText(tr("Dump")); + m_dumpAction->setToolTip(tr("Request the dumping of profile information. This will update the callgrind visualization.")); + connect(m_dumpAction, SIGNAL(triggered()), this, SLOT(slotRequestDump())); + layout->addWidget(createToolButton(m_dumpAction)); + + // reset action + m_resetAction = new QAction(this); + m_resetAction->setDisabled(true); + m_resetAction->setIcon(QIcon(QLatin1String(Core::Constants::ICON_CLEAR))); + m_resetAction->setText(tr("Reset")); + m_resetAction->setToolTip(tr("Zero all event counters.")); + connect(m_resetAction, SIGNAL(triggered()), this, SIGNAL(resetRequested())); + layout->addWidget(createToolButton(m_resetAction)); + + // pause action + m_pauseAction = new QAction(this); + m_pauseAction->setCheckable(true); + m_pauseAction->setIcon(QIcon(QLatin1String(":/qml/images/pause-small.png"))); + m_pauseAction->setText(tr("Ignore")); + m_pauseAction->setToolTip(tr("If enabled, no events are counted which will speed up program execution during profiling.")); + connect(m_pauseAction, SIGNAL(toggled(bool)), this, SIGNAL(pauseToggled(bool))); + layout->addWidget(createToolButton(m_pauseAction)); + + layout->addWidget(new Utils::StyledSeparator); + layout->addStretch(); + + return widget; +} + +CallgrindWidgetHandler *CallgrindTool::callgrindWidgetHandler() const +{ + return m_callgrindWidgetHandler; +} + +QWidget *CallgrindTool::createPaneToolBarWidget() +{ + QWidget *toolbarWidget = new QWidget; + toolbarWidget->setObjectName("CallgrindToolBarWidget"); + QHBoxLayout *layout = new QHBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + toolbarWidget->setLayout(layout); + + m_callgrindWidgetHandler->populateActions(layout); + + CallgrindGlobalSettings *settings = AnalyzerGlobalSettings::instance()->subConfig(); + m_callgrindWidgetHandler->setCostFormat(settings->costFormat()); + m_callgrindWidgetHandler->enableCycleDetection(settings->detectCycles()); + connect(m_callgrindWidgetHandler, SIGNAL(costFormatChanged(Callgrind::Internal::CostDelegate::CostFormat)), + settings, SLOT(setCostFormat(Callgrind::Internal::CostDelegate::CostFormat))); + connect(m_callgrindWidgetHandler, SIGNAL(cycleDetectionEnabled(bool)), + settings, SLOT(setDetectCycles(bool))); + + // performance: add a minimum cost index so that we are not flooded by the results + m_callgrindWidgetHandler->proxyModel()->setMinimumInclusiveCostRatio(settings->minimumInclusiveCostRatio()); + + return toolbarWidget; +} + +void CallgrindTool::clearErrorView() +{ + clearTextMarks(); + + m_callgrindWidgetHandler->slotClear(); +} + +void CallgrindTool::clearTextMarks() +{ + qDeleteAll(m_textMarks); + m_textMarks.clear(); +} + +void CallgrindTool::engineStarting(const Analyzer::IAnalyzerEngine *) +{ + // enable/disable actions + m_resetAction->setEnabled(true); + m_dumpAction->setEnabled(true); + + clearErrorView(); +} + +void CallgrindTool::engineFinished() +{ + // enable/disable actions + m_resetAction->setEnabled(false); + m_dumpAction->setEnabled(false); + + const ParseData *data = m_callgrindWidgetHandler->dataModel()->parseData(); + if (data) + showParserResults(data); + else + AnalyzerManager::instance()->showStatusMessage(tr("Profiling aborted.")); +} + +void CallgrindTool::showParserResults(const ParseData *data) +{ + QString msg; + if (data) { + // be careful, the list of events might be empty + if (data->events().isEmpty()) { + msg = tr("Parsing finished, no data."); + } + else { + const QString costStr = QString("%1 %2").arg(QString::number(data->totalCost(0)), data->events().first()); + msg = tr("Parsing finished, total cost of %1 reported.").arg(costStr); + } + } else { + msg = tr("Parsing failed."); + } + AnalyzerManager::instance()->showStatusMessage(msg); +} + +void CallgrindTool::editorOpened(Core::IEditor *editor) +{ + TextEditor::ITextEditor *textEditor = qobject_cast(editor); + if (!textEditor) + return; + + connect(textEditor, + SIGNAL(markContextMenuRequested(TextEditor::ITextEditor*,int,QMenu*)), + SLOT(requestContextMenu(TextEditor::ITextEditor*,int,QMenu*))); +} + +void CallgrindTool::requestContextMenu(TextEditor::ITextEditor *editor, int line, QMenu *menu) +{ + // find callgrind text mark that corresponds to this editor's file and line number + const Function *func = 0; + foreach(CallgrindTextMark *textMark, m_textMarks) { + if (textMark->fileName() == editor->file()->fileName() && textMark->lineNumber() == line) { + func = textMark->function(); + break; + } + } + if (!func) + return; // no callgrind text mark under cursor, return + + // add our action to the context menu + QAction *action = new QAction(tr("Select this function in the analyzer output"), menu); + connect(action, SIGNAL(triggered()), this, SLOT(handleShowCostsAction())); + action->setData(QVariant::fromValue(func)); + menu->addAction(action); +} + +void CallgrindTool::handleShowCostsAction() +{ + const QAction *action = qobject_cast(sender()); + QTC_ASSERT(action, return) + + const Function *func = action->data().value(); + QTC_ASSERT(func, return) + + m_callgrindWidgetHandler->selectFunction(func); +} + +void CallgrindTool::handleShowCostsOfFunction() +{ + CPlusPlus::Symbol *symbol = AnalyzerUtils::findSymbolUnderCursor(); + if (!symbol) + return; + + if (!symbol->isFunction()) + return; + + CPlusPlus::Overview view; + const QString qualifiedFunctionName = view.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol)); + + m_toggleCollectFunction = QString("%1()").arg(qualifiedFunctionName); + + AnalyzerManager::instance()->selectTool(this); + AnalyzerManager::instance()->startTool(); +} + + +void CallgrindTool::slotRequestDump() +{ + m_callgrindWidgetHandler->visualisation()->setText(tr("Populating...")); + emit dumpRequested(); +} + +void CallgrindTool::slotFunctionSelected(const Function *func) +{ + if (func && QFile::exists(func->file())) { + ///TODO: custom position support? + int line = func->lineNumber(); + TextEditor::BaseTextEditorWidget::openEditorAt(func->file(), qMax(line, 0)); + } +} + +void CallgrindTool::takeParserData(CallgrindEngine *engine) +{ + ParseData *data = engine->takeParserData(); + showParserResults(data); + + if (!data) + return; + + // clear first + clearErrorView(); + + m_callgrindWidgetHandler->setParseData(data); + createTextMarks(); +} + +void CallgrindTool::createTextMarks() +{ + DataModel *model = m_callgrindWidgetHandler->dataModel(); + QTC_ASSERT(model, return) + + QList locations; + for (int row = 0; row < model->rowCount(); ++row) + { + const QModelIndex index = model->index(row, DataModel::InclusiveCostColumn); + + QString fileName = index.data(DataModel::FileNameRole).toString(); + if (fileName.isEmpty() || fileName == "???") + continue; + + bool ok = false; + const int lineNumber = index.data(DataModel::LineNumberRole).toInt(&ok); + QTC_ASSERT(ok, continue); + + // sanitize filename, text marks need a canonical (i.e. no ".."s) path + // BaseTextMark::editorOpened(Core::IEditor *editor) compares file names on string basis + QFileInfo info(fileName); + fileName = info.canonicalFilePath(); + if (fileName.isEmpty()) + continue; // isEmpty == true => file does not exist, continue then + + // create only one text mark per location + const QString location = QString("%1:%2").arg(fileName, QString::number(lineNumber)); + if (locations.contains(location)) + continue; + locations << location; + + CallgrindTextMark *mark = new CallgrindTextMark(index, fileName, lineNumber); + m_textMarks << mark; + } +} + +IAnalyzerOutputPaneAdapter *CallgrindTool::outputPaneAdapter() +{ + if (!m_outputPaneAdapter) + m_outputPaneAdapter = new CallgrindOutputPaneAdapter(this); + return m_outputPaneAdapter; +} + +bool CallgrindTool::canRunRemotely() const +{ + return true; +} + + +} +} diff --git a/src/plugins/callgrind/callgrindtool.h b/src/plugins/callgrind/callgrindtool.h new file mode 100644 index 00000000000..2b1322f55ea --- /dev/null +++ b/src/plugins/callgrind/callgrindtool.h @@ -0,0 +1,155 @@ +/************************************************************************** +** +** 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 CALLGRINDTOOL_H +#define CALLGRINDTOOL_H + +#include + +#include + +QT_BEGIN_NAMESPACE +class QCheckBox; +class QAction; +class QComboBox; +class QSortFilterProxyModel; +class QMenu; +class QModelIndex; +QT_END_NAMESPACE + +namespace Valgrind { +namespace Callgrind { +class CostView; +class DataModel; +class DataProxyModel; +class Function; +class ParseData; +class StackBrowser; +class Visualisation; +} +} + +namespace TextEditor +{ +class ITextEditor; +} +namespace Core +{ +class IEditor; +} + +namespace Callgrind { +namespace Internal { + +class CallgrindEngine; +class CallgrindWidgetHandler; +class CallgrindOutputPaneAdapter; +class CallgrindTextMark; + +class CallgrindTool : public Analyzer::IAnalyzerTool +{ + Q_OBJECT + +public: + explicit CallgrindTool(QObject *parent = 0); + virtual ~CallgrindTool(); + + virtual QString id() const; + virtual QString displayName() const; + virtual ToolMode mode() const; + + virtual void initialize(ExtensionSystem::IPlugin *plugin); + virtual void extensionsInitialized(); + + virtual Analyzer::IAnalyzerOutputPaneAdapter *outputPaneAdapter(); + virtual Analyzer::IAnalyzerEngine *createEngine(const Analyzer::AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration = 0); + virtual QWidget *createControlWidget(); + + // For the output pane adapter. + CallgrindWidgetHandler *callgrindWidgetHandler() const; + QWidget *createPaneToolBarWidget(); + void clearErrorView(); + + virtual bool canRunRemotely() const; + +signals: + void dumpRequested(); + void resetRequested(); + void pauseToggled(bool checked); + + void profilingStartRequested(const QString &toggleCollectFunction); + +private slots: + void showParserResults(const Valgrind::Callgrind::ParseData *data); + + void slotRequestDump(); + void slotFunctionSelected(const Valgrind::Callgrind::Function *); + + void editorOpened(Core::IEditor *); + void requestContextMenu(TextEditor::ITextEditor *editor, int line, QMenu *menu); + + void handleShowCostsAction(); + void handleShowCostsOfFunction(); + + void takeParserData(CallgrindEngine *engine); + + void engineStarting(const Analyzer::IAnalyzerEngine *); + void engineFinished(); + +private: + /// This function will add custom text marks to the editor + /// \note Call this after the data model has been populated + void createTextMarks(); + + /// This function will clear all text marks from the editor + void clearTextMarks(); + + CallgrindWidgetHandler *m_callgrindWidgetHandler; + QVector m_textMarks; + + QAction *m_dumpAction; + QAction *m_resetAction; + QAction *m_pauseAction; + + QAction *m_showCostsOfFunctionAction; + + CallgrindOutputPaneAdapter *m_outputPaneAdapter; + + QString m_toggleCollectFunction; +}; + +} // namespace Internal +} // namespace Callgrind + +#endif // CALLGRINDTOOL_H diff --git a/src/plugins/callgrind/callgrindvisualisation.cpp b/src/plugins/callgrind/callgrindvisualisation.cpp new file mode 100644 index 00000000000..7cd6dcb96d3 --- /dev/null +++ b/src/plugins/callgrind/callgrindvisualisation.cpp @@ -0,0 +1,502 @@ +/************************************************************************** +** +** 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 "callgrindvisualisation.h" + +#include "callgrindhelper.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VISUALISATION_DEBUG 0 +// Margin from hardcoded value in: +// QGraphicsView::fitInView(const QRectF &rect, +// Qt::AspectRatioMode aspectRatioMode) +// Bug report here: http://bugreports.qt.nokia.com/browse/QTBUG-11945 +#define FIT_IN_VIEW_MARGIN 2; + +using namespace Valgrind::Callgrind; + +namespace Callgrind { +namespace Internal { + +class FunctionGraphicsTextItem : public QAbstractGraphicsShapeItem +{ +public: + FunctionGraphicsTextItem(const QString &text, QGraphicsItem *parent); + + virtual void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget); + virtual QRectF boundingRect() const; + + void setRotateText(bool rotate); + +private: + QString m_text; + QStaticText m_staticText; + bool m_rotateText; + QColor m_textColor; + qreal m_previousViewportDimension; +}; + +class FunctionGraphicsItem : public QGraphicsRectItem +{ +public: + enum DataKey { + FunctionCallKey + }; + + FunctionGraphicsItem(const QString &text, qreal x, qreal y, + qreal width, qreal height, QGraphicsItem *parent = 0); + + virtual void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget); + FunctionGraphicsTextItem *textItem() const; + +private: + FunctionGraphicsTextItem *m_text; +}; + +FunctionGraphicsTextItem::FunctionGraphicsTextItem(const QString &text, + QGraphicsItem *parent) + : QAbstractGraphicsShapeItem(parent) + , m_text(text) + , m_rotateText(true) + , m_previousViewportDimension(0) +{ + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setAcceptedMouseButtons(0); // do not steal focus from parent item + setToolTip(text); +} + +void FunctionGraphicsTextItem::setRotateText(bool rotate) +{ + m_rotateText = rotate; +} + +void FunctionGraphicsTextItem::paint(QPainter *painter, + const QStyleOptionGraphicsItem *, + QWidget *widget) +{ + const qreal textHeight = painter->fontMetrics().height(); + // Magic number based on what looked best. + const int margin = 2 + FIT_IN_VIEW_MARGIN; + const QRectF viewportRect = + widget->rect().adjusted(margin, margin, -margin, -margin); + + const qreal maxWidth = viewportRect.width() + * parentItem()->boundingRect().width() + / scene()->sceneRect().width(); + const qreal maxHeight = viewportRect.height() + * parentItem()->boundingRect().height() + / scene()->sceneRect().height(); + + qreal textMaxHeight; + qreal textMaxWidth; + qreal viewportDim; + if (m_rotateText) { + viewportDim = viewportRect.height(); + textMaxHeight = maxWidth; + textMaxWidth = maxHeight; + } else { + viewportDim = viewportRect.width(); + textMaxHeight = maxHeight; + textMaxWidth = maxWidth; + } + + if (textHeight > textMaxHeight) + return; + + if (viewportDim != m_previousViewportDimension) { + const QString &elidedText = + painter->fontMetrics().elidedText(m_text, Qt::ElideRight, + textMaxWidth); + m_staticText.setText(elidedText); + m_staticText.prepare(); + + m_previousViewportDimension = viewportDim; + } + +#if VISUALISATION_DEBUG + painter->setPen(Qt::red); + painter->drawRect(boundingRect()); +#endif + + painter->save(); + int textLeft = 0; + int textTop = 0; + if (m_rotateText) { + painter->rotate(90); + textLeft = 2; + textTop = -textHeight/2; + } + else { + const int textWidth = painter->fontMetrics().width(m_staticText.text()); + textLeft = -textWidth/2; + textTop = (maxHeight - textHeight)/2; + } + painter->drawStaticText(textLeft, textTop, m_staticText); + + painter->restore(); +} + +QRectF FunctionGraphicsTextItem::boundingRect() const +{ + return mapRectFromParent(parentItem()->boundingRect()); +} + +FunctionGraphicsItem::FunctionGraphicsItem(const QString &text, + qreal x, qreal y, qreal width, + qreal height, QGraphicsItem *parent) + : QGraphicsRectItem(x, y, width, height, parent) + , m_text(0) +{ + setFlag(QGraphicsItem::ItemIsSelectable); + setFlag(QGraphicsItem::ItemClipsToShape); + setFlag(QGraphicsItem::ItemClipsChildrenToShape); + setToolTip(text); + + m_text = new FunctionGraphicsTextItem(text, this); + m_text->setPos(rect().center().x(), y); +} + +FunctionGraphicsTextItem *FunctionGraphicsItem::textItem() const +{ + return m_text; +} + +void FunctionGraphicsItem::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *) +{ + painter->save(); + + QRectF rect = this->rect(); + const QColor &color = brush().color(); + if (option->state & QStyle::State_Selected) { + QLinearGradient gradient(0, 0, rect.width(), rect.height()); + gradient.setColorAt(0, color.lighter(250)); + gradient.setColorAt(1, color.darker()); + painter->setBrush(gradient); + } + else { + painter->setBrush(color); + } + +#if VISUALISATION_DEBUG + painter->setPen(Qt::blue); + painter->drawRect(boundingRect()); +#endif + + QPen pen = painter->pen(); + pen.setColor(color.darker()); + pen.setWidthF(0.5); + painter->setPen(pen); + qreal halfPenWidth = pen.widthF()/2.0; + rect.adjust(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth); + painter->drawRect(rect); + + painter->restore(); +} + +class Visualisation::Private +{ +public: + Private(Visualisation *qq); + ~Private(); + + void handleMousePressEvent(QMouseEvent *event, bool doubleClicked); + qreal sceneHeight() const; + qreal sceneWidth() const; + + Visualisation *q; + DataProxyModel *m_model; + QGraphicsScene m_scene; + int m_modelColumn; +}; + +Visualisation::Private::Private(Visualisation *qq) + : q(qq) + , m_model(new DataProxyModel(qq)) + , m_modelColumn(-1) +{ + // setup scene + m_scene.setObjectName("Visualisation Scene"); + ///NOTE: with size 100x100 the Qt-internal mouse selection fails... + m_scene.setSceneRect(0, 0, 1024, 1024); + + // setup model + m_model->setMinimumInclusiveCostRatio(0.1); + connect(m_model, + SIGNAL(filterFunctionChanged(const Function*,const Function*)), + qq, SLOT(populateScene())); +} + +Visualisation::Private::~Private() +{ + +} + +void Visualisation::Private::handleMousePressEvent(QMouseEvent *event, + bool doubleClicked) +{ + // find the first item that accepts mouse presses under the cursor position + QGraphicsItem *itemAtPos = 0; + foreach(QGraphicsItem *item, q->items(event->pos())) { + if (!(item->acceptedMouseButtons() & event->button())) + continue; + + itemAtPos = item; + break; + } + + // if there is an item, select it + if (itemAtPos) { + const Function *func = q->functionForItem(itemAtPos); + + if (doubleClicked) { + q->functionActivated(func); + } + else { + q->scene()->clearSelection(); + itemAtPos->setSelected(true); + q->functionSelected(func); + } + } + +} + +qreal Visualisation::Private::sceneHeight() const +{ + return m_scene.height() - FIT_IN_VIEW_MARGIN; +} + +qreal Visualisation::Private::sceneWidth() const +{ + // Magic number to improve margins appearance + return m_scene.width() + 1; +} + +Visualisation::Visualisation(QWidget *parent) + : QGraphicsView(parent) + , d(new Private(this)) +{ + setObjectName("Visualisation View"); + setScene(&d->m_scene); + setRenderHint(QPainter::Antialiasing); +} + +Visualisation::~Visualisation() +{ + delete d; +} + +const Function *Visualisation::functionForItem(QGraphicsItem *item) const +{ + return item->data(FunctionGraphicsItem::FunctionCallKey).value(); +} + +QGraphicsItem *Visualisation::itemForFunction(const Function *function) const +{ + foreach(QGraphicsItem *item, items()) { + if (functionForItem(item) == function) + return item; + } + return 0; +} + +void Visualisation::setFunction(const Function *function) +{ + d->m_model->setFilterFunction(function); +} + +const Function *Visualisation::function() const +{ + return d->m_model->filterFunction(); +} + +void Visualisation::setModel(DataModel *model) +{ + QTC_ASSERT(!d->m_model->sourceModel() && model, return); // only set once! + d->m_model->setSourceModel(model); + + connect(model, + SIGNAL(columnsInserted(const QModelIndex&, int, int)), + SLOT(populateScene())); + connect(model, + SIGNAL(columnsMoved(const QModelIndex&, int, int, const QModelIndex&, int)), + SLOT(populateScene())); + connect(model, + SIGNAL(columnsRemoved(const QModelIndex&, int, int)), + SLOT(populateScene())); + connect(model, + SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + SLOT(populateScene())); + connect(model, + SIGNAL(headerDataChanged(Qt::Orientation, int, int)), + SLOT(populateScene())); + connect(model, SIGNAL(layoutChanged()), SLOT(populateScene())); + connect(model, SIGNAL(modelReset()), SLOT(populateScene())); + connect(model, + SIGNAL(rowsInserted(const QModelIndex&, int, int)), + SLOT(populateScene())); + connect(model, + SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)), + SLOT(populateScene())); + connect(model, + SIGNAL(rowsRemoved(const QModelIndex&, int, int)), + SLOT(populateScene())); + + populateScene(); +} + +void Visualisation::setText(const QString &message) +{ + d->m_scene.clear(); + + QGraphicsSimpleTextItem *textItem = d->m_scene.addSimpleText(message); + textItem->setBrush(palette().foreground()); + textItem->setPos((d->sceneWidth() - textItem->boundingRect().width()) / 2, + (d->sceneHeight() - textItem->boundingRect().height()) / 2); + textItem->setFlag(QGraphicsItem::ItemIgnoresTransformations); +} + +void Visualisation::populateScene() +{ + // reset scene first + d->m_scene.clear(); + + const qreal sceneWidth = d->sceneWidth(); + const qreal sceneHeight = d->sceneHeight(); + + // cache costs of each element, calculate total costs + qreal total = 0; + + typedef QPair Pair; + QLinkedList costs; + for (int row=0; row < d->m_model->rowCount(); ++row) + { + const QModelIndex index = d->m_model->index(row, DataModel::InclusiveCostColumn); + + bool ok = false; + const qreal cost = index.data().toReal(&ok); + QTC_ASSERT(ok, continue); + costs << QPair(d->m_model->index(row, 0), cost); + total += cost; + } + + if (!costs.isEmpty() || d->m_model->filterFunction()) { + // item showing the current filter function + + QString text; + if (d->m_model->filterFunction()) + text = d->m_model->filterFunction()->name(); + else { + const float ratioPercent = d->m_model->minimumInclusiveCostRatio() * 100; + QString ratioPercentString = QString::number(ratioPercent); + ratioPercentString.append(QLocale::system().percent()); + const int hiddenFunctions = d->m_model->sourceModel()->rowCount() - d->m_model->rowCount(); + text = tr("All functions with an inclusive cost ratio higher than %1 (%2 are hidden)") + .arg(ratioPercentString) + .arg(hiddenFunctions); + } + + const qreal height = sceneHeight* (costs.isEmpty() ? 1.0 : 0.1); + FunctionGraphicsItem *item = new FunctionGraphicsItem(text, 0, 0, sceneWidth, height); + const QColor background = CallgrindHelper::colorForString(text); + item->setBrush(background); + item->setData(FunctionGraphicsItem::FunctionCallKey, QVariant::fromValue(d->m_model->filterFunction())); + item->textItem()->setRotateText(false); + // NOTE: workaround wrong tooltip being show, no idea why... + item->setZValue(-1); + d->m_scene.addItem(item); + } + + // add the canvas elements to the scene + qreal used = 0; + foreach(const Pair &cost, costs) + { + const QModelIndex &index = cost.first; + const QString text = index.data().toString(); + + const qreal width = (sceneWidth * cost.second) / total; + const qreal height = sceneHeight * 0.9; + + FunctionGraphicsItem *item = new FunctionGraphicsItem(text, used, sceneHeight - height, width, height); + const QColor background = CallgrindHelper::colorForString(text); + item->setBrush(background); + item->setData(FunctionGraphicsItem::FunctionCallKey, index.data(DataModel::FunctionRole)); + d->m_scene.addItem(item); + used += width; + } +} + +void Visualisation::mousePressEvent(QMouseEvent *event) +{ + d->handleMousePressEvent(event, false); + + QGraphicsView::mousePressEvent(event); +} + +void Visualisation::mouseDoubleClickEvent(QMouseEvent *event) +{ + d->handleMousePressEvent(event, true); + + QGraphicsView::mouseDoubleClickEvent(event); +} + +void Visualisation::resizeEvent(QResizeEvent *event) +{ + fitInView(sceneRect()); + + QGraphicsView::resizeEvent(event); +} + + +} // Internal +} // Callgrind diff --git a/src/plugins/callgrind/callgrindvisualisation.h b/src/plugins/callgrind/callgrindvisualisation.h new file mode 100644 index 00000000000..d5dd3979100 --- /dev/null +++ b/src/plugins/callgrind/callgrindvisualisation.h @@ -0,0 +1,94 @@ +/************************************************************************** +** +** 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 CALLGRINDVISUALISATION_H +#define CALLGRINDVISUALISATION_H + +#include + +QT_BEGIN_NAMESPACE +class QAbstractItemModel; +class QModelIndex; +QT_END_NAMESPACE + +namespace Valgrind { +namespace Callgrind { +class Function; +class DataModel; +} +} + +namespace Callgrind { +namespace Internal { + +class Visualisation : public QGraphicsView +{ + Q_OBJECT + +public: + explicit Visualisation(QWidget *parent = 0); + virtual ~Visualisation(); + + void setModel(Valgrind::Callgrind::DataModel *model); + + const Valgrind::Callgrind::Function *functionForItem(QGraphicsItem *item) const; + QGraphicsItem *itemForFunction(const Valgrind::Callgrind::Function *function) const; + + void setFunction(const Valgrind::Callgrind::Function *function); + const Valgrind::Callgrind::Function *function() const; + +public slots: + void setText(const QString &message); + +signals: + void functionActivated(const Valgrind::Callgrind::Function *); + void functionSelected(const Valgrind::Callgrind::Function *); + +protected slots: + void populateScene(); + + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); + +protected: + virtual void resizeEvent(QResizeEvent *event); + +private: + class Private; + Private *d; +}; + +} // Internal +} // Callgrind + +#endif // VALGRIND_CALLGRIND_CALLGRINDVISUALISATION_H diff --git a/src/plugins/callgrind/callgrindwidgethandler.cpp b/src/plugins/callgrind/callgrindwidgethandler.cpp new file mode 100644 index 00000000000..bde3b8abf48 --- /dev/null +++ b/src/plugins/callgrind/callgrindwidgethandler.cpp @@ -0,0 +1,504 @@ +/************************************************************************** +** +** 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 "callgrindwidgethandler.h" + +#include "callgrindcostview.h" +#include "callgrindengine.h" +#include "callgrindvisualisation.h" + +#ifndef DISABLE_CALLGRIND_WORKAROUNDS +#include "workarounds.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Valgrind::Callgrind; + +namespace Callgrind { +namespace Internal { + +CallgrindWidgetHandler::CallgrindWidgetHandler(QWidget *parent) +: QObject(parent) +, m_dataModel(new DataModel(this)) +, m_dataProxy(new DataProxyModel(this)) +, m_stackBrowser(new StackBrowser(this)) +, m_callersModel(new CallModel(this)) +, m_calleesModel(new CallModel(this)) +, m_flatView(0) +, m_callersView(0) +, m_calleesView(0) +, m_visualisation(0) +, m_goToOverview(0) +, m_goBack(0) +, m_searchFilter(0) +, m_filterProjectCosts(0) +, m_costAbsolute(0) +, m_costRelative(0) +, m_costRelativeToParent(0) +, m_eventCombo(0) +, m_updateTimer(new QTimer(this)) +{ + connect(m_stackBrowser, SIGNAL(currentChanged()), this, SLOT(stackBrowserChanged())); + + m_updateTimer->setInterval(200); + m_updateTimer->setSingleShot(true); + connect(m_updateTimer, SIGNAL(timeout()), SLOT(updateFilterString())); + + m_dataProxy->setSourceModel(m_dataModel); + m_dataProxy->setDynamicSortFilter(true); + m_dataProxy->setSortCaseSensitivity(Qt::CaseInsensitive); + m_dataProxy->setFilterKeyColumn(DataModel::NameColumn); + m_dataProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); + + m_flatView = new CostView(parent); + m_flatView->sortByColumn(DataModel::SelfCostColumn); + m_flatView->setFrameStyle(QFrame::NoFrame); + m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false); + m_flatView->setModel(m_dataProxy); + m_flatView->setObjectName("Valgrind.CallgrindWidgetHandler.FlatView"); + connect(m_flatView, SIGNAL(activated(QModelIndex)), + this, SLOT(dataFunctionSelected(QModelIndex))); + + m_visualisation = new Visualisation(parent); + m_visualisation->setObjectName("Valgrind.CallgrindWidgetHandler.Visualisation"); + m_visualisation->setModel(m_dataModel); + connect(m_visualisation, SIGNAL(functionActivated(const Valgrind::Callgrind::Function*)), + this, SLOT(visualisationFunctionSelected(const Valgrind::Callgrind::Function*))); + + { + m_calleesView = new CostView(parent); + m_calleesView->sortByColumn(CallModel::CostColumn); + m_calleesView->setObjectName("Valgrind.CallgrindWidgetHandler.CalleesView"); + // enable sorting + QSortFilterProxyModel *calleeProxy = new QSortFilterProxyModel(m_calleesModel); + calleeProxy->setSourceModel(m_calleesModel); + m_calleesView->setModel(calleeProxy); + m_calleesView->hideColumn(CallModel::CallerColumn); + connect(m_calleesView, SIGNAL(activated(QModelIndex)), + this, SLOT(calleeFunctionSelected(QModelIndex))); + } + { + m_callersView = new CostView(parent); + m_callersView->sortByColumn(CallModel::CostColumn); + m_callersView->setObjectName("Valgrind.CallgrindWidgetHandler.CallersView"); + // enable sorting + QSortFilterProxyModel *callerProxy = new QSortFilterProxyModel(m_callersModel); + callerProxy->setSourceModel(m_callersModel); + m_callersView->setModel(callerProxy); + m_callersView->hideColumn(CallModel::CalleeColumn); + connect(m_callersView, SIGNAL(activated(QModelIndex)), + this, SLOT(callerFunctionSelected(QModelIndex))); + } +} + +void CallgrindWidgetHandler::populateActions(QLayout *layout) +{ + // navigation + { + QToolButton *button; + QAction *action; + + // go back + action = new QAction(this); + action->setDisabled(true); + action->setIcon(QIcon::fromTheme("go-previous")); + action->setText(tr("Back")); + action->setToolTip(tr("Go back one step in history. This will select the previously selected item.")); + m_goBack = action; + connect(action, SIGNAL(triggered(bool)), m_stackBrowser, SLOT(goBack())); + button = new QToolButton; + button->setDefaultAction(action); + layout->addWidget(button); + + // overview + action = new QAction(this); + action->setDisabled(true); + action->setIcon(QIcon::fromTheme("go-up")); + action->setText(tr("All Functions")); + action->setToolTip(tr("Show the overview of all function calls.")); + m_goToOverview = action; + connect(action, SIGNAL(triggered(bool)), this, SLOT(slotGoToOverview())); + button = new QToolButton; + button->setDefaultAction(action); + layout->addWidget(button); + } + + layout->addWidget(new Utils::StyledSeparator); + + // event selection + { + m_eventCombo = new QComboBox; + m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized.")); + connect(m_eventCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(setCostEvent(int))); + updateEventCombo(); + layout->addWidget(m_eventCombo); + } + + // cost formatting + { + QMenu *menu = new QMenu(layout->parentWidget()); + QActionGroup *group = new QActionGroup(this); + + // show costs as absolute numbers + m_costAbsolute = new QAction(tr("Absolute Costs"), this); + ///FIXME: icon + m_costAbsolute->setToolTip(tr("Show costs as absolute numbers.")); + m_costAbsolute->setCheckable(true); + m_costAbsolute->setChecked(true); + connect(m_costAbsolute, SIGNAL(toggled(bool)), + this, SLOT(updateCostFormat())); + group->addAction(m_costAbsolute); + menu->addAction(m_costAbsolute); + + // show costs in percentages + m_costRelative = new QAction(tr("Relative Costs"), this); + ///FIXME: icon (percentage sign?) + m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost.")); + m_costRelative->setCheckable(true); + connect(m_costRelative, SIGNAL(toggled(bool)), + this, SLOT(updateCostFormat())); + group->addAction(m_costRelative); + menu->addAction(m_costRelative); + + // show costs relative to parent + m_costRelativeToParent = new QAction(tr("Relative Costs To Parent"), this); + ///FIXME: icon + m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost.")); + m_costRelativeToParent->setCheckable(true); + connect(m_costRelativeToParent, SIGNAL(toggled(bool)), + this, SLOT(updateCostFormat())); + group->addAction(m_costRelativeToParent); + menu->addAction(m_costRelativeToParent); + + QToolButton *button = new QToolButton; + button->setMenu(menu); + button->setPopupMode(QToolButton::InstantPopup); + button->setText(tr("Cost Format")); + layout->addWidget(button); + } + + { + // cycle detection + m_cycleDetection = new QAction(tr("Cycle Detection"), this); + ///FIXME: icon + m_cycleDetection->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls.")); + connect(m_cycleDetection, SIGNAL(toggled(bool)), + m_dataModel, SLOT(enableCycleDetection(bool))); + connect(m_cycleDetection, SIGNAL(toggled(bool)), + this, SIGNAL(cycleDetectionEnabled(bool))); + m_cycleDetection->setCheckable(true); + QToolButton *button = new QToolButton; + button->setDefaultAction(m_cycleDetection); + layout->addWidget(button); + } + + // filtering + { + QToolButton *button; + m_filterProjectCosts = new QAction(tr("Show Project Costs Only"), this); + m_filterProjectCosts->setIcon(QIcon(Core::Constants::ICON_FILTER)); + m_filterProjectCosts->setToolTip(tr("Show only profiling info that originated from this project source.")); + m_filterProjectCosts->setCheckable(true); + connect(m_filterProjectCosts, SIGNAL(toggled(bool)), + this, SLOT( handleFilterProjectCosts())); + button = new QToolButton; + button->setDefaultAction(m_filterProjectCosts); + layout->addWidget(button); + + // filter + ///FIXME: find workaround for http://bugreports.qt.nokia.com/browse/QTCREATORBUG-3247 + QLineEdit *filter = new QLineEdit; + filter->setPlaceholderText(tr("Filter...")); + connect(filter, SIGNAL(textChanged(QString)), + m_updateTimer, SLOT(start())); + layout->addWidget(filter); + m_searchFilter = filter; + } + + layout->addWidget(new Utils::StyledSeparator); +} + +CallgrindWidgetHandler::~CallgrindWidgetHandler() +{ + slotClear(); +} + +void CallgrindWidgetHandler::slotGoToOverview() +{ + selectFunction(0); +} + +void CallgrindWidgetHandler::slotClear() +{ + setParseData(0); + + // clear filters + m_filterProjectCosts->setChecked(false); + m_dataProxy->setFilterBaseDir(QString()); + m_searchFilter->setText(QString()); + m_dataProxy->setFilterFixedString(QString()); +} + +void CallgrindWidgetHandler::slotRequestDump() +{ + m_visualisation->setText(tr("Populating...")); + emit dumpRequested(); +} + +void CallgrindWidgetHandler::selectFunction(const Function *func) +{ + if (!func) { + m_goToOverview->setDisabled(true); + + m_flatView->clearSelection(); + m_visualisation->setFunction(0); + m_callersModel->clear(); + m_calleesModel->clear(); + + emit functionSelected(0); + return; + } + + m_goToOverview->setEnabled(true); + + const QModelIndex index = m_dataModel->indexForObject(func); + const QModelIndex proxyIndex = m_dataProxy->mapFromSource(index); + m_flatView->selectionModel()->clearSelection(); + m_flatView->selectionModel()->setCurrentIndex(proxyIndex, + QItemSelectionModel::ClearAndSelect | + QItemSelectionModel::Rows); + m_flatView->scrollTo(proxyIndex); + + m_callersModel->setCalls(func->incomingCalls(), func); + m_calleesModel->setCalls(func->outgoingCalls(), func); + m_visualisation->setFunction(func); + + FunctionHistoryItem *item = dynamic_cast(m_stackBrowser->current()); + if (!item || item->function() != func) + m_stackBrowser->select(new FunctionHistoryItem(func)); + + emit functionSelected(func); +} + +void CallgrindWidgetHandler::stackBrowserChanged() +{ + FunctionHistoryItem *item = dynamic_cast(m_stackBrowser->current()); + + if (!item || item->function() == 0) + m_goBack->setDisabled(true); + else + m_goBack->setEnabled(true); + + selectFunction(item ? item->function() : 0); +} + +void CallgrindWidgetHandler::updateFilterString() +{ + m_dataProxy->setFilterFixedString(m_searchFilter->text()); +} + +void CallgrindWidgetHandler::setCostFormat(CostDelegate::CostFormat format) +{ + switch(format) { + case CostDelegate::FormatAbsolute: + m_costAbsolute->setChecked(true); + break; + case CostDelegate::FormatRelative: + m_costRelative->setChecked(true); + break; + case CostDelegate::FormatRelativeToParent: + m_costRelativeToParent->setChecked(true); + break; + } +} + +void CallgrindWidgetHandler::setCostEvent(int index) +{ + // prevent assert in model, don't try to set event to -1 + // happens when we clear the eventcombo + if (index == -1) + index = 0; + + m_dataModel->setCostEvent(index); + m_calleesModel->setCostEvent(index); + m_callersModel->setCostEvent(index); +} + +void CallgrindWidgetHandler::enableCycleDetection(bool enabled) +{ + m_cycleDetection->setChecked(enabled); +} + +void CallgrindWidgetHandler::updateCostFormat() +{ + CostDelegate::CostFormat format = CostDelegate::FormatAbsolute; + + if (m_costRelativeToParent->isChecked()) + format = CostDelegate::FormatRelativeToParent; + else if (m_costRelative->isChecked()) + format = CostDelegate::FormatRelative; + // else = Absolute + + m_flatView->setCostFormat(format); + m_calleesView->setCostFormat(format); + m_callersView->setCostFormat(format); + + emit costFormatChanged(format); +} + +void CallgrindWidgetHandler::handleFilterProjectCosts() +{ + ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance(); + ProjectExplorer::Project *pro = pe->currentProject(); + QTC_ASSERT(pro, return) + + if (m_filterProjectCosts->isChecked()) { + const QString projectDir = pro->projectDirectory(); + m_dataProxy->setFilterBaseDir(projectDir); + } + else { + m_dataProxy->setFilterBaseDir(QString()); + } +} + +void CallgrindWidgetHandler::dataFunctionSelected(const QModelIndex &index) +{ + const Function *func = index.data(DataModel::FunctionRole).value(); + QTC_ASSERT(func, return); + + selectFunction(func); +} + +void CallgrindWidgetHandler::calleeFunctionSelected(const QModelIndex &index) +{ + const FunctionCall *call = index.data(CallModel::FunctionCallRole).value(); + QTC_ASSERT(call, return); + + selectFunction(call->callee()); +} + +void CallgrindWidgetHandler::callerFunctionSelected(const QModelIndex &index) +{ + const FunctionCall *call = index.data(CallModel::FunctionCallRole).value(); + QTC_ASSERT(call, return); + + selectFunction(call->caller()); +} + +void CallgrindWidgetHandler::visualisationFunctionSelected(const Function *function) +{ + if (function && function == m_visualisation->function()) + // up-navigation when the initial function was activated + m_stackBrowser->goBack(); + else + selectFunction(function); +} + +void CallgrindWidgetHandler::setParseData(ParseData *data) +{ + // we have new parse data, invalidate filters in the proxy model + m_visualisation->setFunction(0); + + // invalidate parse data in the data model + delete m_dataModel->parseData(); + + if (data && data->events().isEmpty()) { + // might happen if the user cancelled the profile run + // callgrind then sometimes produces empty callgrind.out.PID files + delete data; + data = 0; + } + m_dataModel->setParseData(data); + m_calleesModel->setParseData(data); + m_callersModel->setParseData(data); + + updateEventCombo(); + + // clear history for new data + m_stackBrowser->clear(); +} + +void CallgrindWidgetHandler::updateEventCombo() +{ + QTC_ASSERT(m_eventCombo, return) + + m_eventCombo->clear(); + + const ParseData *data = m_dataModel->parseData(); + if (!data || data->events().isEmpty()) { + m_eventCombo->hide(); + return; + } + + m_eventCombo->show(); + foreach(const QString &event, data->events()) + m_eventCombo->addItem(ParseData::prettyStringForEvent(event)); +} + +} +} diff --git a/src/plugins/callgrind/callgrindwidgethandler.h b/src/plugins/callgrind/callgrindwidgethandler.h new file mode 100644 index 00000000000..88a027849b6 --- /dev/null +++ b/src/plugins/callgrind/callgrindwidgethandler.h @@ -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 CALLGRINDWIDGETHANDLER_H +#define CALLGRINDWIDGETHANDLER_H + +#include + +#include "callgrindcostdelegate.h" + +QT_BEGIN_NAMESPACE +class QToolButton; +class QAction; +class QLineEdit; +class QModelIndex; +class QSortFilterProxyModel; +class QTimer; +class QComboBox; +QT_END_NAMESPACE + +namespace Valgrind { +namespace Callgrind { +class DataModel; +class DataProxyModel; +class Function; +class ParseData; +class StackBrowser; +class CallModel; +} +} + +namespace Callgrind { +namespace Internal { + +class CallgrindEngine; +class Visualisation; +class CostView; + +/** + * Encapsulates all widgets required for a fully operational callgrind UI. + * Prevents code duplication between QtC code and unit tests. + */ +class CallgrindWidgetHandler : public QObject +{ + Q_OBJECT + +public: + explicit CallgrindWidgetHandler(QWidget *parent); + virtual ~CallgrindWidgetHandler(); + + void populateActions(QLayout *layout); + + void setParseData(Valgrind::Callgrind::ParseData *data); + + Valgrind::Callgrind::DataModel *dataModel() const { return m_dataModel; } + Valgrind::Callgrind::DataProxyModel *proxyModel() const { return m_dataProxy; } + CostView *flatView() const { return m_flatView; } + Visualisation *visualisation() const { return m_visualisation; } + + Valgrind::Callgrind::CallModel *callersModel() const { return m_callersModel; } + CostView *callersView() const { return m_callersView; } + Valgrind::Callgrind::CallModel *calleesModel() const { return m_calleesModel; } + CostView *calleesView() const { return m_calleesView; } + +signals: + void dumpRequested(); + void resetRequested(); + void pauseToggled(bool checked); + + void functionSelected(const Valgrind::Callgrind::Function *); + + void costFormatChanged(Callgrind::Internal::CostDelegate::CostFormat format); + void cycleDetectionEnabled(bool enabled); + +public slots: + void slotClear(); + void slotRequestDump(); + + void selectFunction(const Valgrind::Callgrind::Function *); + void setCostFormat(Callgrind::Internal::CostDelegate::CostFormat format); + void enableCycleDetection(bool enabled); + void setCostEvent(int index); + +private slots: + void updateFilterString(); + void updateCostFormat(); + + void handleFilterProjectCosts(); + + void slotGoToOverview(); + void stackBrowserChanged(); + + void dataFunctionSelected(const QModelIndex &index); + void calleeFunctionSelected(const QModelIndex &index); + void callerFunctionSelected(const QModelIndex &index); + void visualisationFunctionSelected(const Valgrind::Callgrind::Function *function); + +private: + void updateEventCombo(); + + Valgrind::Callgrind::DataModel *m_dataModel; + Valgrind::Callgrind::DataProxyModel *m_dataProxy; + Valgrind::Callgrind::StackBrowser *m_stackBrowser; + + Valgrind::Callgrind::CallModel *m_callersModel; + Valgrind::Callgrind::CallModel *m_calleesModel; + + CostView *m_flatView; + CostView *m_callersView; + CostView *m_calleesView; + Visualisation *m_visualisation; + + // navigation + QAction *m_goToOverview; + QAction *m_goBack; + QLineEdit *m_searchFilter; + + // cost formatting + QAction *m_filterProjectCosts; + QAction *m_costAbsolute; + QAction *m_costRelative; + QAction *m_costRelativeToParent; + QAction *m_cycleDetection; + QComboBox *m_eventCombo; + + QTimer *m_updateTimer; +}; + +} // namespace Internal +} // namespace Callgrind + +#endif // CALLGRINDWIDGETHANDLER_H diff --git a/src/plugins/callgrind/workarounds.cpp b/src/plugins/callgrind/workarounds.cpp new file mode 100644 index 00000000000..c361f3497a3 --- /dev/null +++ b/src/plugins/callgrind/workarounds.cpp @@ -0,0 +1,51 @@ +/************************************************************************** +** +** 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 "workarounds.h" + +#include + +#include + +QPalette panelPalette(const QPalette &oldPalette, bool lightColored) +{ + QColor color = Utils::StyleHelper::panelTextColor(lightColored); + QPalette pal = oldPalette; + pal.setBrush(QPalette::All, QPalette::WindowText, color); + pal.setBrush(QPalette::All, QPalette::ButtonText, color); + pal.setBrush(QPalette::All, QPalette::Foreground, color); + color.setAlpha(100); + pal.setBrush(QPalette::Disabled, QPalette::WindowText, color); + pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color); + pal.setBrush(QPalette::Disabled, QPalette::Foreground, color); + return pal; +} diff --git a/src/plugins/callgrind/workarounds.h b/src/plugins/callgrind/workarounds.h new file mode 100644 index 00000000000..7a4be0eb896 --- /dev/null +++ b/src/plugins/callgrind/workarounds.h @@ -0,0 +1,45 @@ +/************************************************************************** +** +** 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 WORKAROUNDS_H +#define WORKAROUNDS_H + +#include + +QT_BEGIN_NAMESPACE +class QPalette; +QT_END_NAMESPACE + +///FIXME: remove this once http://bugreports.qt.nokia.com/browse/QTCREATORBUG-3247 gets fixed +QPalette panelPalette(const QPalette &oldPalette, bool lightColored = false); + +#endif // WORKAROUNDS_H diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 952ab710bc3..67d647fb431 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -44,7 +44,8 @@ SUBDIRS = plugin_coreplugin \ !win32 { SUBDIRS += plugin_valgrindtoolbase \ - plugin_memcheck + plugin_memcheck \ + plugin_callgrind } linux-* { @@ -263,6 +264,11 @@ plugin_analyzerbase.depends += plugin_projectexplorer plugin_memcheck.depends += plugin_analyzerbase plugin_memcheck.depends += plugin_valgrindtoolbase + plugin_callgrind.subdir = callgrind + plugin_callgrind.depends = plugin_coreplugin + plugin_callgrind.depends += plugin_analyzerbase + plugin_callgrind.depends += plugin_valgrindtoolbase + plugin_qmlprofiler.subdir = qmlprofiler plugin_qmlprofiler.depends = plugin_coreplugin plugin_qmlprofiler.depends = plugin_analyzerbase