9#include <private/qjsengine_p.h>
10#include <private/qqmldebugpluginmanager_p.h>
12#include <QtCore/qurl.h>
13#include <QtCore/qtimer.h>
14#include <QtCore/qthread.h>
15#include <QtCore/qcoreapplication.h>
21Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
24 QQmlConfigurableDebugService<QQmlProfilerService>(1, parent),
25 m_waitingForStop(
false), m_globalEnabled(
false), m_globalFeatures(0)
28 QQmlAbstractProfilerAdapter *quickAdapter =
29 loadQQmlAbstractProfilerAdapter(QLatin1String(
"QQuickProfilerAdapter"));
31 addGlobalProfiler(quickAdapter);
32 quickAdapter->setService(
this);
36 QQmlAbstractProfilerAdapter *quick3DAdapter =
37 loadQQmlAbstractProfilerAdapter(QLatin1String(
"QQuick3DProfilerAdapter"));
39 addGlobalProfiler(quick3DAdapter);
40 quick3DAdapter->setService(
this);
50 qDeleteAll(m_engineProfilers);
51 qDeleteAll(m_globalProfilers);
56 QMutexLocker lock(&m_configMutex);
57 bool dataComplete =
true;
58 for (QMultiMap<qint64, QQmlAbstractProfilerAdapter *>::iterator i(m_startTimes.begin()); i != m_startTimes.end();) {
59 if (i.value() == profiler) {
60 m_startTimes.erase(i++);
67 m_startTimes.insert(0, profiler);
69 QList<QJSEngine *> enginesToRelease;
70 for (QJSEngine *engine : std::as_const(m_stoppingEngines)) {
71 const auto range = std::as_const(m_engineProfilers).equal_range(engine);
72 const auto startTimesEnd = m_startTimes.cend();
73 for (
auto it = range.first; it != range.second; ++it) {
74 if (std::find(m_startTimes.cbegin(), startTimesEnd, *it) != startTimesEnd) {
75 enginesToRelease.append(engine);
81 for (QJSEngine *engine : std::as_const(enginesToRelease)) {
82 m_stoppingEngines.removeOne(engine);
83 emit detachedFromEngine(engine);
90 Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO,
91 "QML profilers have to be added from the engine thread");
93 QMutexLocker lock(&m_configMutex);
94 if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine)) {
95 QQmlProfilerAdapter *qmlAdapter
96 =
new QQmlProfilerAdapter(
this, QQmlEnginePrivate::get(qmlEngine));
97 addEngineProfiler(qmlAdapter, engine);
98 QQmlProfilerAdapter *compileAdapter
99 =
new QQmlProfilerAdapter(
this, QQmlTypeLoader::get(engine));
100 addEngineProfiler(compileAdapter, engine);
103 addEngineProfiler(v4Adapter, engine);
104 QQmlConfigurableDebugService<QQmlProfilerService>::engineAboutToBeAdded(engine);
109 Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO,
110 "QML profilers have to be added from the engine thread");
112 QMutexLocker lock(&m_configMutex);
115 startProfiling(engine, m_globalFeatures);
117 const auto range = std::as_const(m_engineProfilers).equal_range(engine);
118 for (
auto it = range.first; it != range.second; ++it)
119 (*it)->stopWaiting();
124 Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO,
125 "QML profilers have to be removed from the engine thread");
127 QMutexLocker lock(&m_configMutex);
128 bool isRunning =
false;
129 const auto range = std::as_const(m_engineProfilers).equal_range(engine);
130 for (
auto it = range.first; it != range.second; ++it) {
131 QQmlAbstractProfilerAdapter *profiler = *it;
132 if (profiler->isRunning())
134 profiler->startWaiting();
137 m_stoppingEngines.append(engine);
138 stopProfiling(engine);
140 emit detachedFromEngine(engine);
146 Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO,
147 "QML profilers have to be removed from the engine thread");
149 QMutexLocker lock(&m_configMutex);
150 const auto range = std::as_const(m_engineProfilers).equal_range(engine);
151 for (
auto it = range.first; it != range.second; ++it) {
152 QQmlAbstractProfilerAdapter *profiler = *it;
153 removeProfilerFromStartTimes(profiler);
156 m_engineProfilers.remove(engine);
161 profiler->moveToThread(thread());
162 profiler->synchronize(m_timer);
163 m_engineProfilers.insert(engine, profiler);
168 QMutexLocker lock(&m_configMutex);
169 profiler->synchronize(m_timer);
170 m_globalProfilers.append(profiler);
174 quint64 features = 0;
175 for (QQmlAbstractProfilerAdapter *engineProfiler : std::as_const(m_engineProfilers))
176 features |= engineProfiler->features();
179 profiler->startProfiling(features);
184 QMutexLocker lock(&m_configMutex);
185 removeProfilerFromStartTimes(profiler);
186 m_globalProfilers.removeOne(profiler);
191 for (QMultiMap<qint64, QQmlAbstractProfilerAdapter *>::iterator i(m_startTimes.begin());
192 i != m_startTimes.end();) {
193 if (i.value() == profiler) {
194 m_startTimes.erase(i++);
203
204
205
206
207
210 QMutexLocker lock(&m_configMutex);
212 if (features &
static_cast<quint64>(1) << ProfileDebugMessages) {
213 if (QDebugMessageService *messageService =
214 QQmlDebugConnector::instance()->service<QDebugMessageService>())
215 messageService->synchronizeTime(m_timer);
220 d << m_timer.nsecsElapsed() <<
static_cast<qint32>(Event) <<
static_cast<qint32>(StartTrace);
221 bool startedAny =
false;
222 if (engine !=
nullptr) {
223 const auto range = std::as_const(m_engineProfilers).equal_range(engine);
224 for (
auto it = range.first; it != range.second; ++it) {
225 QQmlAbstractProfilerAdapter *profiler = *it;
226 if (!profiler->isRunning()) {
227 profiler->startProfiling(features);
232 d << idForObject(engine);
234 m_globalEnabled =
true;
235 m_globalFeatures = features;
237 QSet<QJSEngine *> engines;
238 for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
239 i != m_engineProfilers.end(); ++i) {
240 if (!i.value()->isRunning()) {
242 i.value()->startProfiling(features);
246 for (QJSEngine *profiledEngine : std::as_const(engines))
247 d << idForObject(profiledEngine);
251 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(m_globalProfilers)) {
252 if (!profiler->isRunning())
253 profiler->startProfiling(features);
256 emit startFlushTimer();
257 emit messageToClient(name(), d.data());
262
263
264
265
266
267
270 QMutexLocker lock(&m_configMutex);
271 QList<QQmlAbstractProfilerAdapter *> stopping;
272 QList<QQmlAbstractProfilerAdapter *> reporting;
274 if (engine ==
nullptr)
275 m_globalEnabled =
false;
277 bool stillRunning =
false;
278 for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
279 i != m_engineProfilers.end(); ++i) {
280 if (i.value()->isRunning()) {
281 m_startTimes.insert(-1, i.value());
282 if (engine ==
nullptr || i.key() == engine) {
283 stopping << i.value();
285 reporting << i.value();
291 if (stopping.isEmpty())
294 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(m_globalProfilers)) {
295 if (!profiler->isRunning())
297 m_startTimes.insert(-1, profiler);
299 reporting << profiler;
301 stopping << profiler;
305 emit stopFlushTimer();
306 m_waitingForStop =
true;
308 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(reporting))
309 profiler->reportData();
311 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(stopping))
312 profiler->stopProfiling();
316
317
320 QList<QByteArray> messages;
322 QQmlDebugPacket traceEnd;
323 if (m_waitingForStop) {
324 traceEnd << m_timer.nsecsElapsed() <<
static_cast<qint32>(Event)
325 <<
static_cast<qint32>(EndTrace);
327 QSet<QJSEngine *> seen;
328 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(m_startTimes)) {
329 for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
330 i != m_engineProfilers.end(); ++i) {
331 if (i.value() == profiler && !seen.contains(i.key())) {
333 traceEnd << idForObject(i.key());
339 while (!m_startTimes.empty()) {
340 QQmlAbstractProfilerAdapter *first = m_startTimes.begin().value();
341 m_startTimes.erase(m_startTimes.begin());
342 qint64 next = first->sendMessages(m_startTimes.isEmpty() ?
343 std::numeric_limits<qint64>::max() :
344 m_startTimes.begin().key(), messages);
346 m_startTimes.insert(next, first);
348 if (messages.size() >= QQmlAbstractProfilerAdapter::s_numMessagesPerBatch) {
349 emit messagesToClient(name(), messages);
354 bool stillRunning =
false;
355 for (
const QQmlAbstractProfilerAdapter *profiler : std::as_const(m_engineProfilers)) {
356 if (profiler->isRunning()) {
362 if (m_waitingForStop) {
364 messages << traceEnd.data();
369 ds <<
static_cast<qint64>(-1) <<
static_cast<qint32>(Complete);
370 messages << ds.data();
371 m_waitingForStop =
false;
375 emit messagesToClient(name(), messages);
379 emit startFlushTimer();
384 QMutexLocker lock(&m_configMutex);
386 if (state() == newState)
390 if (newState != Enabled) {
391 for (
auto it = m_engineProfilers.keyBegin(), end = m_engineProfilers.keyEnd();
400 QMutexLocker lock(&m_configMutex);
402 QQmlDebugPacket stream(message);
405 quint64 features = std::numeric_limits<quint64>::max();
407 quint32 flushInterval = 0;
413 if (!stream.atEnd()) {
414 stream >> flushInterval;
415 m_flushTimer.setInterval(
416 static_cast<
int>(qMin(flushInterval,
417 static_cast<quint32>(std::numeric_limits<
int>::max()))));
418 auto timerStart =
static_cast<
void(QTimer::*)()>(&QTimer::start);
419 if (flushInterval > 0) {
420 connect(&m_flushTimer, &QTimer::timeout,
this, &QQmlProfilerServiceImpl::flush);
421 connect(
this, &QQmlProfilerServiceImpl::startFlushTimer, &m_flushTimer, timerStart);
422 connect(
this, &QQmlProfilerServiceImpl::stopFlushTimer, &m_flushTimer, &QTimer::stop);
424 disconnect(&m_flushTimer, &QTimer::timeout,
this, &QQmlProfilerServiceImpl::flush);
425 disconnect(
this, &QQmlProfilerServiceImpl::startFlushTimer, &m_flushTimer, timerStart);
426 disconnect(
this, &QQmlProfilerServiceImpl::stopFlushTimer,
427 &m_flushTimer, &QTimer::stop);
431 bool useMessageTypes =
false;
433 stream >> useMessageTypes;
436 if (enabled && useMessageTypes)
437 startProfiling(qobject_cast<QJSEngine *>(objectForId(engineId)), features);
439 stopProfiling(qobject_cast<QJSEngine *>(objectForId(engineId)));
446 QMutexLocker lock(&m_configMutex);
447 QList<QQmlAbstractProfilerAdapter *> reporting;
449 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(m_engineProfilers)) {
450 if (profiler->isRunning()) {
451 m_startTimes.insert(-1, profiler);
452 reporting.append(profiler);
456 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(m_globalProfilers)) {
457 if (profiler->isRunning()) {
458 m_startTimes.insert(-1, profiler);
459 reporting.append(profiler);
463 for (QQmlAbstractProfilerAdapter *profiler : std::as_const(reporting))
464 profiler->reportData();
469#include "moc_qqmlprofilerservice.cpp"
void engineAboutToBeRemoved(QJSEngine *engine) override
void engineAdded(QJSEngine *engine) override
void messageReceived(const QByteArray &) override
void stateAboutToBeChanged(State state) override
void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) override
void dataReady(QQmlAbstractProfilerAdapter *profiler) override
void engineRemoved(QJSEngine *engine) override
void stopProfiling(QJSEngine *engine) override
Stop profiling the given engine.
void removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) override
void startProfiling(QJSEngine *engine, quint64 features=std::numeric_limits< quint64 >::max()) override
Start profiling the given engine.
~QQmlProfilerServiceImpl() override