CtfVisualizer: Fix computation of nesting level

The computed nesting level (which row an event to show in) was solely
based on begin+end events and "complete" events were ignored.

Compute the rows afterwards, similar to the "parent" computation that
the timeline model already does. Find the first row that is free,
and use that for the row of the item.

Change-Id: I890138c10f5038508da9b286b35d7bcfdf0ab64d
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Eike Ziller
2023-09-11 08:53:42 +02:00
parent bd6348fc20
commit 305a1a6ed1
5 changed files with 68 additions and 14 deletions

View File

@@ -83,6 +83,54 @@ void TimelineModel::computeNesting()
} }
} }
/*!
Compute all ranges' nesting level. Sort them into rows by finding the
first row that has "an open spot".
*/
QList<int> TimelineModel::computeRows(int *maxlevel) const
{
*maxlevel = 0;
std::list<int> rows;
QList<int> levels;
levels.reserve(d->ranges.count());
for (int range = 0; range != count(); ++range) {
TimelineModelPrivate::Range &current = d->ranges[range];
// find first row for inserting
int level = 0;
auto rowIt = rows.begin();
forever {
if (rowIt == rows.end()) {
// didn't find a row, insert new one
rows.push_back(range);
break;
}
TimelineModelPrivate::Range &rowItem = d->ranges[*rowIt];
if (rowItem.start + rowItem.duration < current.start) {
// We've completely passed the item
// Use this row for the range
*rowIt = range;
break;
}
++rowIt;
++level;
}
levels.append(level);
if (level > *maxlevel)
*maxlevel = level;
// remove other rows that we passed
while (rowIt != rows.end()) {
TimelineModelPrivate::Range &rowItem = d->ranges[*rowIt];
if (rowItem.start + rowItem.duration < current.start) {
// We've completely passed the item, remove
rowIt = rows.erase(rowIt);
} else {
++rowIt;
}
}
}
return levels;
}
int TimelineModel::collapsedRowCount() const int TimelineModel::collapsedRowCount() const
{ {
return d->collapsedRowCount; return d->collapsedRowCount;

View File

@@ -133,6 +133,7 @@ protected:
int insertStart(qint64 startTime, int selectionId); int insertStart(qint64 startTime, int selectionId);
void insertEnd(int index, qint64 duration); void insertEnd(int index, qint64 duration);
void computeNesting(); void computeNesting();
QList<int> computeRows(int *maxlevel) const;
void setCollapsedRowCount(int rows); void setCollapsedRowCount(int rows);
void setExpandedRowCount(int rows); void setExpandedRowCount(int rows);

View File

@@ -105,7 +105,7 @@ int CtfTimelineModel::expandedRow(int index) const
if (counterIdx > 0) { if (counterIdx > 0) {
return m_counterIndexToRow[counterIdx - 1] + 1; return m_counterIndexToRow[counterIdx - 1] + 1;
} }
return m_nestingLevels.value(index) + m_counterData.size() + 1; return m_rows.value(index) + m_counterData.size() + 1;
} }
int CtfTimelineModel::collapsedRow(int index) const int CtfTimelineModel::collapsedRow(int index) const
@@ -187,6 +187,8 @@ void CtfTimelineModel::finalize(double traceBegin, double traceEnd, const QStrin
m_details[index].insert(6, {reuse(Tr::tr("Unfinished")), reuse(Tr::tr("true"))}); m_details[index].insert(6, {reuse(Tr::tr("Unfinished")), reuse(Tr::tr("true"))});
} }
computeNesting(); computeNesting();
m_rows = computeRows(&m_maxStackSize);
++m_maxStackSize; // index -> count
QVector<std::string> sortedCounterNames = m_counterNames; QVector<std::string> sortedCounterNames = m_counterNames;
std::sort(sortedCounterNames.begin(), sortedCounterNames.end()); std::sort(sortedCounterNames.begin(), sortedCounterNames.end());
@@ -233,8 +235,6 @@ qint64 CtfTimelineModel::newStackEvent(const json &event, qint64 normalizedTime,
const std::string &eventPhase, const std::string &name, const std::string &eventPhase, const std::string &name,
int selectionId) int selectionId)
{ {
int nestingLevel = m_openEventIds.size();
m_maxStackSize = std::max(qsizetype(m_maxStackSize), qsizetype(m_openEventIds.size() + 1));
int index = 0; int index = 0;
qint64 duration = -1; qint64 duration = -1;
if (eventPhase == CtfEventTypeBegin) { if (eventPhase == CtfEventTypeBegin) {
@@ -250,29 +250,21 @@ qint64 CtfTimelineModel::newStackEvent(const json &event, qint64 normalizedTime,
duration = qint64(event[CtfDurationKey]) * 1000; duration = qint64(event[CtfDurationKey]) * 1000;
index = insert(normalizedTime, duration, selectionId); index = insert(normalizedTime, duration, selectionId);
for (int i = m_openEventIds.size() - 1; i >= 0; --i) { for (int i = m_openEventIds.size() - 1; i >= 0; --i) {
if (m_openEventIds[i] >= index) { if (m_openEventIds[i] >= index)
++m_openEventIds[i]; ++m_openEventIds[i];
// if the event is before an open event, the nesting level decreases:
--nestingLevel;
}
} }
} else { } else {
index = insert(normalizedTime, 0, selectionId); index = insert(normalizedTime, 0, selectionId);
for (int i = m_openEventIds.size() - 1; i >= 0; --i) { for (int i = m_openEventIds.size() - 1; i >= 0; --i) {
if (m_openEventIds[i] >= index) { if (m_openEventIds[i] >= index)
++m_openEventIds[i]; ++m_openEventIds[i];
--nestingLevel;
}
} }
} }
if (index >= m_details.size()) { if (index >= m_details.size()) {
m_details.resize(index + 1); m_details.resize(index + 1);
m_details[index] = QMap<int, QPair<QString, QString>>(); m_details[index] = QMap<int, QPair<QString, QString>>();
m_nestingLevels.resize(index + 1);
m_nestingLevels[index] = nestingLevel;
} else { } else {
m_details.insert(index, QMap<int, QPair<QString, QString>>()); m_details.insert(index, QMap<int, QPair<QString, QString>>());
m_nestingLevels.insert(index, nestingLevel);
} }
if (m_counterValues.size() > index) { if (m_counterValues.size() > index) {
// if the event was inserted before any counter, we need // if the event was inserted before any counter, we need

View File

@@ -73,7 +73,7 @@ protected:
QString m_processName; QString m_processName;
int m_maxStackSize = 0; int m_maxStackSize = 0;
QVector<int> m_nestingLevels; QVector<int> m_rows;
QVector<QMap<int, QPair<QString, QString>>> m_details; QVector<QMap<int, QPair<QString, QString>>> m_details;
QSet<int> m_handledTypeIds; QSet<int> m_handledTypeIds;
QStack<int> m_openEventIds; QStack<int> m_openEventIds;

View File

@@ -57,6 +57,7 @@ private slots:
void rowCount(); void rowCount();
void prevNext(); void prevNext();
void parentingOfEqualStarts(); void parentingOfEqualStarts();
void rows();
private: private:
TimelineModelAggregator aggregator; TimelineModelAggregator aggregator;
@@ -463,6 +464,18 @@ void tst_TimelineModel::parentingOfEqualStarts()
QCOMPARE(dummy.lastIndex(2), 1); QCOMPARE(dummy.lastIndex(2), 1);
} }
void tst_TimelineModel::rows()
{
DummyModel dummy(&aggregator);
dummy.loadData();
int maxlevel;
const QList<int> levels = dummy.computeRows(&maxlevel);
QCOMPARE(levels.at(0), 0);
QCOMPARE(levels.at(7), 7);
QCOMPARE(levels.at(10), 2);
QCOMPARE(maxlevel, 15);
}
QTEST_GUILESS_MAIN(tst_TimelineModel) QTEST_GUILESS_MAIN(tst_TimelineModel)
#include "tst_timelinemodel.moc" #include "tst_timelinemodel.moc"