Skip to content

Commit

Permalink
use QTextLayout for resultsdisassemblypage
Browse files Browse the repository at this point in the history
This patch replaces the usage of QTextDocument in the sourcecode and
disassembly view. QTextDocument is way to overkill for that job.
This patch also includes an highlighter based on ansi codes, which can
be used instead of KSyntaxHighlighting for objdump (if supported).
  • Loading branch information
lievenhey committed Oct 23, 2023
1 parent cdc66a4 commit fd9546c
Show file tree
Hide file tree
Showing 13 changed files with 439 additions and 235 deletions.
3 changes: 2 additions & 1 deletion src/models/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ add_library(
disassemblyoutput.cpp
eventmodel.cpp
filterandzoomstack.cpp
formattingutils.cpp
frequencymodel.cpp
highlighter.cpp
highlightedtext.cpp
processfiltermodel.cpp
processlist_unix.cpp
processmodel.cpp
Expand Down
39 changes: 14 additions & 25 deletions src/models/disassemblymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,15 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/

#include <QFontDatabase>
#include <QTextBlock>
#include <QTextDocument>

#include "disassemblymodel.h"

#include "highlighter.hpp"
#include "search.h"
#include "sourcecodemodel.h"

DisassemblyModel::DisassemblyModel(KSyntaxHighlighting::Repository* repository, QObject* parent)
: QAbstractTableModel(parent)
, m_document(new QTextDocument(this))
, m_highlighter(new Highlighter(m_document, repository, this))
, m_highlightedText(repository)
{
m_document->setUndoRedoEnabled(false);
}

DisassemblyModel::~DisassemblyModel() = default;
Expand Down Expand Up @@ -56,17 +49,13 @@ void DisassemblyModel::setDisassembly(const DisassemblyOutput& disassemblyOutput
m_results = results;
m_numTypes = results.selfCosts.numTypes();

m_document->clear();

QTextCursor cursor(m_document);
cursor.beginEditBlock();
for (const auto& it : disassemblyOutput.disassemblyLines) {
cursor.insertText(it.disassembly);
cursor.insertBlock();
}
cursor.endEditBlock();
QStringList assemblyLines;
assemblyLines.reserve(disassemblyOutput.disassemblyLines.size());
std::transform(disassemblyOutput.disassemblyLines.cbegin(), disassemblyOutput.disassemblyLines.cend(),
std::back_inserter(assemblyLines),
[](const DisassemblyOutput::DisassemblyLine& line) { return line.disassembly; });

m_document->setTextWidth(m_document->idealWidth());
m_highlightedText.setText(assemblyLines);

endResetModel();
}
Expand Down Expand Up @@ -110,6 +99,7 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const
}

const auto& data = m_data.disassemblyLines.at(index.row());
const auto& line = m_highlightedText.textAt(index.row());
if (role == AddrRole)
return data.addr;

Expand All @@ -123,10 +113,10 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const
} else if (index.column() == BranchColumn) {
return data.branchVisualisation;
} else if (index.column() == DisassemblyColumn) {
const auto block = m_document->findBlockByLineNumber(index.row());
if (role == SyntaxHighlightRole)
return QVariant::fromValue(block.layout()->lineAt(0));
return block.text();
if (role == SyntaxHighlightRole) {
return QVariant::fromValue(m_highlightedText.lineAt(index.row()));
}
return m_highlightedText.textAt(index.row());
}
}

Expand All @@ -149,7 +139,7 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const
return totalCost;
} else if (role == Qt::ToolTipRole) {
auto tooltip = tr("addr: <tt>%1</tt><br/>assembly: <tt>%2</tt><br/>disassembly: <tt>%3</tt>")
.arg(QString::number(data.addr, 16), data.disassembly);
.arg(QString::number(data.addr, 16), line);
return Util::formatTooltip(tooltip, locationCost, m_results.selfCosts);
}

Expand All @@ -158,8 +148,7 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const
return Util::formatCostRelative(costLine, totalCost, true);
} else {
if (role == Qt::ToolTipRole)
return tr("<qt><tt>%1</tt><hr/>No samples at this location.</qt>")
.arg(data.disassembly.toHtmlEscaped());
return tr("<qt><tt>%1</tt><hr/>No samples at this location.</qt>").arg(line.toHtmlEscaped());
else
return QString();
}
Expand Down
11 changes: 4 additions & 7 deletions src/models/disassemblymodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@

#include "data.h"
#include "disassemblyoutput.h"

class QTextDocument;
class Highlighter;
#include "highlightedtext.h"

namespace KSyntaxHighlighting {
class Definition;
Expand Down Expand Up @@ -47,9 +45,9 @@ class DisassemblyModel : public QAbstractTableModel
Data::FileLine fileLineForIndex(const QModelIndex& index) const;
QModelIndex indexForFileLine(const Data::FileLine& line) const;

Highlighter* highlighter() const
HighlightedText* highlightedText()
{
return m_highlighter;
return &m_highlightedText;
}

enum Columns
Expand Down Expand Up @@ -81,8 +79,7 @@ public slots:
void find(const QString& search, Direction direction, int offset);

private:
QTextDocument* m_document;
Highlighter* m_highlighter;
HighlightedText m_highlightedText;
DisassemblyOutput m_data;
Data::CallerCalleeResults m_results;
int m_numTypes = 0;
Expand Down
33 changes: 29 additions & 4 deletions src/models/disassemblyoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,46 @@
#include <QProcess>
#include <QStandardPaths>

#include "formattingutils.h"

namespace {
Q_LOGGING_CATEGORY(disassemblyoutput, "hotspot.disassemblyoutput")

bool canVisualizeJumps(const QString& objdump)
QString objdumpHelp(const QString& objdump)
{
QProcess process;
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
process.start(objdump, {QStringLiteral("-H")});
if (!process.waitForFinished(1000)) {
qCWarning(disassemblyoutput) << "failed to query objdump help output:" << objdump << process.errorString();
return false;
return {};
}
const auto help = process.readAllStandardOutput();
return help.contains("--visualize-jumps");
return QString::fromUtf8(help);
}

bool canVisualizeJumps(const QString& objdump)
{
return objdumpHelp(objdump).contains(QStringLiteral("--visualize-jumps"));
}

bool canUseSyntaxHighlighting(const QString& objdump)
{
return objdumpHelp(objdump).contains(QStringLiteral("--disassembler-color"));
}

DisassemblyOutput::LinkedFunction extractLinkedFunction(const QString& disassembly)
DisassemblyOutput::LinkedFunction extractLinkedFunction(const QString& disassemblyWithAnsi)
{
DisassemblyOutput::LinkedFunction function = {};

const auto escapeChar = QLatin1Char('\u001B');

const auto disassembly =
disassemblyWithAnsi.contains(escapeChar) ? utils::removeAnsi(disassemblyWithAnsi) : disassemblyWithAnsi;

const auto leftBracketIndex = disassembly.indexOf(QLatin1Char('<'));
const auto rightBracketIndex = disassembly.indexOf(QLatin1Char('>'));

if (leftBracketIndex != -1 && rightBracketIndex != -1) {
if (leftBracketIndex < rightBracketIndex) {
function.name = disassembly.mid(leftBracketIndex + 1, rightBracketIndex - leftBracketIndex - 1);
Expand All @@ -61,6 +79,7 @@ DisassemblyOutput::LinkedFunction extractLinkedFunction(const QString& disassemb
}
}
}

return function;
}

Expand Down Expand Up @@ -300,6 +319,12 @@ DisassemblyOutput DisassemblyOutput::disassemble(const QString& objdump, const Q
else
qCInfo(disassemblyoutput) << "objdump binary does not support `--visualize-jumps`:" << processPath;

if (canUseSyntaxHighlighting(processPath)) {
arguments.append(QStringLiteral("--disassembler-color=color"));
} else {
qCInfo(disassemblyoutput) << "objdump binary does not support `--disassembler-color`:" << processPath;
}

auto binary = findBinaryForSymbol(debugPaths, extraLibPaths, symbol);
if (binary.isEmpty()) {
disassemblyOutput.errorMessage +=
Expand Down
24 changes: 24 additions & 0 deletions src/models/formattingutils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
SPDX-FileCopyrightText: Lieven Hey <[email protected]>
SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected]
SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "formattingutils.h"

QString utils::removeAnsi(const QString& stringWithAnsi)
{
const static QChar escapeChar = QLatin1Char('\u001B');
if (!stringWithAnsi.contains(escapeChar)) {
return stringWithAnsi;
}

QString ansiFreeString = stringWithAnsi;
while (ansiFreeString.contains(escapeChar)) {
const auto escapeStart = ansiFreeString.indexOf(escapeChar);
const auto escapeEnd = ansiFreeString.indexOf(QLatin1Char('m'), escapeStart);
ansiFreeString.remove(escapeStart, escapeEnd - escapeStart + 1);
}
return ansiFreeString;
}
14 changes: 14 additions & 0 deletions src/models/formattingutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
SPDX-FileCopyrightText: Lieven Hey <[email protected]>
SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected]
SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once

#include <QString>

namespace utils {
QString removeAnsi(const QString& stringWithAnsi);
}
Loading

0 comments on commit fd9546c

Please sign in to comment.