aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
blob: be753ed10ff5d07300f7db6b4e15bcfe10e97ad4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "qqmlprofileradapter.h"
#include "qqmlprofilerservice.h"

#include <private/qqmldebugserviceinterfaces_p.h>

QT_BEGIN_NAMESPACE

QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine)
{
    engine->profiler = new QQmlProfiler;
    init(service, engine->profiler);
}

QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader)
{
    QQmlProfiler *profiler = new QQmlProfiler;
    loader->setProfiler(profiler);
    init(service, profiler);
}

void QQmlProfilerAdapter::init(QQmlProfilerService *service, QQmlProfiler *profiler)
{
    next = 0;
    setService(service);
    connect(this, &QQmlProfilerAdapter::profilingEnabled,
            profiler, &QQmlProfiler::startProfiling);
    connect(this, &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting,
            profiler, &QQmlProfiler::startProfiling, Qt::DirectConnection);
    connect(this, &QQmlAbstractProfilerAdapter::profilingDisabled,
            profiler, &QQmlProfiler::stopProfiling);
    connect(this, &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting,
            profiler, &QQmlProfiler::stopProfiling, Qt::DirectConnection);
    connect(this, &QQmlAbstractProfilerAdapter::dataRequested,
            profiler, &QQmlProfiler::reportData);
    connect(this, &QQmlAbstractProfilerAdapter::referenceTimeKnown,
            profiler, &QQmlProfiler::setTimer);
    connect(profiler, &QQmlProfiler::dataReady,
            this, &QQmlProfilerAdapter::receiveData);
}

// convert to QByteArrays that can be sent to the debug client
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
                                         QQmlProfiler::LocationHash &locations,
                                         QList<QByteArray> &messages)
{
    QQmlDebugPacket ds;
    Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO,
               "You can use at most 31 message types.");
    for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0;
         ++decodedMessageType) {
        if (decodedMessageType == QQmlProfilerDefinitions::RangeData
                || (d.messageType & (1 << decodedMessageType)) == 0) {
            continue; // RangeData is sent together with RangeLocation
        }

        if (decodedMessageType == QQmlProfilerDefinitions::RangeEnd
                || decodedMessageType == QQmlProfilerDefinitions::RangeStart) {
            ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
            if (d.locationId != 0)
                ds << static_cast<qint64>(d.locationId);
        } else {
            auto i = locations.find(d.locationId);
            if (i != locations.end()) {
                ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
                ds << (i->url.isEmpty() ? i->location.sourceFile : i->url.toString())
                   << static_cast<qint32>(i->location.line)
                   << static_cast<qint32>(i->location.column);
                if (d.messageType & (1 << QQmlProfilerDefinitions::RangeData)) {
                    // Send both, location and data ...
                    ds << static_cast<qint64>(d.locationId);
                    messages.append(ds.squeezedData());
                    ds.clear();
                    ds << d.time << int(QQmlProfilerDefinitions::RangeData)
                       << static_cast<quint32>(d.detailType)
                       << (i->location.sourceFile.isEmpty() ? i->url.toString() :
                                                              i->location.sourceFile);
                }
                ds << static_cast<qint64>(d.locationId);
                locations.erase(i); // ... so that we can erase here without missing anything.
            } else {
                // Skip RangeData and RangeLocation: We've already sent them
                continue;
            }
        }
        messages.append(ds.squeezedData());
        ds.clear();
    }
}

qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
    while (next != data.size()) {
        const QQmlProfilerData &nextData = data.at(next);
        if (nextData.time > until || messages.size() > s_numMessagesPerBatch)
            return nextData.time;
        qQmlProfilerDataToByteArrays(nextData, locations, messages);
        ++next;
    }

    next = 0;
    data.clear();
    locations.clear();
    return -1;
}

void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data,
                                      const QQmlProfiler::LocationHash &new_locations)
{
    if (data.isEmpty())
        data = new_data;
    else
        data.append(new_data);

    if (locations.isEmpty())
        locations = new_locations;
    else
        locations.insert(new_locations);

    service->dataReady(this);
}

QT_END_NAMESPACE

#include "moc_qqmlprofileradapter.cpp"