|
3 | 3 |
|
4 | 4 | #include "qmlprofilerdata.h"
|
5 | 5 |
|
6 |
| -#include <QStringList> |
7 |
| -#include <QUrl> |
8 |
| -#include <QHash> |
9 |
| -#include <QFile> |
10 |
| -#include <QXmlStreamReader> |
11 |
| -#include <QRegularExpression> |
12 |
| -#include <QQueue> |
13 |
| -#include <QStack> |
| 6 | +#include <QtCore/qfile.h> |
| 7 | +#include <QtCore/qqueue.h> |
| 8 | +#include <QtCore/qregularexpression.h> |
| 9 | +#include <QtCore/qurl.h> |
| 10 | +#include <QtCore/qxmlstream.h> |
| 11 | +#include <QtCore/qxpfunctional.h> |
14 | 12 |
|
15 | 13 | #include <limits>
|
16 | 14 |
|
@@ -375,6 +373,132 @@ struct StreamWriter {
|
375 | 373 | QXmlStreamWriter stream;
|
376 | 374 | };
|
377 | 375 |
|
| 376 | +struct DataIterator |
| 377 | +{ |
| 378 | + DataIterator( |
| 379 | + const QmlProfilerDataPrivate *d, |
| 380 | + qxp::function_ref<void(const QQmlProfilerEvent &, qint64)> &&sendEvent) |
| 381 | + : d(d) |
| 382 | + , sendEvent(std::move(sendEvent)) |
| 383 | + {} |
| 384 | + |
| 385 | + void run(); |
| 386 | + |
| 387 | +private: |
| 388 | + void handleRangeEvent(const QQmlProfilerEvent &event, const QQmlProfilerEventType &type); |
| 389 | + void sendPending(); |
| 390 | + void endLevel0(); |
| 391 | + |
| 392 | + const QmlProfilerDataPrivate *d = nullptr; |
| 393 | + const qxp::function_ref<void(const QQmlProfilerEvent &, qint64)> sendEvent; |
| 394 | + |
| 395 | + QQueue<QQmlProfilerEvent> pointEvents; |
| 396 | + QList<QQmlProfilerEvent> rangeStarts[MaximumRangeType]; |
| 397 | + QList<qint64> rangeEnds[MaximumRangeType]; |
| 398 | + |
| 399 | + int level = 0; |
| 400 | +}; |
| 401 | + |
| 402 | +void DataIterator::handleRangeEvent( |
| 403 | + const QQmlProfilerEvent &event, const QQmlProfilerEventType &type) |
| 404 | +{ |
| 405 | + QList<QQmlProfilerEvent> &starts = rangeStarts[type.rangeType()]; |
| 406 | + switch (event.rangeStage()) { |
| 407 | + case RangeStart: { |
| 408 | + ++level; |
| 409 | + starts.append(event); |
| 410 | + break; |
| 411 | + } |
| 412 | + case RangeEnd: { |
| 413 | + const qint64 invalidTimestamp = -1; |
| 414 | + QList<qint64> &ends = rangeEnds[type.rangeType()]; |
| 415 | + |
| 416 | + // -1 because all valid timestamps are >= 0. |
| 417 | + ends.resize(starts.size(), invalidTimestamp); |
| 418 | + |
| 419 | + qsizetype i = starts.size(); |
| 420 | + while (ends[--i] != invalidTimestamp) {} |
| 421 | + |
| 422 | + Q_ASSERT(i >= 0); |
| 423 | + Q_ASSERT(starts[i].timestamp() <= event.timestamp()); |
| 424 | + |
| 425 | + ends[i] = event.timestamp(); |
| 426 | + if (--level == 0) |
| 427 | + endLevel0(); |
| 428 | + break; |
| 429 | + } |
| 430 | + default: |
| 431 | + break; |
| 432 | + } |
| 433 | +} |
| 434 | + |
| 435 | +void DataIterator::sendPending() |
| 436 | +{ |
| 437 | + // Send all pending events in the order of their start times. |
| 438 | + |
| 439 | + qsizetype index[MaximumRangeType] = { 0, 0, 0, 0, 0, 0 }; |
| 440 | + while (true) { |
| 441 | + |
| 442 | + // Find the range type with the minimum start time. |
| 443 | + qsizetype minimum = MaximumRangeType; |
| 444 | + qint64 minimumTime = std::numeric_limits<qint64>::max(); |
| 445 | + for (qsizetype i = 0; i < MaximumRangeType; ++i) { |
| 446 | + const QList<QQmlProfilerEvent> &starts = rangeStarts[i]; |
| 447 | + if (starts.size() == index[i]) |
| 448 | + continue; |
| 449 | + const qint64 timestamp = starts[index[i]].timestamp(); |
| 450 | + if (timestamp < minimumTime) { |
| 451 | + minimumTime = timestamp; |
| 452 | + minimum = i; |
| 453 | + } |
| 454 | + } |
| 455 | + if (minimum == MaximumRangeType) |
| 456 | + break; |
| 457 | + |
| 458 | + // Send all point events that happened before the range we've found. |
| 459 | + while (!pointEvents.isEmpty() && pointEvents.front().timestamp() < minimumTime) |
| 460 | + sendEvent(pointEvents.dequeue(), 0); |
| 461 | + |
| 462 | + // Send the range itself |
| 463 | + sendEvent(rangeStarts[minimum][index[minimum]], |
| 464 | + rangeEnds[minimum][index[minimum]] - minimumTime); |
| 465 | + |
| 466 | + // Bump the index so that we don't send the same range again |
| 467 | + ++index[minimum]; |
| 468 | + } |
| 469 | +} |
| 470 | + |
| 471 | +void DataIterator::endLevel0() |
| 472 | +{ |
| 473 | + sendPending(); |
| 474 | + for (qsizetype i = 0; i < MaximumRangeType; ++i) { |
| 475 | + rangeStarts[i].clear(); |
| 476 | + rangeEnds[i].clear(); |
| 477 | + } |
| 478 | +} |
| 479 | + |
| 480 | +void DataIterator::run() |
| 481 | +{ |
| 482 | + for (const QQmlProfilerEvent &event : std::as_const(d->events)) { |
| 483 | + const QQmlProfilerEventType &type = d->eventTypes.at(event.typeIndex()); |
| 484 | + if (type.rangeType() != MaximumRangeType) |
| 485 | + handleRangeEvent(event, type); |
| 486 | + else if (level == 0) |
| 487 | + sendEvent(event, 0); |
| 488 | + else |
| 489 | + pointEvents.enqueue(event); |
| 490 | + } |
| 491 | + |
| 492 | + for (qsizetype i = 0; i < MaximumRangeType; ++i) { |
| 493 | + while (rangeEnds[i].size() < rangeStarts[i].size()) { |
| 494 | + rangeEnds[i].append(d->traceEndTime); |
| 495 | + --level; |
| 496 | + } |
| 497 | + } |
| 498 | + |
| 499 | + sendPending(); |
| 500 | +} |
| 501 | + |
378 | 502 | bool QmlProfilerData::save(const QString &filename)
|
379 | 503 | {
|
380 | 504 | if (isEmpty()) {
|
@@ -442,6 +566,7 @@ bool QmlProfilerData::save(const QString &filename)
|
442 | 566 | stream.writeStartElement("profilerDataModel");
|
443 | 567 |
|
444 | 568 | auto sendEvent = [&](const QQmlProfilerEvent &event, qint64 duration = 0) {
|
| 569 | + Q_ASSERT(duration >= 0); |
445 | 570 | const QQmlProfilerEventType &type = d->eventTypes.at(event.typeIndex());
|
446 | 571 | stream.writeStartElement("range");
|
447 | 572 | stream.writeAttribute("startTime", event.timestamp());
|
@@ -481,74 +606,7 @@ bool QmlProfilerData::save(const QString &filename)
|
481 | 606 | stream.writeEndElement();
|
482 | 607 | };
|
483 | 608 |
|
484 |
| - QQueue<QQmlProfilerEvent> pointEvents; |
485 |
| - QQueue<QQmlProfilerEvent> rangeStarts[MaximumRangeType]; |
486 |
| - QStack<qint64> rangeEnds[MaximumRangeType]; |
487 |
| - int level = 0; |
488 |
| - |
489 |
| - auto sendPending = [&]() { |
490 |
| - forever { |
491 |
| - int minimum = MaximumRangeType; |
492 |
| - qint64 minimumTime = std::numeric_limits<qint64>::max(); |
493 |
| - for (int i = 0; i < MaximumRangeType; ++i) { |
494 |
| - const QQueue<QQmlProfilerEvent> &starts = rangeStarts[i]; |
495 |
| - if (starts.isEmpty()) |
496 |
| - continue; |
497 |
| - if (starts.head().timestamp() < minimumTime) { |
498 |
| - minimumTime = starts.head().timestamp(); |
499 |
| - minimum = i; |
500 |
| - } |
501 |
| - } |
502 |
| - if (minimum == MaximumRangeType) |
503 |
| - break; |
504 |
| - |
505 |
| - while (!pointEvents.isEmpty() && pointEvents.front().timestamp() < minimumTime) |
506 |
| - sendEvent(pointEvents.dequeue()); |
507 |
| - |
508 |
| - sendEvent(rangeStarts[minimum].dequeue(), |
509 |
| - rangeEnds[minimum].pop() - minimumTime); |
510 |
| - } |
511 |
| - }; |
512 |
| - |
513 |
| - for (const QQmlProfilerEvent &event : std::as_const(d->events)) { |
514 |
| - const QQmlProfilerEventType &type = d->eventTypes.at(event.typeIndex()); |
515 |
| - |
516 |
| - if (type.rangeType() != MaximumRangeType) { |
517 |
| - QQueue<QQmlProfilerEvent> &starts = rangeStarts[type.rangeType()]; |
518 |
| - switch (event.rangeStage()) { |
519 |
| - case RangeStart: { |
520 |
| - ++level; |
521 |
| - starts.enqueue(event); |
522 |
| - break; |
523 |
| - } |
524 |
| - case RangeEnd: { |
525 |
| - QStack<qint64> &ends = rangeEnds[type.rangeType()]; |
526 |
| - if (starts.size() > ends.size()) { |
527 |
| - ends.push(event.timestamp()); |
528 |
| - if (--level == 0) |
529 |
| - sendPending(); |
530 |
| - } |
531 |
| - break; |
532 |
| - } |
533 |
| - default: |
534 |
| - break; |
535 |
| - } |
536 |
| - } else { |
537 |
| - if (level == 0) |
538 |
| - sendEvent(event); |
539 |
| - else |
540 |
| - pointEvents.enqueue(event); |
541 |
| - } |
542 |
| - } |
543 |
| - |
544 |
| - for (int i = 0; i < MaximumRangeType; ++i) { |
545 |
| - while (rangeEnds[i].size() < rangeStarts[i].size()) { |
546 |
| - rangeEnds[i].push(d->traceEndTime); |
547 |
| - --level; |
548 |
| - } |
549 |
| - } |
550 |
| - |
551 |
| - sendPending(); |
| 609 | + DataIterator(d, std::move(sendEvent)).run(); |
552 | 610 |
|
553 | 611 | stream.writeEndElement(); // profilerDataModel
|
554 | 612 |
|
|
0 commit comments