performance/ThreadSelectionPerformanceTracker.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "performance/ThreadSelectionPerformanceTracker.h" | ||
| 2 | |||
| 3 | #include <QApplication> | ||
| 4 | #include <QEvent> | ||
| 5 | |||
| 6 | namespace MailJD::Performance { | ||
| 7 | |||
| 8 | namespace { | ||
| 9 | |||
| 10 | constexpr auto SelectionMetric = "thread.selection_to_quick_frame.v1"; | ||
| 11 | // A missing frame confirmation within this window is `timeout`, never | ||
| 12 | // an implicit success (P90.0: no probe may finish "fast" without the | ||
| 13 | // visible side). | ||
| 14 | constexpr int SelectionTimeoutMs = 15000; | ||
| 15 | // Input older than this window no longer explains a selection. | ||
| 16 | constexpr qint64 OriginFreshNs = 750 * 1000 * 1000; | ||
| 17 | |||
| 18 | } // namespace | ||
| 19 | |||
| 20 | 20279 | ThreadSelectionPerformanceTracker &ThreadSelectionPerformanceTracker::instance() { | |
| 21 |
4/7✓ Branch 2 → 3 taken 22 times.
✓ Branch 2 → 8 taken 20257 times.
✓ Branch 4 → 5 taken 22 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 22 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
20279 | static ThreadSelectionPerformanceTracker tracker; |
| 22 | 20279 | return tracker; | |
| 23 | } | ||
| 24 | |||
| 25 | 22 | ThreadSelectionPerformanceTracker::ThreadSelectionPerformanceTracker( | |
| 26 | 22 | QObject *parent) | |
| 27 |
1/1✓ Branch 6 → 7 taken 22 times.
|
22 | : QObject(parent) { |
| 28 |
1/1✓ Branch 8 → 9 taken 22 times.
|
22 | m_timeout.setSingleShot(true); |
| 29 |
1/1✓ Branch 9 → 10 taken 22 times.
|
22 | m_timeout.setInterval(SelectionTimeoutMs); |
| 30 |
1/1✓ Branch 10 → 11 taken 22 times.
|
22 | m_timeout.callOnTimeout(this, [this] { |
| 31 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
|
1 | if (m_operation.isValid()) finish(Outcome::Timeout); |
| 32 | 1 | }); | |
| 33 | 22 | } | |
| 34 | |||
| 35 | 20906 | bool ThreadSelectionPerformanceTracker::isActive() const { | |
| 36 |
4/4✓ Branch 2 → 3 taken 20906 times.
✓ Branch 3 → 4 taken 20906 times.
✓ Branch 4 → 5 taken 11 times.
✓ Branch 4 → 13 taken 20895 times.
|
20928 | return PerformanceTrace::instance().isEnabled() && |
| 37 |
5/7✓ Branch 5 → 6 taken 11 times.
✓ Branch 6 → 7 taken 11 times.
✓ Branch 10 → 11 taken 11 times.
✓ Branch 11 → 12 taken 9 times.
✓ Branch 11 → 13 taken 2 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
|
20928 | PerformanceTrace::instance().selectedScenario().startsWith( |
| 38 |
6/10✓ Branch 14 → 15 taken 11 times.
✓ Branch 14 → 16 taken 20895 times.
✓ Branch 16 → 17 taken 11 times.
✓ Branch 16 → 18 taken 20895 times.
✓ Branch 18 → 19 taken 11 times.
✓ Branch 18 → 20 taken 20895 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
|
41823 | QStringLiteral("THREAD_SELECTION.")); |
| 39 | } | ||
| 40 | |||
| 41 | 765 | void ThreadSelectionPerformanceTracker::prepare() { | |
| 42 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 765 times.
|
765 | if (isActive()) ensureEventFilterInstalled(); |
| 43 | 765 | } | |
| 44 | |||
| 45 | 16 | void ThreadSelectionPerformanceTracker::reset() { | |
| 46 | 16 | m_selection = MailId{}; | |
| 47 | 16 | m_operation = {}; | |
| 48 | 16 | m_visibleRevision = -1; | |
| 49 | 16 | m_catchupRevision = -1; | |
| 50 | 16 | } | |
| 51 | |||
| 52 | 8 | void ThreadSelectionPerformanceTracker::finish(Outcome outcome, qint64 itemCount) { | |
| 53 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 8 times.
|
8 | if (!m_operation.isValid()) return; |
| 54 | 8 | m_timeout.stop(); | |
| 55 | 8 | m_operation.finish(outcome, itemCount); | |
| 56 | 8 | reset(); | |
| 57 | } | ||
| 58 | |||
| 59 | 8 | void ThreadSelectionPerformanceTracker::ensureEventFilterInstalled() { | |
| 60 |
5/6✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 7 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 11 taken 7 times.
|
8 | if (!m_eventFilterInstalled && qApp) { |
| 61 | 1 | qApp->installEventFilter(this); | |
| 62 | 1 | m_eventFilterInstalled = true; | |
| 63 | } | ||
| 64 | 8 | } | |
| 65 | |||
| 66 | 5 | bool ThreadSelectionPerformanceTracker::eventFilter(QObject *watched, | |
| 67 | QEvent *event) { | ||
| 68 | Q_UNUSED(watched) | ||
| 69 |
3/3✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 12 taken 1 time.
✓ Branch 3 → 20 taken 3 times.
|
5 | switch (event->type()) { |
| 70 | 1 | case QEvent::MouseButtonPress: | |
| 71 | case QEvent::MouseButtonDblClick: | ||
| 72 | case QEvent::Wheel: | ||
| 73 | case QEvent::TabletPress: | ||
| 74 | case QEvent::TouchBegin: | ||
| 75 | 1 | m_lastInputClass = QStringLiteral("pointer"); | |
| 76 | 1 | m_lastInputNs = PerformanceTrace::monotonicNowNs(); | |
| 77 | 1 | break; | |
| 78 | 1 | case QEvent::KeyPress: | |
| 79 | 1 | m_lastInputClass = QStringLiteral("keyboard"); | |
| 80 | 1 | m_lastInputNs = PerformanceTrace::monotonicNowNs(); | |
| 81 | 1 | break; | |
| 82 | 3 | default: | |
| 83 | 3 | break; | |
| 84 | } | ||
| 85 | 5 | return QObject::eventFilter(watched, event); | |
| 86 | } | ||
| 87 | |||
| 88 | 2 | QString ThreadSelectionPerformanceTracker::classifyOrigin() const { | |
| 89 |
3/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 5 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 13 taken 1 time.
|
4 | if (m_lastInputNs == 0 || |
| 90 |
2/2✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1 time.
|
2 | PerformanceTrace::monotonicNowNs() - m_lastInputNs > OriginFreshNs) |
| 91 | 1 | return QStringLiteral("other"); | |
| 92 | 1 | return m_lastInputClass; | |
| 93 | } | ||
| 94 | |||
| 95 | 9 | void ThreadSelectionPerformanceTracker::beginSelection(const MailId &mailId, | |
| 96 | const QString &origin) { | ||
| 97 |
6/7✓ Branch 2 → 3 taken 9 times.
✓ Branch 3 → 4 taken 8 times.
✓ Branch 3 → 6 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 8 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 8 times.
|
9 | if (!isActive() || !mailId.isValid()) return; |
| 98 |
1/1✓ Branch 10 → 11 taken 8 times.
|
8 | ensureEventFilterInstalled(); |
| 99 |
3/3✓ Branch 11 → 12 taken 8 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 24 taken 7 times.
|
8 | if (m_operation.isValid()) { |
| 100 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1 time.
|
1 | if (mailId == m_selection) return; |
| 101 | // A newer selection replaces the probe; the old one never reached its | ||
| 102 | // frame and must not pollute the distribution. | ||
| 103 |
1/1✓ Branch 16 → 17 taken 1 time.
|
1 | PerformanceTrace::instance().markProcessEvent( |
| 104 |
1/1✓ Branch 20 → 21 taken 1 time.
|
1 | m_scenario, QStringLiteral("selection_superseded")); |
| 105 |
1/1✓ Branch 23 → 24 taken 1 time.
|
1 | finish(Outcome::Cancelled); |
| 106 | } | ||
| 107 | 8 | reset(); | |
| 108 |
2/2✓ Branch 25 → 26 taken 8 times.
✓ Branch 26 → 27 taken 8 times.
|
8 | m_scenario = PerformanceTrace::instance().selectedScenario(); |
| 109 | 8 | m_selection = mailId; | |
| 110 |
1/1✓ Branch 30 → 31 taken 8 times.
|
16 | m_operation = PerformanceTrace::instance().startMetric( |
| 111 |
2/2✓ Branch 32 → 33 taken 8 times.
✓ Branch 33 → 34 taken 8 times.
|
16 | m_scenario, QString::fromLatin1(SelectionMetric)); |
| 112 | // Origin tokens are a fixed enumeration from the callers or the | ||
| 113 | // input classifier, never free user text. | ||
| 114 | const QString originToken = | ||
| 115 |
8/18✓ Branch 46 → 47 taken 4 times.
✓ Branch 46 → 52 taken 1 time.
✓ Branch 51 → 52 taken 2 times.
✓ Branch 51 → 53 taken 2 times.
✓ Branch 60 → 61 taken 5 times.
✓ Branch 60 → 62 taken 3 times.
✓ Branch 62 → 63 taken 8 times.
✗ Branch 62 → 64 not taken.
✓ Branch 64 → 65 taken 8 times.
✗ Branch 64 → 66 not taken.
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ Branch 104 → 105 not taken.
✗ Branch 104 → 106 not taken.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
|
25 | origin == QStringLiteral("pointer") || origin == QStringLiteral("keyboard") || |
| 116 |
6/10✓ Branch 54 → 55 taken 4 times.
✓ Branch 54 → 56 taken 4 times.
✓ Branch 56 → 57 taken 4 times.
✓ Branch 56 → 58 taken 4 times.
✓ Branch 58 → 59 taken 5 times.
✓ Branch 58 → 60 taken 3 times.
✗ Branch 92 → 93 not taken.
✗ Branch 92 → 94 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
|
12 | origin == QStringLiteral("restore") |
| 117 |
2/2✓ Branch 41 → 42 taken 5 times.
✓ Branch 41 → 52 taken 3 times.
|
8 | ? origin |
| 118 |
1/1✓ Branch 53 → 54 taken 2 times.
|
16 | : classifyOrigin(); |
| 119 |
1/1✓ Branch 66 → 67 taken 8 times.
|
8 | PerformanceTrace::instance().markProcessEvent( |
| 120 |
1/1✓ Branch 71 → 72 taken 8 times.
|
8 | m_scenario, |
| 121 |
1/1✓ Branch 70 → 71 taken 8 times.
|
16 | QStringLiteral("selection_origin.") + originToken); |
| 122 |
1/1✓ Branch 75 → 76 taken 8 times.
|
8 | m_timeout.start(); |
| 123 | 8 | } | |
| 124 | |||
| 125 | 3 | void ThreadSelectionPerformanceTracker::visiblePagePublished(qint64 revision, | |
| 126 | int rowCount) { | ||
| 127 |
5/6✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 2 times.
|
3 | if (!m_operation.isValid() || m_visibleRevision >= 0) return; |
| 128 | 2 | m_visibleRevision = revision; | |
| 129 |
1/1✓ Branch 12 → 13 taken 2 times.
|
4 | m_operation.mark(QStringLiteral("visible_page"), rowCount); |
| 130 | } | ||
| 131 | |||
| 132 | 3 | void ThreadSelectionPerformanceTracker::indexCatchupFinished(qint64 revision) { | |
| 133 |
5/6✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 2 times.
|
3 | if (!m_operation.isValid() || m_catchupRevision >= 0) return; |
| 134 | 2 | m_catchupRevision = revision; | |
| 135 |
1/1✓ Branch 12 → 13 taken 2 times.
|
4 | m_operation.mark(QStringLiteral("index_catchup")); |
| 136 | } | ||
| 137 | |||
| 138 | 1 | void ThreadSelectionPerformanceTracker::authoritativeSyncFinished(qint64 folderId) { | |
| 139 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
|
1 | if (!m_operation.isValid()) return; |
| 140 |
1/1✓ Branch 8 → 9 taken 1 time.
|
2 | m_operation.mark(QStringLiteral("authoritative_sync"), folderId); |
| 141 | } | ||
| 142 | |||
| 143 | 7 | void ThreadSelectionPerformanceTracker::quickFramePresented(const MailId &mailId) { | |
| 144 |
6/6✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 6 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 5 times.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 5 times.
|
7 | if (!m_operation.isValid() || !(mailId == m_selection)) return; |
| 145 | 5 | finish(Outcome::Success); | |
| 146 | } | ||
| 147 | |||
| 148 | ✗ | void ThreadSelectionPerformanceTracker::selectionSuperseded() { | |
| 149 | ✗ | if (!m_operation.isValid()) return; | |
| 150 | ✗ | PerformanceTrace::instance().markProcessEvent( | |
| 151 | ✗ | m_scenario, QStringLiteral("selection_superseded")); | |
| 152 | ✗ | finish(Outcome::Cancelled); | |
| 153 | } | ||
| 154 | |||
| 155 | 93 | void ThreadSelectionPerformanceTracker::folderSwitched() { | |
| 156 |
2/2✓ Branch 3 → 4 taken 92 times.
✓ Branch 3 → 5 taken 1 time.
|
93 | if (!m_operation.isValid()) return; |
| 157 | 1 | PerformanceTrace::instance().markProcessEvent( | |
| 158 |
1/1✓ Branch 9 → 10 taken 1 time.
|
1 | m_scenario, QStringLiteral("selection_folder_changed")); |
| 159 | 1 | finish(Outcome::Cancelled); | |
| 160 | } | ||
| 161 | |||
| 162 | ✗ | void ThreadSelectionPerformanceTracker::fail() { | |
| 163 | ✗ | if (!m_operation.isValid()) return; | |
| 164 | ✗ | finish(Outcome::Failed); | |
| 165 | } | ||
| 166 | |||
| 167 | } // namespace MailJD::Performance | ||
| 168 |