Skip to content

Commit

Permalink
Add context menu with option to jump to Caller/Callee tab from
Browse files Browse the repository at this point in the history
Bottom-Up, Top-Down, and Flame-Graph.

Fixes KDAB#33
  • Loading branch information
nwrogers committed Mar 14, 2017
1 parent 5790009 commit 2ec4ec5
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 12 deletions.
11 changes: 11 additions & 0 deletions src/flamegraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <QCheckBox>
#include <QDoubleSpinBox>
#include <QCursor>
#include <QMenu>

#include <ThreadWeaver/ThreadWeaver>
#include <KLocalizedString>
Expand Down Expand Up @@ -447,6 +448,16 @@ bool FlameGraph::eventFilter(QObject* object, QEvent* event)
updateTooltip();
} else if (event->type() == QEvent::Hide) {
setData(nullptr);
} else if (event->type() == QEvent::ContextMenu) {
QMenu contextMenu;
auto *viewCallerCallee = contextMenu.addAction(tr("View Caller/Callee"));

QPoint itemPosition(QCursor::pos().x()-1, QCursor::pos().y()-1);
auto item = static_cast<FrameGraphicsItem*>(m_view->itemAt(m_view->mapFromGlobal(itemPosition)));
QAction *action = contextMenu.exec(QCursor::pos());
if (item && action == viewCallerCallee) {
emit jumpToCallerCallee(item->symbol());
}
}
return ret;
}
Expand Down
3 changes: 3 additions & 0 deletions src/flamegraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class FlameGraph : public QWidget
private slots:
void setData(FrameGraphicsItem* rootItem);

signals:
void jumpToCallerCallee(const Data::Symbol& symbol);

private:
void setTooltipItem(const FrameGraphicsItem* item);
void updateTooltip();
Expand Down
61 changes: 50 additions & 11 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ void setupTreeView(QTreeView* view, KFilterProxySearchLine* filter, Model* model
view->sortByColumn(Model::InitialSortColumn);
view->setModel(proxy);
stretchFirstColumn(view);

view->setContextMenuPolicy(Qt::CustomContextMenu);
}

template<typename Model>
Expand Down Expand Up @@ -150,11 +152,13 @@ MainWindow::MainWindow(QWidget *parent) :
auto bottomUpCostModel = new BottomUpModel(this);
setupTreeView(ui->bottomUpTreeView, ui->bottomUpSearch, bottomUpCostModel);
ui->bottomUpTreeView->setItemDelegateForColumn(BottomUpModel::Cost, treeViewCostDelegate);
connect(ui->bottomUpTreeView, &QTreeView::customContextMenuRequested, this, &MainWindow::onBottomUpContextMenu);

auto topDownCostModel = new TopDownModel(this);
setupTreeView(ui->topDownTreeView, ui->topDownSearch, topDownCostModel);
ui->topDownTreeView->setItemDelegateForColumn(TopDownModel::SelfCost, treeViewCostDelegate);
ui->topDownTreeView->setItemDelegateForColumn(TopDownModel::InclusiveCost, treeViewCostDelegate);
connect(ui->topDownTreeView, &QTreeView::customContextMenuRequested, this, &MainWindow::onTopDownContextMenu);

auto topHotspotsProxy = new TopProxy(this);
topHotspotsProxy->setSourceModel(bottomUpCostModel);
Expand All @@ -163,12 +167,12 @@ MainWindow::MainWindow(QWidget *parent) :
ui->topHotspotsTableView->setModel(topHotspotsProxy);
stretchFirstColumn(ui->topHotspotsTableView);

auto callerCalleeCostModel = new CallerCalleeModel(this);
auto callerCalleeProxy = new QSortFilterProxyModel(this);
callerCalleeProxy->setSourceModel(callerCalleeCostModel);
ui->callerCalleeFilter->setProxy(callerCalleeProxy);
m_callerCalleeCostModel = new CallerCalleeModel(this);
m_callerCalleeProxy = new QSortFilterProxyModel(this);
m_callerCalleeProxy->setSourceModel(m_callerCalleeCostModel);
ui->callerCalleeFilter->setProxy(m_callerCalleeProxy);
ui->callerCalleeTableView->setSortingEnabled(true);
ui->callerCalleeTableView->setModel(callerCalleeProxy);
ui->callerCalleeTableView->setModel(m_callerCalleeProxy);
ui->callerCalleeTableView->hideColumn(CallerCalleeModel::Callers);
ui->callerCalleeTableView->hideColumn(CallerCalleeModel::Callees);
stretchFirstColumn(ui->callerCalleeTableView);
Expand All @@ -191,8 +195,8 @@ MainWindow::MainWindow(QWidget *parent) :
});

connect(m_parser, &PerfParser::callerCalleeDataAvailable,
this, [this, callerCalleeCostModel] (const Data::CallerCalleeEntryMap& data) {
callerCalleeCostModel->setData(data);
this, [this] (const Data::CallerCalleeEntryMap& data) {
m_callerCalleeCostModel->setData(data);
auto view = ui->callerCalleeTableView;
view->sortByColumn(CallerCalleeModel::InclusiveCost);
view->setCurrentIndex(view->model()->index(0, 0, {}));
Expand All @@ -214,10 +218,10 @@ MainWindow::MainWindow(QWidget *parent) :
});

auto calleesModel = setupCallerOrCalleeView<CalleeModel>(ui->calleesView, ui->callerCalleeTableView,
callerCalleeCostModel, callerCalleeProxy);
m_callerCalleeCostModel, m_callerCalleeProxy);

auto callersModel = setupCallerOrCalleeView<CallerModel>(ui->callersView, ui->callerCalleeTableView,
callerCalleeCostModel, callerCalleeProxy);
m_callerCalleeCostModel, m_callerCalleeProxy);

auto sourceMapModel = setupModelAndProxyForView<SourceMapModel>(ui->sourceMapView);

Expand All @@ -232,7 +236,7 @@ MainWindow::MainWindow(QWidget *parent) :
});

connect(m_parser, &PerfParser::summaryDataAvailable,
this, [this, bottomUpCostModel, topDownCostModel, callerCalleeCostModel, calleesModel, callersModel, sourceMapModel] (const SummaryData& data) {
this, [this, bottomUpCostModel, topDownCostModel, calleesModel, callersModel, sourceMapModel] (const SummaryData& data) {
auto formatSummaryText = [] (const QString& description, const QString& value) -> QString {
return QString(QLatin1String("<tr><td>") + description + QLatin1String(": </td><td>")
+ value + QLatin1String("</td></tr>"));
Expand Down Expand Up @@ -274,7 +278,7 @@ MainWindow::MainWindow(QWidget *parent) :

bottomUpCostModel->setSampleCount(data.sampleCount);
topDownCostModel->setSampleCount(data.sampleCount);
callerCalleeCostModel->setSampleCount(data.sampleCount);
m_callerCalleeCostModel->setSampleCount(data.sampleCount);
calleesModel->setSampleCount(data.sampleCount);
callersModel->setSampleCount(data.sampleCount);
sourceMapModel->setSampleCount(data.sampleCount);
Expand All @@ -289,6 +293,8 @@ MainWindow::MainWindow(QWidget *parent) :
}
});

connect(ui->flameGraph, &FlameGraph::jumpToCallerCallee, this, &MainWindow::jumpToCallerCallee);

for (int i = 0, c = ui->resultsTabWidget->count(); i < c; ++i) {
ui->resultsTabWidget->setTabToolTip(i, ui->resultsTabWidget->widget(i)->toolTip());
}
Expand Down Expand Up @@ -367,3 +373,36 @@ void MainWindow::aboutHotspot()
dialog.adjustSize();
dialog.exec();
}

void MainWindow::customContextMenu(const QPoint &point, QTreeView* view, int symbolRole)
{
const auto index = view->indexAt(point);
if (!index.isValid()) {
return;
}

QMenu contextMenu;
auto *viewCallerCallee = contextMenu.addAction(tr("View Caller/Callee"));
auto *action = contextMenu.exec(QCursor::pos());
if (action == viewCallerCallee) {
const auto symbol = index.data(symbolRole).value<Data::Symbol>();
jumpToCallerCallee(symbol);
}
}

void MainWindow::onBottomUpContextMenu(const QPoint &point)
{
customContextMenu(point, ui->bottomUpTreeView, BottomUpModel::SymbolRole);
}

void MainWindow::onTopDownContextMenu(const QPoint &point)
{
customContextMenu(point, ui->topDownTreeView, TopDownModel::SymbolRole);
}

void MainWindow::jumpToCallerCallee(const Data::Symbol &symbol)
{
auto callerCalleeIndex = m_callerCalleeProxy->mapFromSource(m_callerCalleeCostModel->indexForSymbol(symbol));
ui->callerCalleeTableView->setCurrentIndex(callerCalleeIndex);
ui->resultsTabWidget->setCurrentWidget(ui->callerCalleeTab);
}
14 changes: 14 additions & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ namespace Ui {
class MainWindow;
}

namespace Data {
struct Symbol;
}

class PerfParser;
class CallerCalleeModel;
class QSortFilterProxyModel;
class QTreeView;

class MainWindow : public QMainWindow
{
Expand All @@ -55,7 +62,14 @@ public slots:
private slots:
void on_openFileButton_clicked();

void customContextMenu(const QPoint &point, QTreeView* view, int symbolRole);
void onBottomUpContextMenu(const QPoint &pos);
void onTopDownContextMenu(const QPoint &pos);
void jumpToCallerCallee(const Data::Symbol &symbol);

private:
QScopedPointer<Ui::MainWindow> ui;
PerfParser* m_parser;
CallerCalleeModel* m_callerCalleeCostModel;
QSortFilterProxyModel* m_callerCalleeProxy;
};
12 changes: 12 additions & 0 deletions src/models/hashmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <QAbstractTableModel>
#include <QHash>

#include "data.h"

template<typename Rows, typename ModelImpl>
class HashModel : public QAbstractTableModel
{
Expand Down Expand Up @@ -104,6 +106,16 @@ class HashModel : public QAbstractTableModel
return index(row, column);
}

QModelIndex indexForSymbol(const Data::Symbol& symbol)
{
auto it = m_rows.find(symbol);
if (it == m_rows.end()) {
return {};
}
const int row = std::distance(m_rows.begin(), it);
return createIndex(row, 0);
}

private:
Rows m_rows;
quint64 m_sampleCount = 0;
Expand Down
5 changes: 4 additions & 1 deletion src/models/treemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class AbstractTreeModel : public QAbstractItemModel
enum Roles {
SortRole = Qt::UserRole,
TotalCostRole,
FilterRole
FilterRole,
SymbolRole
};
};

Expand Down Expand Up @@ -143,6 +144,8 @@ class TreeModel : public AbstractTreeModel
return ModelImpl::displayData(item, static_cast<typename ModelImpl::Columns>(index.column()));
} else if (role == TotalCostRole) {
return m_sampleCount;
} else if (role == SymbolRole) {
return QVariant::fromValue(item->symbol);
}

// TODO: tooltips
Expand Down

0 comments on commit 2ec4ec5

Please sign in to comment.