1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qqmlprofileradapter.h" |
5 | #include "qqmlprofilerservice.h" |
6 | |
7 | #include <private/qqmldebugserviceinterfaces_p.h> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine) |
12 | { |
13 | engine->profiler = new QQmlProfiler; |
14 | init(service, profiler: engine->profiler); |
15 | } |
16 | |
17 | QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader) |
18 | { |
19 | QQmlProfiler *profiler = new QQmlProfiler; |
20 | loader->setProfiler(profiler); |
21 | init(service, profiler); |
22 | } |
23 | |
24 | void QQmlProfilerAdapter::init(QQmlProfilerService *service, QQmlProfiler *profiler) |
25 | { |
26 | next = 0; |
27 | setService(service); |
28 | connect(sender: this, signal: &QQmlProfilerAdapter::profilingEnabled, |
29 | context: profiler, slot: &QQmlProfiler::startProfiling); |
30 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting, |
31 | context: profiler, slot: &QQmlProfiler::startProfiling, type: Qt::DirectConnection); |
32 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingDisabled, |
33 | context: profiler, slot: &QQmlProfiler::stopProfiling); |
34 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting, |
35 | context: profiler, slot: &QQmlProfiler::stopProfiling, type: Qt::DirectConnection); |
36 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::dataRequested, |
37 | context: profiler, slot: &QQmlProfiler::reportData); |
38 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::referenceTimeKnown, |
39 | context: profiler, slot: &QQmlProfiler::setTimer); |
40 | connect(sender: profiler, signal: &QQmlProfiler::dataReady, |
41 | context: this, slot: &QQmlProfilerAdapter::receiveData); |
42 | } |
43 | |
44 | // convert to QByteArrays that can be sent to the debug client |
45 | static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, |
46 | QQmlProfiler::LocationHash &locations, |
47 | QList<QByteArray> &messages) |
48 | { |
49 | QQmlDebugPacket ds; |
50 | Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO, |
51 | "You can use at most 31 message types." ); |
52 | for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0; |
53 | ++decodedMessageType) { |
54 | if (decodedMessageType == QQmlProfilerDefinitions::RangeData |
55 | || (d.messageType & (1 << decodedMessageType)) == 0) { |
56 | continue; // RangeData is sent together with RangeLocation |
57 | } |
58 | |
59 | if (decodedMessageType == QQmlProfilerDefinitions::RangeEnd |
60 | || decodedMessageType == QQmlProfilerDefinitions::RangeStart) { |
61 | ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType); |
62 | if (d.locationId != 0) |
63 | ds << static_cast<qint64>(d.locationId); |
64 | } else { |
65 | auto i = locations.find(key: d.locationId); |
66 | if (i != locations.end()) { |
67 | ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType); |
68 | ds << (i->url.isEmpty() ? i->location.sourceFile : i->url.toString()) |
69 | << static_cast<qint32>(i->location.line) |
70 | << static_cast<qint32>(i->location.column); |
71 | if (d.messageType & (1 << QQmlProfilerDefinitions::RangeData)) { |
72 | // Send both, location and data ... |
73 | ds << static_cast<qint64>(d.locationId); |
74 | messages.append(t: ds.squeezedData()); |
75 | ds.clear(); |
76 | ds << d.time << int(QQmlProfilerDefinitions::RangeData) |
77 | << static_cast<quint32>(d.detailType) |
78 | << (i->location.sourceFile.isEmpty() ? i->url.toString() : |
79 | i->location.sourceFile); |
80 | } |
81 | ds << static_cast<qint64>(d.locationId); |
82 | locations.erase(it: i); // ... so that we can erase here without missing anything. |
83 | } else { |
84 | // Skip RangeData and RangeLocation: We've already sent them |
85 | continue; |
86 | } |
87 | } |
88 | messages.append(t: ds.squeezedData()); |
89 | ds.clear(); |
90 | } |
91 | } |
92 | |
93 | qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) |
94 | { |
95 | while (next != data.size()) { |
96 | const QQmlProfilerData &nextData = data.at(i: next); |
97 | if (nextData.time > until || messages.size() > s_numMessagesPerBatch) |
98 | return nextData.time; |
99 | qQmlProfilerDataToByteArrays(d: nextData, locations, messages); |
100 | ++next; |
101 | } |
102 | |
103 | next = 0; |
104 | data.clear(); |
105 | locations.clear(); |
106 | return -1; |
107 | } |
108 | |
109 | void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data, |
110 | const QQmlProfiler::LocationHash &new_locations) |
111 | { |
112 | if (data.isEmpty()) |
113 | data = new_data; |
114 | else |
115 | data.append(l: new_data); |
116 | |
117 | if (locations.isEmpty()) |
118 | locations = new_locations; |
119 | else |
120 | locations.insert(hash: new_locations); |
121 | |
122 | service->dataReady(profiler: this); |
123 | } |
124 | |
125 | QT_END_NAMESPACE |
126 | |
127 | #include "moc_qqmlprofileradapter.cpp" |
128 | |