aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/ctfvisualizer
diff options
context:
space:
mode:
authorTim Henning <tim.henning@kdab.com>2019-08-29 11:45:45 +0200
committerTim Henning <tim.henning@kdab.com>2019-08-29 13:37:04 +0000
commit7fec4182059f2841239a06cc2402110aaa2a1ab4 (patch)
treeb5ccfc605c43af64a7259ae4b2e61865c1e75479 /src/plugins/ctfvisualizer
parent41361047b44282033ae13842e6f6d425b45b3d3a (diff)
Tracing: Add Chrome Trace Format Visualizer plugin
This new plugin adds a viewer for Chrome Trace Format (CTF) files (aka Trace Event Format). It uses the same UI components as the QML Profiler timeline and the Perf Profiler. The Trace Event Format is generated by different kinds of tracing tools. Usually the files are display with the trace-viewer, built into Chrome (chrome://tracing). This plugin was developed because of the high memory usage of trace-viewer, which makes it difficult to use with trace files bigger than 100 MB. The plugin fully supports all event types used in data generated by LTTng, converted to CTF by https://github.com/KDAB/ctf2ctf. Some of the more advanced event types used for example in Android system traces, though, are not supported. The viewer will silently ignore unsupported event types. Supported Event Types: - Begin, End, Duration and Instant events - Counter events (graphs) - Metadata events (process and thread name) The plugin uses nlohmann/json instead of QJson because of the ~128 MB object size limit by QJson. [ChangeLog][Tracing][CtfVisualizer] Added Chrome Trace Format Visualizer plugin Change-Id: I5969f7f83f3305712d4aec04487e2403510af64b Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/plugins/ctfvisualizer')
-rw-r--r--src/plugins/ctfvisualizer/CtfVisualizer.json.in20
-rw-r--r--src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp189
-rw-r--r--src/plugins/ctfvisualizer/ctfstatisticsmodel.h84
-rw-r--r--src/plugins/ctfvisualizer/ctfstatisticsview.cpp84
-rw-r--r--src/plugins/ctfvisualizer/ctfstatisticsview.h52
-rw-r--r--src/plugins/ctfvisualizer/ctftimelinemodel.cpp383
-rw-r--r--src/plugins/ctfvisualizer/ctftimelinemodel.h115
-rw-r--r--src/plugins/ctfvisualizer/ctftracemanager.cpp256
-rw-r--r--src/plugins/ctfvisualizer/ctftracemanager.h92
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizer.pro34
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizer_dependencies.pri9
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizerconstants.h58
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizerplugin.cpp58
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizerplugin.h49
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizertool.cpp187
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizertool.h86
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizertraceview.cpp85
-rw-r--r--src/plugins/ctfvisualizer/ctfvisualizertraceview.h51
18 files changed, 1892 insertions, 0 deletions
diff --git a/src/plugins/ctfvisualizer/CtfVisualizer.json.in b/src/plugins/ctfvisualizer/CtfVisualizer.json.in
new file mode 100644
index 00000000000..78b6e093f0a
--- /dev/null
+++ b/src/plugins/ctfvisualizer/CtfVisualizer.json.in
@@ -0,0 +1,20 @@
+{
+ \"Name\" : \"CtfVisualizer\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Revision\" : \"$$QTC_PLUGIN_REVISION\",
+ \"Vendor\" : \"KDAB Group, www.kdab.com\",
+ \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\",
+ \"License\" : [ \"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 The Qt Company.\",
+ \"\",
+ \"GNU General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html.\"
+ ],
+ \"Category\" : \"Code Analyzer\",
+ \"Description\" : \"Chrome Trace Format Visualizer Plugin.\",
+ \"Url\" : \"https://www.kdab.com\",
+ $$dependencyList
+}
diff --git a/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp b/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp
new file mode 100644
index 00000000000..bdf88eaf5c2
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "ctfstatisticsmodel.h"
+
+#include "ctfvisualizerconstants.h"
+
+#include <tracing/timelineformattime.h>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+using json = nlohmann::json;
+using namespace Constants;
+
+CtfStatisticsModel::CtfStatisticsModel(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+
+}
+
+void CtfStatisticsModel::beginLoading()
+{
+ beginResetModel();
+ m_data.clear();
+}
+
+void CtfStatisticsModel::addEvent(const json &event, qint64 durationInNs)
+{
+ const std::string name = event.value(CtfEventNameKey, "");
+
+ EventData &data = m_data[QString::fromStdString(name)];
+ ++data.count;
+ if (durationInNs >= 0) {
+ data.totalDuration += durationInNs;
+ data.minDuration = std::min(data.minDuration, durationInNs);
+ data.maxDuration = std::max(data.maxDuration, durationInNs);
+ }
+}
+
+void CtfStatisticsModel::endLoading()
+{
+ endResetModel();
+}
+
+int CtfStatisticsModel::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : m_data.size();
+}
+
+int CtfStatisticsModel::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : Column::COUNT;
+}
+
+QVariant CtfStatisticsModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ QString title = m_data.keys().at(index.row());
+
+ switch (role) {
+ case Qt::TextAlignmentRole:
+ switch (index.column()) {
+ case Column::Title:
+ return Qt::AlignLeft;
+ case Column::Count:
+ case Column::TotalDuration:
+ case Column::MinDuration:
+ case Column::AvgDuration:
+ case Column::MaxDuration:
+ return Qt::AlignRight;
+ }
+ case SortRole:
+ switch (index.column()) {
+ case Column::Title:
+ return title;
+ case Column::Count:
+ return m_data.value(title).count;
+ case Column::TotalDuration:
+ return m_data.value(title).totalDuration;
+ case Column::MinDuration:
+ {
+ auto minDuration = m_data.value(title).minDuration;
+ return minDuration != std::numeric_limits<qint64>::max() ? minDuration : 0;
+ }
+ case Column::AvgDuration:
+ {
+ auto data = m_data.value(title);
+ if (data.totalDuration > 0 && data.count > 0)
+ return double(data.totalDuration) / data.count;
+ return 0;
+ }
+ case Column::MaxDuration:
+ return m_data.value(title).maxDuration;
+ default:
+ return QVariant();
+ }
+ case Qt::DisplayRole:
+ switch (index.column()) {
+ case Column::Title:
+ return title;
+ case Column::Count:
+ return m_data.value(title).count;
+ case Column::TotalDuration:
+ {
+ auto totalDuration = m_data.value(title).totalDuration;
+ if (totalDuration > 0)
+ return Timeline::formatTime(totalDuration);
+ else
+ return "-";
+ }
+ case Column::MinDuration:
+ {
+ auto minDuration = m_data.value(title).minDuration;
+ if (minDuration != std::numeric_limits<qint64>::max())
+ return Timeline::formatTime(minDuration);
+ else
+ return "-";
+ }
+ case Column::AvgDuration:
+ {
+ auto data = m_data.value(title);
+ if (data.totalDuration > 0 && data.count > 0)
+ return Timeline::formatTime(data.totalDuration / data.count);
+ return "-";
+ }
+ case Column::MaxDuration:
+ {
+ auto maxDuration = m_data.value(title).maxDuration;
+ if (maxDuration > 0)
+ return Timeline::formatTime(maxDuration);
+ else
+ return "-";
+ }
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant CtfStatisticsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
+ return QAbstractTableModel::headerData(section, orientation, role);
+
+ switch (section) {
+ case Column::Title:
+ return tr("Title");
+ case Column::Count:
+ return tr("Count");
+ case Column::TotalDuration:
+ return tr("Total Time");
+ case Column::MinDuration:
+ return tr("Minimum Time");
+ case Column::AvgDuration:
+ return tr("Average Time");
+ case Column::MaxDuration:
+ return tr("Maximum Time");
+ default:
+ return "";
+ }
+}
+
+} // Internal
+} // CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfstatisticsmodel.h b/src/plugins/ctfvisualizer/ctfstatisticsmodel.h
new file mode 100644
index 00000000000..2465d793a3b
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfstatisticsmodel.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "libs/3rdparty/json/json.hpp"
+
+#include <QHash>
+#include <QStack>
+#include <QVector>
+#include <QPointer>
+#include <QAbstractTableModel>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfStatisticsModel : public QAbstractTableModel
+{
+
+public:
+ enum Role {
+ SortRole = Qt::UserRole + 1,
+ };
+
+ enum Column {
+ Title = 0,
+ Count,
+ TotalDuration,
+ MinDuration,
+ AvgDuration,
+ MaxDuration,
+ COUNT
+ };
+
+ struct EventData {
+ int count = 0;
+ qint64 totalDuration = 0.0;
+ qint64 minDuration = std::numeric_limits<qint64>::max();
+ qint64 maxDuration = 0.0;
+ };
+
+ explicit CtfStatisticsModel(QObject *parent);
+ ~CtfStatisticsModel() override = default;
+
+ void beginLoading();
+ void addEvent(const nlohmann::json &event, qint64 duration);
+ void endLoading();
+
+private:
+
+ int rowCount(const QModelIndex &parent) const override;
+ int columnCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+ QHash<QString, EventData> m_data;
+
+};
+
+} // Internal
+} // CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfstatisticsview.cpp b/src/plugins/ctfvisualizer/ctfstatisticsview.cpp
new file mode 100644
index 00000000000..16c886249a1
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfstatisticsview.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "ctfstatisticsview.h"
+
+#include "ctfstatisticsmodel.h"
+
+#include <QHeaderView>
+#include <QSortFilterProxyModel>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+CtfStatisticsView::CtfStatisticsView(CtfStatisticsModel *model, QWidget *parent)
+ : Utils::TreeView(parent)
+{
+ setObjectName(QLatin1String("CtfVisualizerStatisticsView"));
+
+ auto sortModel = new QSortFilterProxyModel(this);
+ sortModel->setSourceModel(model);
+ sortModel->setSortRole(CtfStatisticsModel::SortRole);
+ sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+
+ setModel(sortModel);
+
+ header()->setSectionResizeMode(QHeaderView::Interactive);
+ header()->setDefaultSectionSize(100);
+ header()->setMinimumSectionSize(50);
+ header()->setStretchLastSection(false);
+ header()->setSectionResizeMode(CtfStatisticsModel::Column::Title, QHeaderView::Stretch);
+ setRootIsDecorated(false);
+ setUniformRowHeights(true);
+ setSortingEnabled(true);
+
+ connect(selectionModel(), &QItemSelectionModel::currentChanged,
+ [this] (const QModelIndex &current, const QModelIndex &previous)
+ {
+ Q_UNUSED(previous);
+ QModelIndex index = this->model()->index(current.row(), CtfStatisticsModel::Title);
+ QString title = this->model()->data(index).toString();
+ emit this->eventTypeSelected(title);
+ });
+}
+
+void CtfStatisticsView::selectByTitle(const QString &title)
+{
+ auto model = this->model();
+ for (int row = 0; row < model->rowCount(); ++row)
+ {
+ auto index = model->index(row, CtfStatisticsModel::Column::Title);
+ if (model->data(index).toString() == title)
+ {
+ QItemSelection selection(index, model->index(row, CtfStatisticsModel::Column::COUNT - 1));
+ selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
+ scrollTo(index);
+ break;
+ }
+ }
+}
+
+} // Internal
+} // CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfstatisticsview.h b/src/plugins/ctfvisualizer/ctfstatisticsview.h
new file mode 100644
index 00000000000..3e94e0115f1
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfstatisticsview.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "ctfvisualizerconstants.h"
+
+#include <utils/itemviews.h>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfStatisticsModel;
+
+class CtfStatisticsView : public Utils::TreeView
+{
+ Q_OBJECT
+public:
+ explicit CtfStatisticsView(CtfStatisticsModel *model, QWidget *parent = nullptr);
+ ~CtfStatisticsView() override = default;
+
+ void selectByTitle(const QString &title);
+
+signals:
+ void eventTypeSelected(const QString &title);
+};
+
+} // Internal
+} // CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctftimelinemodel.cpp b/src/plugins/ctfvisualizer/ctftimelinemodel.cpp
new file mode 100644
index 00000000000..4b0d6b1a61b
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctftimelinemodel.cpp
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "ctftimelinemodel.h"
+
+#include "ctftracemanager.h"
+#include "ctfvisualizerconstants.h"
+
+#include <tracing/timelineformattime.h>
+#include <tracing/timelinemodelaggregator.h>
+#include <utils/qtcassert.h>
+
+#include <QDebug>
+
+#include <string>
+
+
+namespace CtfVisualizer {
+namespace Internal {
+
+using json = nlohmann::json;
+using namespace Constants;
+
+CtfTimelineModel::CtfTimelineModel(Timeline::TimelineModelAggregator *parent,
+ CtfTraceManager *traceManager, int tid, int pid)
+ : Timeline::TimelineModel (parent)
+ , m_traceManager(traceManager)
+ , m_threadId(tid)
+ , m_processId(pid)
+{
+ updateName();
+ setCollapsedRowCount(1);
+ setCategoryColor(colorByHue(pid * 25));
+ setHasMixedTypesInExpandedState(true);
+}
+
+QRgb CtfTimelineModel::color(int index) const
+{
+ return colorBySelectionId(index);
+}
+
+QVariantList CtfTimelineModel::labels() const
+{
+ QVariantList result;
+
+ QVector<std::string> sortedCounterNames = m_counterNames;
+ std::sort(sortedCounterNames.begin(), sortedCounterNames.end());
+ for (int i = 0; i < sortedCounterNames.size(); ++i) {
+ QVariantMap element;
+ element.insert(QLatin1String("description"), QString("~ %1").arg(QString::fromStdString(sortedCounterNames[i])));
+ element.insert(QLatin1String("id"), i);
+ result << element;
+ }
+
+ for (int i = 0; i < m_maxStackSize; ++i) {
+ QVariantMap element;
+ element.insert(QLatin1String("description"), QStringLiteral("- ").append(tr("Stack Level %1").arg(i)));
+ element.insert(QLatin1String("id"), m_counterNames.size() + i);
+ result << element;
+ }
+ return result;
+}
+
+QVariantMap CtfTimelineModel::orderedDetails(int index) const
+{
+ QMap<int, QPair<QString, QString>> info = m_details.value(index);
+ info.insert(2, {tr("Start"), Timeline::formatTime(startTime(index))});
+ info.insert(3, {tr("Wall Duration"), Timeline::formatTime(duration(index))});
+ QVariantMap data;
+ QString title = info.value(0).second;
+ data.insert("title", title);
+ QVariantList content;
+ auto it = info.constBegin();
+ auto end = info.constEnd();
+ ++it; // skip title
+ while (it != end) {
+ content.append(it.value().first);
+ content.append(it.value().second);
+ ++it;
+ }
+ data.insert("content", content);
+ emit detailsRequested(title);
+ return data;
+}
+
+int CtfTimelineModel::expandedRow(int index) const
+{
+ // m_itemToCounterIdx[index] is 0 for non-counter indexes
+ const int counterIdx = m_itemToCounterIdx.value(index, 0);
+ if (counterIdx > 0) {
+ return m_counterIndexToRow[counterIdx - 1] + 1;
+ }
+ return m_nestingLevels.value(index) + m_counterData.size() + 1;
+}
+
+int CtfTimelineModel::collapsedRow(int index) const
+{
+ Q_UNUSED(index);
+ return 0;
+}
+
+int CtfTimelineModel::typeId(int index) const
+{
+ QTC_ASSERT(index >= 0 && index < count(), return -1);
+ return selectionId(index);
+}
+
+bool CtfTimelineModel::handlesTypeId(int typeId) const
+{
+ return m_handledTypeIds.contains(typeId);
+}
+
+float CtfTimelineModel::relativeHeight(int index) const
+{
+ // m_itemToCounterIdx[index] is 0 for non-counter indexes
+ const int counterIdx = m_itemToCounterIdx.value(index, 0);
+ if (counterIdx > 0) {
+ const CounterData &data = m_counterData[counterIdx - 1];
+ const float value = m_counterValues[index] / std::max(data.max, 1.0f);
+ return value;
+ }
+ return 1.0f;
+}
+
+QPair<bool, qint64> CtfTimelineModel::addEvent(const json &event, double timeOffset)
+{
+ const double timestamp = event.value(CtfTracingClockTimestampKey, 0.0);
+ const qint64 normalizedTime = qint64((timestamp - timeOffset) * 1000);
+ const std::string eventPhase = event.value(CtfEventPhaseKey, "");
+ const std::string name = event.value(CtfEventNameKey, "");
+ qint64 duration = -1;
+
+ const int selectionId = m_traceManager->getSelectionId(name);
+ m_handledTypeIds.insert(selectionId);
+
+ bool visibleOnTimeline = false;
+ if (eventPhase == CtfEventTypeBegin || eventPhase == CtfEventTypeComplete
+ || eventPhase == CtfEventTypeInstant || eventPhase == CtfEventTypeInstantDeprecated) {
+ duration = newStackEvent(event, normalizedTime, eventPhase, name, selectionId);
+ visibleOnTimeline = true;
+ } else if (eventPhase == CtfEventTypeEnd) {
+ duration = closeStackEvent(event, timestamp, normalizedTime);
+ visibleOnTimeline = true;
+ } else if (eventPhase == CtfEventTypeCounter) {
+ addCounterValue(event, normalizedTime, name, selectionId);
+ visibleOnTimeline = true;
+ } else if (eventPhase == CtfEventTypeMetadata) {
+ const std::string name = event[CtfEventNameKey];
+ if (name == "thread_name") {
+ m_threadName = QString::fromStdString(event["args"]["name"]);
+ updateName();
+ } else if (name == "process_name") {
+ m_processName = QString::fromStdString(event["args"]["name"]);
+ updateName();
+ }
+ }
+ return {visibleOnTimeline, duration};
+}
+
+void CtfTimelineModel::finalize(double traceBegin, double traceEnd, const QString &processName, const QString &threadName)
+{
+ m_processName = processName;
+ m_threadName = threadName;
+ updateName();
+
+ qint64 normalizedEnd = qint64((traceEnd - traceBegin) * 1000);
+ while (!m_openEventIds.isEmpty()) {
+ int index = m_openEventIds.pop();
+ qint64 duration = normalizedEnd - startTime(index);
+ insertEnd(index, duration);
+ m_details[index].insert(3, {reuse(tr("Wall Duration")), Timeline::formatTime(duration)});
+ m_details[index].insert(6, {reuse(tr("Unfinished")), reuse(tr("true"))});
+ }
+ computeNesting();
+
+ QVector<std::string> sortedCounterNames = m_counterNames;
+ std::sort(sortedCounterNames.begin(), sortedCounterNames.end());
+ m_counterIndexToRow.resize(m_counterNames.size());
+ for (int i = 0; i < m_counterIndexToRow.size(); ++i) {
+ m_counterIndexToRow[i] = sortedCounterNames.indexOf(m_counterNames[i]);
+ }
+
+ // we insert an empty row in expanded state because otherwise
+ // the row label would be where the thread label is
+ setExpandedRowCount(1 + m_counterData.size() + m_maxStackSize);
+ emit contentChanged();
+}
+
+void CtfTimelineModel::updateName()
+{
+ if (m_threadName.isEmpty()) {
+ setDisplayName(tr("> Thread %1").arg(m_threadId));
+ } else {
+ setDisplayName(QString("> %1 (%2)").arg(m_threadName).arg(m_threadId));
+ }
+ QString process = m_processName.isEmpty() ? QString::number(m_processId) :
+ QString("%1 (%2)").arg(m_processName).arg(m_processId);
+ QString thread = m_threadName.isEmpty() ? QString::number(m_threadId) :
+ QString("%1 (%2)").arg(m_threadName).arg(m_threadId);
+ setTooltip(QString("Process: %1\nThread: %2").arg(process).arg(thread));
+}
+
+qint64 CtfTimelineModel::newStackEvent(const json &event, qint64 normalizedTime,
+ const std::string &eventPhase, const std::string &name,
+ int selectionId)
+{
+ int nestingLevel = m_openEventIds.size();
+ m_maxStackSize = std::max(m_maxStackSize, m_openEventIds.size() + 1);
+ int index = 0;
+ qint64 duration = -1;
+ if (eventPhase == CtfEventTypeBegin) {
+ index = insertStart(normalizedTime, selectionId);
+ m_openEventIds.push(index);
+ // if this event was inserted before existing events, we need to
+ // check whether indexes stored in m_openEventIds need to be updated (increased):
+ // (the top element is the current event and is skipped)
+ for (int i = m_openEventIds.size() - 2; i >= 0; --i) {
+ if (m_openEventIds[i] >= index) ++m_openEventIds[i];
+ }
+ } else if (eventPhase == CtfEventTypeComplete) {
+ duration = qint64(event[CtfDurationKey]) * 1000;
+ index = insert(normalizedTime, duration, selectionId);
+ for (int i = m_openEventIds.size() - 1; i >= 0; --i) {
+ if (m_openEventIds[i] >= index) {
+ ++m_openEventIds[i];
+ // if the event is before an open event, the nesting level decreases:
+ --nestingLevel;
+ }
+ }
+ } else {
+ index = insert(normalizedTime, 0, selectionId);
+ for (int i = m_openEventIds.size() - 1; i >= 0; --i) {
+ if (m_openEventIds[i] >= index) {
+ ++m_openEventIds[i];
+ --nestingLevel;
+ }
+ }
+ }
+ if (index >= m_details.size()) {
+ m_details.resize(index + 1);
+ m_details[index] = QMap<int, QPair<QString, QString>>();
+ m_nestingLevels.resize(index + 1);
+ m_nestingLevels[index] = nestingLevel;
+ } else {
+ m_details.insert(index, QMap<int, QPair<QString, QString>>());
+ m_nestingLevels.insert(index, nestingLevel);
+ }
+ if (m_counterValues.size() > index) {
+ // if the event was inserted before any counter, we need
+ // to shift the values after it and update the last index:
+ m_counterValues.insert(index, 0);
+ m_itemToCounterIdx.insert(index, 0);
+ for (CounterData &counterData: m_counterData) {
+ if (counterData.startEventIndex >= index) ++counterData.startEventIndex;
+ }
+ }
+
+ if (!name.empty()) {
+ m_details[index].insert(0, {{}, reuse(QString::fromStdString(name))});
+ }
+ if (event.contains(CtfEventCategoryKey)) {
+ m_details[index].insert(1, {reuse(tr("Categories")), reuse(QString::fromStdString(event[CtfEventCategoryKey]))});
+ }
+ if (event.contains("args") && !event["args"].empty()) {
+ QString argsJson = QString::fromStdString(event["args"].dump(1));
+ // strip leading and trailing curled brackets:
+ argsJson = argsJson.size() > 4 ? argsJson.mid(2, argsJson.size() - 4) : argsJson;
+ m_details[index].insert(4, {reuse(tr("Arguments")), reuse(argsJson)});
+ }
+ if (eventPhase == CtfEventTypeInstant) {
+ m_details[index].insert(6, {reuse(tr("Instant")), reuse(tr("true"))});
+ if (event.contains("s")) {
+ std::string scope = event["s"];
+ if (scope == "g") {
+ m_details[index].insert(7, {reuse(tr("Scope")), reuse(tr("global"))});
+ } else if (scope == "p") {
+ m_details[index].insert(7, {reuse(tr("Scope")), reuse(tr("process"))});
+ } else {
+ m_details[index].insert(7, {reuse(tr("Scope")), reuse(tr("thread"))});
+ }
+ }
+ }
+ return duration;
+}
+
+qint64 CtfTimelineModel::closeStackEvent(const json &event, double timestamp, qint64 normalizedTime)
+{
+ if (m_openEventIds.isEmpty()) {
+ qWarning() << QString("End event without open 'begin' event at timestamp %1").arg(timestamp, 0, 'f');
+ return -1;
+ } else {
+ const int index = m_openEventIds.pop();
+ const qint64 duration = normalizedTime - startTime(index);
+ insertEnd(index, duration);
+ if (event.contains("args") && !event["args"].empty()) {
+ QString argsJson = QString::fromStdString(event["args"].dump(1));
+ // strip leading and trailing curled brackets:
+ argsJson = argsJson.size() > 4 ? argsJson.mid(2, argsJson.size() - 4) : argsJson;
+ m_details[index].insert(5, {reuse(tr("Return Arguments")), reuse(argsJson)});
+ }
+ return duration;
+ }
+}
+
+void CtfTimelineModel::addCounterValue(const json &event, qint64 normalizedTime,
+ const std::string &name, int selectionId)
+{
+ if (!event.contains("args")) return;
+ // CTF documentation says all keys of 'args' should be displayed in
+ // one stacked graph, but we will display them separately:
+ for (auto it: event["args"].items()) {
+ std::string counterName = event.contains("id") ?
+ name + event.value("id", "") : name;
+ const std::string &key = it.key();
+ if (key != "value") {
+ counterName += " " + key;
+ }
+ const float value = it.value();
+ int counterIndex = m_counterNames.indexOf(counterName);
+ if (counterIndex < 0) {
+ counterIndex = m_counterData.size();
+ m_counterNames.append(counterName);
+ m_counterData.append(CounterData());
+ }
+ CounterData &data = m_counterData[counterIndex];
+ if (data.startEventIndex >= 0) {
+ insertEnd(data.startEventIndex, normalizedTime - data.end);
+ }
+ const int index = insertStart(normalizedTime, selectionId);
+ data.startEventIndex = index;
+ data.end = normalizedTime;
+ data.min = std::min(data.min, value);
+ data.max = std::max(data.max, value);
+ if (index >= m_counterValues.size()) {
+ m_counterValues.resize(index + 1);
+ m_counterValues[index] = value;
+ m_itemToCounterIdx.resize(index + 1);
+ // m_itemToCounterIdx[index] == 0 is used to indicate a non-counter value
+ m_itemToCounterIdx[index] = counterIndex + 1;
+ } else {
+ m_counterValues.insert(index, value);
+ m_itemToCounterIdx.insert(index, counterIndex + 1);
+ }
+ }
+}
+
+const QString &CtfTimelineModel::reuse(const QString &value)
+{
+ auto it = m_reusableStrings.find(value);
+ if (it == m_reusableStrings.end()) {
+ m_reusableStrings.insert(value);
+ return value;
+ }
+ return *it;
+}
+
+
+} // namespace Internal
+} // namespace CtfVisualizer
+
diff --git a/src/plugins/ctfvisualizer/ctftimelinemodel.h b/src/plugins/ctfvisualizer/ctftimelinemodel.h
new file mode 100644
index 00000000000..8bc6671879a
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctftimelinemodel.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include "libs/3rdparty/json/json.hpp"
+
+#include <tracing/timelinemodel.h>
+
+#include <QMap>
+#include <QSet>
+#include <QStack>
+#include <QVector>
+
+namespace Timeline {
+class TimelineModelAggregator;
+}
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfTraceManager;
+
+class CtfTimelineModel : public Timeline::TimelineModel
+{
+ Q_OBJECT
+
+ friend class CtfTraceManager;
+
+public:
+ explicit CtfTimelineModel(Timeline::TimelineModelAggregator *parent,
+ CtfTraceManager *traceManager, int tid, int pid);
+
+ QRgb color(int index) const override;
+ QVariantList labels() const override;
+ QVariantMap orderedDetails(int index) const override;
+ int expandedRow(int index) const override;
+ int collapsedRow(int index) const override;
+
+ int typeId(int index) const override;
+ bool handlesTypeId(int typeId) const override;
+ float relativeHeight(int index) const override;
+
+ QPair<bool, qint64> addEvent(const nlohmann::json &event, double traceBegin);
+
+ void finalize(double traceBegin, double traceEnd, const QString &processName, const QString &threadName);
+
+signals:
+ void detailsRequested(const QString &eventName) const;
+
+private:
+ void updateName();
+
+ qint64 newStackEvent(const nlohmann::json &event, qint64 normalizedTime,
+ const std::string &eventPhase, const std::string &name, int selectionId);
+
+ qint64 closeStackEvent(const nlohmann::json &event, double timestamp, qint64 normalizedTime);
+
+ void addCounterValue(const nlohmann::json &event, qint64 normalizedTime, const std::string &name, int selectionId);
+
+ const QString &reuse(const QString &value);
+
+protected:
+ CtfTraceManager *const m_traceManager;
+
+ int m_threadId;
+ QString m_threadName;
+ int m_processId;
+ QString m_processName;
+
+ int m_maxStackSize = 0;
+ QVector<int> m_nestingLevels;
+ QVector<QMap<int, QPair<QString, QString>>> m_details;
+ QSet<int> m_handledTypeIds;
+ QStack<int> m_openEventIds;
+ QSet<QString> m_reusableStrings;
+
+ struct CounterData {
+ qint64 end = 0;
+ int startEventIndex = -1;
+ float min = std::numeric_limits<float>::max();
+ float max = std::numeric_limits<float>::min();
+ };
+
+ QVector<std::string> m_counterNames;
+ QVector<CounterData> m_counterData;
+ QVector<float> m_counterValues;
+ QVector<int> m_itemToCounterIdx;
+ QVector<int> m_counterIndexToRow;
+};
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctftracemanager.cpp b/src/plugins/ctfvisualizer/ctftracemanager.cpp
new file mode 100644
index 00000000000..855f8341288
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctftracemanager.cpp
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "ctftracemanager.h"
+
+#include "ctftimelinemodel.h"
+#include "ctfstatisticsmodel.h"
+#include "ctfvisualizerconstants.h"
+
+#include <coreplugin/icore.h>
+#include <tracing/timelinemodelaggregator.h>
+
+#include <QByteArray>
+#include <QDebug>
+#include <QFile>
+#include <QList>
+#include <QMessageBox>
+
+#include <fstream>
+
+
+namespace CtfVisualizer {
+namespace Internal {
+
+using json = nlohmann::json;
+
+using namespace Constants;
+
+
+class CtfJsonParserCallback
+{
+
+public:
+
+ explicit CtfJsonParserCallback(CtfTraceManager *traceManager)
+ : m_traceManager(traceManager)
+ {}
+
+ bool callback(int depth, nlohmann::json::parse_event_t event, nlohmann::json &parsed)
+ {
+ if ((event == json::parse_event_t::array_start && depth == 0)
+ || (event == json::parse_event_t::key && depth == 1 && parsed == json(CtfTraceEventsKey))) {
+ m_isInTraceArray = true;
+ m_traceArrayDepth = depth;
+ return true;
+ }
+ if (m_isInTraceArray && event == json::parse_event_t::array_end && depth == m_traceArrayDepth) {
+ m_isInTraceArray = false;
+ return false;
+ }
+ if (m_isInTraceArray && event == json::parse_event_t::object_end && depth == m_traceArrayDepth + 1) {
+ m_traceManager->addEvent(parsed);
+ return false;
+ }
+ if (m_isInTraceArray || (event == json::parse_event_t::object_start && depth == 0)) {
+ // keep outer object and values in trace objects:
+ return true;
+ }
+ // discard any objects outside of trace array:
+ // TODO: parse other data, e.g. stack frames
+ return false;
+ }
+
+protected:
+ CtfTraceManager *m_traceManager;
+
+ bool m_isInTraceArray = false;
+ int m_traceArrayDepth = 0;
+};
+
+CtfTraceManager::CtfTraceManager(QObject *parent,
+ Timeline::TimelineModelAggregator *modelAggregator,
+ CtfStatisticsModel *statisticsModel)
+ : QObject(parent)
+ , m_modelAggregator(modelAggregator)
+ , m_statisticsModel(statisticsModel)
+{
+
+}
+
+qint64 CtfTraceManager::traceDuration() const
+{
+ return qint64((m_traceEnd - m_traceBegin) * 1000);
+}
+
+qint64 CtfTraceManager::traceBegin() const
+{
+ return qint64((m_traceBegin - m_timeOffset) * 1000);
+}
+
+qint64 CtfTraceManager::traceEnd() const
+{
+ return qint64((m_traceEnd - m_timeOffset) * 1000);
+}
+
+void CtfTraceManager::addEvent(const json &event)
+{
+ const double timestamp = event.value(CtfTracingClockTimestampKey, -1.0);
+ if (timestamp < 0) {
+ // events without or with negative timestamp will be ignored
+ return;
+ }
+ if (m_timeOffset < 0) {
+ // the timestamp of the first event is used as the global offset
+ m_timeOffset = timestamp;
+ }
+
+ const int processId = event.value(CtfProcessIdKey, 0);
+ const int threadId = event.contains(CtfThreadIdKey) ? int(event[CtfThreadIdKey]) : processId;
+ if (!m_threadModels.contains(threadId)) {
+ addModelForThread(threadId, processId);
+ }
+ if (event.value(CtfEventPhaseKey, "") == CtfEventTypeMetadata) {
+ const std::string name = event[CtfEventNameKey];
+ if (name == "thread_name") {
+ m_threadNames[threadId] = QString::fromStdString(event["args"]["name"]);
+ } else if (name == "process_name") {
+ m_processNames[processId] = QString::fromStdString(event["args"]["name"]);
+ }
+ }
+
+ const QPair<bool, qint64> result = m_threadModels[threadId]->addEvent(event, m_timeOffset);
+ const bool visibleOnTimeline = result.first;
+ if (visibleOnTimeline) {
+ m_traceBegin = std::min(m_traceBegin, timestamp);
+ m_traceEnd = std::max(m_traceEnd, timestamp);
+ m_statisticsModel->addEvent(event, result.second);
+ } else if (m_timeOffset == timestamp) {
+ // this timestamp was used as the time offset but it is not a visible element
+ // -> reset the time offset again:
+ m_timeOffset = -1.0;
+ }
+}
+
+void CtfVisualizer::Internal::CtfTraceManager::load(const QString &filename)
+{
+ clearAll();
+
+ std::ifstream file(filename.toStdString());
+ if (!file.is_open()) {
+ QMessageBox::warning(Core::ICore::mainWindow(),
+ tr("CTF Visualizer"),
+ tr("Cannot read the CTF file."));
+ return;
+ }
+ CtfJsonParserCallback ctfParser(this);
+ json::parser_callback_t callback = [&ctfParser](int depth, json::parse_event_t event, json &parsed) {
+ return ctfParser.callback(depth, event, parsed);
+ };
+ m_statisticsModel->beginLoading();
+ json unusedValues = json::parse(file, callback, /*allow_exceptions*/ false);
+ m_statisticsModel->endLoading();
+ file.close();
+}
+
+void CtfTraceManager::finalize()
+{
+ bool userConsentToIgnoreDeepTraces = false;
+ for (qint64 tid: m_threadModels.keys()) {
+ if (m_threadModels[tid]->m_maxStackSize > 512) {
+ if (!userConsentToIgnoreDeepTraces) {
+ QMessageBox::StandardButton answer = QMessageBox::question(Core::ICore::mainWindow(),
+ tr("CTF Visualizer"),
+ tr("The trace contains threads with stack depth > 512.\nDo you want to display them anyway?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+ if (answer == QMessageBox::No) {
+ userConsentToIgnoreDeepTraces = true;
+ } else {
+ break;
+ }
+ }
+ m_threadModels.remove(tid);
+ }
+ }
+ for (CtfTimelineModel *model: m_threadModels) {
+ model->finalize(m_traceBegin, m_traceEnd,
+ m_processNames[model->m_processId], m_threadNames[model->m_threadId]);
+ }
+ // TimelineModelAggregator::addModel() is called here because it
+ // needs to be run in the main thread
+ addModelsToAggregator();
+}
+
+bool CtfTraceManager::isEmpty() const
+{
+ return m_threadModels.isEmpty();
+}
+
+int CtfTraceManager::getSelectionId(const std::string &name)
+{
+ auto it = m_name2selectionId.find(name);
+ if (it == m_name2selectionId.end())
+ it = m_name2selectionId.insert(name, m_name2selectionId.size());
+ return *it;
+}
+
+void CtfTraceManager::addModelForThread(int threadId, int processId)
+{
+ CtfTimelineModel *model = new CtfTimelineModel(m_modelAggregator, this, threadId, processId);
+ m_threadModels.insert(threadId, model);
+ connect(model, &CtfTimelineModel::detailsRequested, this,
+ &CtfTraceManager::detailsRequested);
+}
+
+void CtfTraceManager::addModelsToAggregator()
+{
+ QList<CtfTimelineModel *> models = m_threadModels.values();
+ std::sort(models.begin(), models.end(), [](const CtfTimelineModel *a, const CtfTimelineModel *b) -> bool {
+ return (a->m_processId != b->m_processId) ? (a->m_processId < b->m_processId)
+ : (std::abs(a->m_threadId) < std::abs(b->m_threadId));
+ });
+
+ QVariantList modelsToAdd;
+ for (CtfTimelineModel *model: models) {
+ modelsToAdd.append(QVariant::fromValue(model));
+ }
+ m_modelAggregator->setModels(modelsToAdd);
+}
+
+void CtfTraceManager::clearAll()
+{
+ m_modelAggregator->clear();
+ for (CtfTimelineModel *model: m_threadModels) {
+ model->deleteLater();
+ }
+ m_threadModels.clear();
+ m_traceBegin = std::numeric_limits<double>::max();
+ m_traceEnd = std::numeric_limits<double>::min();
+ m_timeOffset = -1;
+}
+
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctftracemanager.h b/src/plugins/ctfvisualizer/ctftracemanager.h
new file mode 100644
index 00000000000..995d26b07a9
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctftracemanager.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include "libs/3rdparty/json/json.hpp"
+
+#include <QHash>
+#include <QMap>
+#include <QObject>
+#include <QVector>
+
+namespace Timeline {
+class TimelineModelAggregator;
+}
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfStatisticsModel;
+class CtfTimelineModel;
+
+class CtfTraceManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit CtfTraceManager(QObject *parent,
+ Timeline::TimelineModelAggregator *modelAggregator,
+ CtfStatisticsModel *statisticsModel);
+
+ qint64 traceDuration() const;
+ qint64 traceBegin() const;
+ qint64 traceEnd() const;
+
+ void addEvent(const nlohmann::json &event);
+
+ void load(const QString &filename);
+ void finalize();
+
+ bool isEmpty() const;
+
+ int getSelectionId(const std::string &name);
+
+signals:
+ void detailsRequested(const QString &title);
+
+protected:
+
+ void addModelForThread(int threadId, int processId);
+ void addModelsToAggregator();
+
+ void clearAll();
+
+ Timeline::TimelineModelAggregator *const m_modelAggregator;
+ CtfStatisticsModel *const m_statisticsModel;
+
+ QHash<qint64, CtfTimelineModel *> m_threadModels;
+ QHash<qint64, QString> m_processNames;
+ QHash<qint64, QString> m_threadNames;
+ QMap<std::string, int> m_name2selectionId;
+
+ double m_traceBegin = std::numeric_limits<double>::max();
+ double m_traceEnd = std::numeric_limits<double>::min();
+ double m_timeOffset = -1.0;
+
+};
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfvisualizer.pro b/src/plugins/ctfvisualizer/ctfvisualizer.pro
new file mode 100644
index 00000000000..bfea14962c5
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizer.pro
@@ -0,0 +1,34 @@
+TARGET = CtfVisualizer
+TEMPLATE = lib
+
+QT += quick quickwidgets
+
+include(../../qtcreatorplugin.pri)
+include(ctfvisualizer_dependencies.pri)
+
+DEFINES += CTFVISUALIZER_LIBRARY
+
+# CtfVisualizer files
+
+SOURCES += \
+ ctfstatisticsmodel.cpp \
+ ctfstatisticsview.cpp \
+ ctfvisualizerplugin.cpp \
+ ctfvisualizertool.cpp \
+ ctftimelinemodel.cpp \
+ ctftracemanager.cpp \
+ ctfvisualizertraceview.cpp
+
+HEADERS += \
+ ctfstatisticsmodel.h \
+ ctfstatisticsview.h \
+ ctfvisualizerplugin.h \
+ ctfvisualizertool.h\
+ ctftimelinemodel.h \
+ ctftracemanager.h \
+ ctfvisualizerconstants.h \
+ ctfvisualizertraceview.h \
+ ../../libs/3rdparty/json/json.hpp
+
+OTHER_FILES += \
+ CtfVisualizer.json.in
diff --git a/src/plugins/ctfvisualizer/ctfvisualizer_dependencies.pri b/src/plugins/ctfvisualizer/ctfvisualizer_dependencies.pri
new file mode 100644
index 00000000000..56a2101bdff
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizer_dependencies.pri
@@ -0,0 +1,9 @@
+QTC_PLUGIN_NAME = CtfVisualizer
+
+QTC_LIB_DEPENDS += \
+ utils \
+ tracing
+
+QTC_PLUGIN_DEPENDS += \
+ debugger \
+ qtsupport
diff --git a/src/plugins/ctfvisualizer/ctfvisualizerconstants.h b/src/plugins/ctfvisualizer/ctfvisualizerconstants.h
new file mode 100644
index 00000000000..93ef360a34f
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizerconstants.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <string>
+
+namespace CtfVisualizer {
+namespace Constants {
+
+const char CtfVisualizerMenuId[] = "Analyzer.Menu.CtfVisualizer";
+const char CtfVisualizerTaskLoadJson[] =
+ "Analyzer.Menu.StartAnalyzer.CtfVisualizer.LoadTrace";
+
+const char CtfVisualizerPerspectiveId[] = "CtfVisualizer.Perspective";
+
+const char CtfTraceEventsKey[] = "traceEvents";
+
+const char CtfEventNameKey[] = "name";
+const char CtfEventCategoryKey[] = "cat";
+const char CtfEventPhaseKey[] = "ph";
+const char CtfTracingClockTimestampKey[] = "ts";
+const char CtfProcessIdKey[] = "pid";
+const char CtfThreadIdKey[] = "tid";
+const char CtfDurationKey[] = "dur";
+
+const char CtfEventTypeBegin[] = "B";
+const char CtfEventTypeEnd[] = "E";
+const char CtfEventTypeComplete[] = "X";
+const char CtfEventTypeMetadata[] = "M";
+const char CtfEventTypeInstant[] = "i";
+const char CtfEventTypeInstantDeprecated[] = "I";
+const char CtfEventTypeCounter[] = "C";
+
+} // namespace Constants
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfvisualizerplugin.cpp b/src/plugins/ctfvisualizer/ctfvisualizerplugin.cpp
new file mode 100644
index 00000000000..c44b9eb20b3
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizerplugin.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "ctfvisualizerplugin.h"
+
+#include "ctfvisualizertool.h"
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfVisualizerPluginPrivate
+{
+public:
+ CtfVisualizerTool profilerTool;
+};
+
+CtfVisualizerPlugin::~CtfVisualizerPlugin()
+{
+ delete d;
+}
+
+bool CtfVisualizerPlugin::initialize(const QStringList &arguments, QString *errorString)
+{
+ Q_UNUSED(arguments)
+ Q_UNUSED(errorString)
+
+ d = new CtfVisualizerPluginPrivate;
+ return true;
+}
+
+void CtfVisualizerPlugin::extensionsInitialized()
+{
+}
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfvisualizerplugin.h b/src/plugins/ctfvisualizer/ctfvisualizerplugin.h
new file mode 100644
index 00000000000..cd1844452c0
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizerplugin.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <extensionsystem/iplugin.h>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfVisualizerPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "CtfVisualizer.json")
+
+public:
+ ~CtfVisualizerPlugin();
+
+ bool initialize(const QStringList &arguments, QString *errorString) final;
+ void extensionsInitialized() final;
+
+ class CtfVisualizerPluginPrivate *d = nullptr;
+};
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp
new file mode 100644
index 00000000000..594b89eb528
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "ctfvisualizertool.h"
+
+#include "ctftracemanager.h"
+
+#include "ctfstatisticsmodel.h"
+#include "ctfstatisticsview.h"
+#include "ctfvisualizertraceview.h"
+
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <debugger/analyzer/analyzerconstants.h>
+
+#include <QAction>
+#include <QApplication>
+#include <QFileDialog>
+#include <QFutureInterface>
+#include <QMenu>
+#include <QMessageBox>
+#include <QThread>
+
+using namespace Core;
+using namespace CtfVisualizer::Constants;
+
+
+namespace CtfVisualizer {
+namespace Internal {
+
+CtfVisualizerTool::CtfVisualizerTool()
+ : QObject (nullptr)
+ , m_isLoading(false)
+ , m_loadJson(nullptr)
+ , m_traceView(nullptr)
+ , m_modelAggregator(new Timeline::TimelineModelAggregator(this))
+ , m_zoomControl(new Timeline::TimelineZoomControl(this))
+ , m_statisticsModel(new CtfStatisticsModel(this))
+ , m_statisticsView(nullptr)
+ , m_traceManager(new CtfTraceManager(this, m_modelAggregator.get(), m_statisticsModel.get()))
+{
+ ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
+ ActionContainer *options = ActionManager::createMenu(Constants::CtfVisualizerMenuId);
+ options->menu()->setTitle(tr("Chrome Trace Format Viewer"));
+ menu->addMenu(options, Debugger::Constants::G_ANALYZER_REMOTE_TOOLS);
+ options->menu()->setEnabled(true);
+
+ const Core::Context globalContext(Core::Constants::C_GLOBAL);
+
+ m_loadJson.reset(new QAction(tr("Load JSON File"), options));
+ Core::Command *command = Core::ActionManager::registerAction(m_loadJson.get(), Constants::CtfVisualizerTaskLoadJson,
+ globalContext);
+ connect(m_loadJson.get(), &QAction::triggered, this, &CtfVisualizerTool::loadJson);
+ options->addAction(command);
+
+ m_perspective.setAboutToActivateCallback([this]() { createViews(); });
+}
+
+CtfVisualizerTool::~CtfVisualizerTool() = default;
+
+void CtfVisualizerTool::createViews()
+{
+ m_traceView = new CtfVisualizerTraceView(nullptr, this);
+ m_traceView->setWindowTitle(tr("Timeline"));
+
+ QMenu *contextMenu = new QMenu(m_traceView);
+ contextMenu->addAction(m_loadJson.get());
+ connect(contextMenu->addAction(tr("Reset Zoom")), &QAction::triggered, this, [this](){
+ m_zoomControl->setRange(m_zoomControl->traceStart(), m_zoomControl->traceEnd());
+ });
+
+ m_traceView->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(m_traceView, &QWidget::customContextMenuRequested,
+ contextMenu, [contextMenu, this](const QPoint &pos) {
+ contextMenu->exec(m_traceView->mapToGlobal(pos));
+ });
+
+ m_perspective.addWindow(m_traceView, Utils::Perspective::OperationType::SplitVertical, nullptr);
+
+ m_statisticsView = new CtfStatisticsView(m_statisticsModel.get());
+ m_statisticsView->setWindowTitle(tr("Statistics"));
+ connect(m_statisticsView, &CtfStatisticsView::eventTypeSelected, [this] (QString title)
+ {
+ int typeId = m_traceManager->getSelectionId(title.toStdString());
+ m_traceView->selectByTypeId(typeId);
+ });
+ connect(m_traceManager.get(), &CtfTraceManager::detailsRequested, m_statisticsView,
+ &CtfStatisticsView::selectByTitle);
+
+ m_perspective.addWindow(m_statisticsView, Utils::Perspective::AddToTab, m_traceView);
+
+ m_perspective.setAboutToActivateCallback(Utils::Perspective::Callback());
+ emit viewsCreated();
+}
+
+Timeline::TimelineModelAggregator *CtfVisualizerTool::modelAggregator() const
+{
+ return m_modelAggregator.get();
+}
+
+CtfTraceManager *CtfVisualizerTool::traceManager() const
+{
+ return m_traceManager.get();
+}
+
+Timeline::TimelineZoomControl *CtfVisualizerTool::zoomControl() const
+{
+ return m_zoomControl.get();
+}
+
+void CtfVisualizerTool::loadJson()
+{
+ if (m_isLoading)
+ return;
+
+ m_isLoading = true;
+
+ QString filename = QFileDialog::getOpenFileName(
+ ICore::mainWindow(), tr("Load Chrome Trace Format File"),
+ "", tr("JSON File (*.json)"));
+ if (filename.isEmpty()) {
+ m_isLoading = false;
+ return;
+ }
+
+ auto *futureInterface = new QFutureInterface<void>();
+ auto *task = new QFuture<void>(futureInterface);
+
+ QThread *thread = QThread::create([this, filename, futureInterface]() {
+ m_traceManager->load(filename);
+
+ m_modelAggregator->moveToThread(QApplication::instance()->thread());
+ m_modelAggregator->setParent(this);
+ futureInterface->reportFinished();
+ });
+
+ connect(thread, &QThread::finished, this, [this, thread, task, futureInterface]() {
+ // in main thread:
+ if (m_traceManager->isEmpty()) {
+ QMessageBox::warning(Core::ICore::mainWindow(),
+ tr("CTF Visualizer"),
+ tr("The file does not contain any trace data."));
+ } else {
+ m_traceManager->finalize();
+ m_perspective.select();
+ zoomControl()->setTrace(m_traceManager->traceBegin(), m_traceManager->traceEnd() + m_traceManager->traceDuration() / 20);
+ zoomControl()->setRange(m_traceManager->traceBegin(), m_traceManager->traceEnd() + m_traceManager->traceDuration() / 20);
+ }
+ thread->deleteLater();
+ delete task;
+ delete futureInterface;
+ m_isLoading = false;
+ }, Qt::QueuedConnection);
+
+ m_modelAggregator->setParent(nullptr);
+ m_modelAggregator->moveToThread(thread);
+
+ thread->start();
+ Core::ProgressManager::addTask(*task, tr("Loading CTF File"), CtfVisualizerTaskLoadJson);
+}
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfvisualizertool.h b/src/plugins/ctfvisualizer/ctfvisualizertool.h
new file mode 100644
index 00000000000..d53ffdc26b3
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizertool.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "ctfvisualizerconstants.h"
+
+#include <debugger/debuggermainwindow.h>
+#include <tracing/timelinemodelaggregator.h>
+#include <tracing/timelinezoomcontrol.h>
+
+#include <QScopedPointer>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfTraceManager;
+class CtfStatisticsModel;
+class CtfStatisticsView;
+class CtfVisualizerTraceView;
+
+
+class CtfVisualizerTool : public QObject
+{
+ Q_OBJECT
+
+public:
+ CtfVisualizerTool();
+ ~CtfVisualizerTool();
+
+ Timeline::TimelineModelAggregator *modelAggregator() const;
+ CtfTraceManager *traceManager() const;
+ Timeline::TimelineZoomControl *zoomControl() const;
+
+ void loadJson();
+
+signals:
+ void viewsCreated();
+
+private:
+ void createViews();
+
+ void initialize();
+ void finalize();
+
+ Utils::Perspective m_perspective{Constants::CtfVisualizerPerspectiveId,
+ tr("Chrome Trace Format Visualizer")};
+
+ bool m_isLoading;
+ QScopedPointer<QAction> m_loadJson;
+
+ CtfVisualizerTraceView *m_traceView;
+ const QScopedPointer<Timeline::TimelineModelAggregator> m_modelAggregator;
+ const QScopedPointer<Timeline::TimelineZoomControl> m_zoomControl;
+
+ const QScopedPointer<CtfStatisticsModel> m_statisticsModel;
+ CtfStatisticsView *m_statisticsView;
+
+ const QScopedPointer<CtfTraceManager> m_traceManager;
+};
+
+} // namespace Internal
+} // namespace CtfVisualizer
diff --git a/src/plugins/ctfvisualizer/ctfvisualizertraceview.cpp b/src/plugins/ctfvisualizer/ctfvisualizertraceview.cpp
new file mode 100644
index 00000000000..a89afe0df34
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizertraceview.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "ctfvisualizertraceview.h"
+
+#include "ctfvisualizertool.h"
+
+#include <tracing/timelineformattime.h>
+#include <tracing/timelineoverviewrenderer.h>
+#include <tracing/timelinerenderer.h>
+#include <tracing/timelinetheme.h>
+
+#include <QQmlContext>
+
+
+namespace CtfVisualizer {
+namespace Internal {
+
+CtfVisualizerTraceView::CtfVisualizerTraceView(QWidget *parent, CtfVisualizerTool *tool)
+ : QQuickWidget(parent)
+{
+ setObjectName(QLatin1String("CtfVisualizerTraceView"));
+
+ qmlRegisterType<Timeline::TimelineRenderer>("TimelineRenderer", 1, 0, "TimelineRenderer");
+ qmlRegisterType<Timeline::TimelineOverviewRenderer>("TimelineOverviewRenderer", 1, 0,
+ "TimelineOverviewRenderer");
+ qmlRegisterType<Timeline::TimelineZoomControl>();
+ qmlRegisterType<Timeline::TimelineModel>();
+ qmlRegisterType<Timeline::TimelineNotesModel>();
+
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ // Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
+ setMinimumHeight(170);
+
+ Timeline::TimelineTheme::setupTheme(engine());
+ Timeline::TimeFormatter::setupTimeFormatter();
+
+ rootContext()->setContextProperty(QLatin1String("timelineModelAggregator"),
+ tool->modelAggregator());
+ rootContext()->setContextProperty(QLatin1String("zoomControl"),
+ tool->zoomControl());
+ setSource(QUrl(QLatin1String("qrc:/tracing/MainView.qml")));
+
+ // Avoid ugly warnings when reading from null properties in QML.
+ connect(tool->modelAggregator(), &QObject::destroyed, this, [this]{ setSource(QUrl()); });
+ connect(tool->zoomControl(), &QObject::destroyed, this, [this]{ setSource(QUrl()); });
+}
+
+CtfVisualizerTraceView::~CtfVisualizerTraceView() = default;
+
+void CtfVisualizerTraceView::selectByTypeId(int typeId)
+{
+ QMetaObject::invokeMethod(rootObject(), "selectByTypeId",
+ Q_ARG(QVariant,QVariant::fromValue<int>(typeId)));
+}
+
+
+} // namespace Internal
+} // namespace CtfVisualizer
+
diff --git a/src/plugins/ctfvisualizer/ctfvisualizertraceview.h b/src/plugins/ctfvisualizer/ctfvisualizertraceview.h
new file mode 100644
index 00000000000..ce3aafaee0d
--- /dev/null
+++ b/src/plugins/ctfvisualizer/ctfvisualizertraceview.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company,
+** info@kdab.com, author Tim Henning <tim.henning@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QQuickWidget>
+#include <QWidget>
+
+namespace CtfVisualizer {
+namespace Internal {
+
+class CtfVisualizerTool;
+
+class CtfVisualizerTraceView : public QQuickWidget
+{
+ Q_OBJECT
+
+public:
+ CtfVisualizerTraceView(QWidget *parent, CtfVisualizerTool *tool);
+
+ ~CtfVisualizerTraceView();
+
+ void selectByTypeId(int typeId);
+};
+
+
+} // namespace Internal
+} // namespace CtfVisualizer
+