diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2017-03-21 13:33:00 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2017-03-23 15:09:15 +0000 |
commit | b609f2d9e948ec7fb91cd317f4e1a7e36969ce65 (patch) | |
tree | bf4b209f08dfa4eb4076c83eefd70a68cca8277b /src/plugins/qmlprofiler | |
parent | 01cb51c11963772a34e503f907a1f80a0de85eb0 (diff) |
QmlProfiler: Correctly process coarse-grained traces
If many events start or end at the same time, the parser would confuse
their order, resulting in meaningless statistics.
Change-Id: I05f94e694c16d6c22b6e937c2f979ce572a068d1
Task-number: QTCREATORBUG-17885
Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins/qmlprofiler')
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilertracefile.cpp | 79 |
1 files changed, 71 insertions, 8 deletions
diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp index da66e9beb3..a821b43eb0 100644 --- a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp @@ -416,10 +416,77 @@ void QmlProfilerFileReader::loadEventTypes(QXmlStreamReader &stream) } } +class EventList +{ +public: + void addEvent(const QmlEvent &event); + void addRange(const QmlEvent &start, const QmlEvent &end); + + QVector<QmlEvent> finalize(); + +private: + struct QmlRange { + QmlEvent begin; + QmlEvent end; + }; + + QVector<QmlRange> ranges; +}; + +void EventList::addEvent(const QmlEvent &event) +{ + ranges.append({event, QmlEvent()}); +} + +void EventList::addRange(const QmlEvent &start, const QmlEvent &end) +{ + ranges.append({start, end}); +} + +QVector<QmlEvent> EventList::finalize() +{ + std::sort(ranges.begin(), ranges.end(), [](const QmlRange &a, const QmlRange &b) { + if (a.begin.timestamp() < b.begin.timestamp()) + return true; + if (a.begin.timestamp() > b.begin.timestamp()) + return false; + + // If the start times are equal. Sort the one with the greater end time first, so that + // the nesting is retained. + return (a.end.timestamp() > b.end.timestamp()); + }); + + QList<QmlEvent> ends; + QVector<QmlEvent> result; + while (!ranges.isEmpty()) { + // This is more expensive than just iterating, but we don't want to double the already + // high memory footprint. + QmlRange range = ranges.takeFirst(); + while (!ends.isEmpty() && ends.last().timestamp() <= range.begin.timestamp()) + result.append(ends.takeLast()); + + result.append(range.begin); + if (range.end.isValid()) { + auto it = ends.end(); + for (auto begin = ends.begin(); it != begin;) { + if ((--it)->timestamp() >= range.end.timestamp()) { + ++it; + break; + } + } + ends.insert(it, range.end); + } + } + while (!ends.isEmpty()) + result.append(ends.takeLast()); + + return result; +} + void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) { QTC_ASSERT(stream.name() == _("profilerDataModel"), return); - QVector<QmlEvent> events; + EventList events; while (!stream.atEnd() && !stream.hasError() && !isCanceled()) { @@ -444,12 +511,11 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) if (attributes.hasAttribute(_("duration"))) { event.setRangeStage(RangeStart); - events.append(event); QmlEvent rangeEnd(event); rangeEnd.setRangeStage(RangeEnd); rangeEnd.setTimestamp(event.timestamp() + attributes.value(_("duration")).toLongLong()); - events.append(rangeEnd); + events.addRange(event, rangeEnd); } else { // attributes for special events if (attributes.hasAttribute(_("framerate"))) @@ -485,7 +551,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) if (attributes.hasAttribute(_("text"))) event.setString(attributes.value(_("text")).toString()); - events.append(event); + events.addEvent(event); } } break; @@ -493,10 +559,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) case QXmlStreamReader::EndElement: { if (elementName == _("profilerDataModel")) { // done reading profilerDataModel - std::sort(events.begin(), events.end(), [](const QmlEvent &a, const QmlEvent &b) { - return a.timestamp() < b.timestamp(); - }); - emit qmlEventsLoaded(events); + emit qmlEventsLoaded(events.finalize()); return; } break; |