Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qhitrace.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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 <private/qhitrace_p.h>
5#include <private/qtools_p.h>
6
7#include <QtCore/qlogging.h>
8
9#include <hitrace/trace.h>
10
11#include <cstdarg>
12#include <cstdio>
13#include <cstring>
14#include <type_traits>
15
16QT_BEGIN_NAMESPACE
17
18namespace {
19
20constexpr char elidedMark[] = "...";
21constexpr char16_t firstPrintable = 0x20;
22constexpr char16_t lastPrintable = 0x7e;
23constexpr char escapeMark = '\\';
24constexpr char unicodeEscape = 'u';
25constexpr char separatorReplacement = ' ';
26constexpr int escapeDigits = 2 * sizeof(char16_t);
27constexpr int bitsPerHexDigit = 4;
31
32Q_CONSTINIT int32_t qtHiTraceListener = unregisteredListener;
33
34bool isSeparator(QChar unit)
35{
36 return unit == u',' || unit == u'=' || unit == u'|';
37}
38
39bool isWrittenVerbatim(QChar unit)
40{
41 return unit.unicode() >= firstPrintable && unit.unicode() <= lastPrintable
42 && unit != QLatin1Char(escapeMark);
43}
44
45char shortEscape(QChar unit)
46{
47 switch (unit.unicode()) {
48 case '\\':
49 return '\\';
50 case '\b':
51 return 'b';
52 case '\f':
53 return 'f';
54 case '\n':
55 return 'n';
56 case '\r':
57 return 'r';
58 case '\t':
59 return 't';
60 default:
61 return 0;
62 }
63}
64
66{
67 if (isWrittenVerbatim(unit))
68 return 1;
69 return shortEscape(unit) ? shortEscapeSize : unicodeEscapeSize;
70}
71
72QByteArray escaped(QStringView text)
73{
74 QByteArray result;
75 result.reserve(text.size());
76 for (const QChar unit : text) {
77 if (isSeparator(unit)) {
78 result += separatorReplacement;
79 continue;
80 }
81 if (isWrittenVerbatim(unit)) {
82 result += char(unit.unicode());
83 continue;
84 }
85 result += escapeMark;
86 if (const char shortForm = shortEscape(unit)) {
87 result += shortForm;
88 continue;
89 }
90 result += unicodeEscape;
91 for (int digit = escapeDigits - 1; digit >= 0; --digit)
92 result += QtMiscUtils::toHexLower(unit.unicode() >> (digit * bitsPerHexDigit));
93 }
94 return result;
95}
96
102
103template <typename Iterator>
104bool startsSurrogatePair(Iterator unit, Iterator end)
105{
106 constexpr bool isReversed = std::is_same_v<Iterator, QStringView::const_reverse_iterator>;
107 if (unit + 1 == end)
108 return false;
109 const QChar high = isReversed ? unit[1] : unit[0];
110 const QChar low = isReversed ? unit[0] : unit[1];
111 return high.isHighSurrogate() && low.isLowSurrogate();
112}
113
114template <typename Iterator>
115FittingUnits fittingUnits(Iterator unit, Iterator end, qsizetype maximumSize)
116{
117 FittingUnits fitting;
118 while (unit != end) {
119 const qsizetype step = startsSurrogatePair(unit, end) ? 2 : 1;
120 qsizetype stepSize = escapedSize(unit[0]);
121 if (step == 2)
122 stepSize += escapedSize(unit[1]);
123 if (fitting.escapedSize + stepSize > maximumSize)
124 break;
125 fitting.escapedSize += stepSize;
126 fitting.count += step;
127 unit += step;
128 }
129 return fitting;
130}
131
132QByteArray elided(QStringView value, qsizetype maximumSize)
133{
134 Q_ASSERT(maximumSize >= qtHiTraceSmallestValueBudget);
135
136 if (fittingUnits(value.cbegin(), value.cend(), maximumSize).count == value.size())
137 return escaped(value);
138
139 const qsizetype kept = maximumSize - (qsizetype(sizeof(elidedMark)) - 1);
140 const FittingUnits head = fittingUnits(value.cbegin(), value.cend(), kept / 2);
141 const FittingUnits tail =
142 fittingUnits(value.crbegin(), value.crend(), kept - head.escapedSize);
143 return escaped(value.first(head.count)) + elidedMark + escaped(value.last(tail.count));
144}
145
146void qtHiTraceStatusChanged(bool enabled)
147{
148 qtHiTraceEnabled.storeRelaxed(enabled);
149}
150
152{
153 const int32_t listener = OH_HiTrace_RegisterTraceListener(qtHiTraceStatusChanged);
154 if (listener < 0) {
155 qtHiTraceEnabled.storeRelaxed(true);
156 qWarning("Qt tracing: OH_HiTrace_RegisterTraceListener() failed with %d, so tracepoint "
157 "arguments are rendered whether or not a capture is running",
158 listener);
159 return;
160 }
161
162 qtHiTraceListener = listener;
163 if (OH_HiTrace_IsTraceEnabled())
164 qtHiTraceEnabled.storeRelaxed(true);
165}
166
168{
169 if (qtHiTraceListener != unregisteredListener)
170 OH_HiTrace_UnregisterTraceListener(qtHiTraceListener);
171}
172
173} // namespace
174
175QByteArray qtHiTraceArgument(const char *value, qsizetype maximumSize)
176{
177 return elided(QString::fromUtf8(value), maximumSize);
178}
179
180QByteArray qtHiTraceArgument(const QString &value, qsizetype maximumSize)
181{
182 return elided(value, maximumSize);
183}
184
185const char *qtHiTraceFormatArguments(int sliceNameSize, const char *format, ...)
186{
187 Q_CONSTINIT static thread_local char renderedArguments[qtHiTraceRecordBudget] = {};
188
189 const int budget = qtHiTraceRecordBudget - sliceNameSize;
190 if (budget <= int(sizeof(elidedMark)))
191 return "";
192
193 va_list values;
194 va_start(values, format);
195 const int renderedSize = std::vsnprintf(renderedArguments, budget, format, values);
196 va_end(values);
197
198 if (renderedSize < 0)
199 return "";
200 if (renderedSize >= budget) {
201 std::memcpy(renderedArguments + budget - sizeof(elidedMark), elidedMark,
202 sizeof(elidedMark));
203 }
204 return renderedArguments;
205}
206
207Q_CONSTINIT QBasicAtomicInteger<bool> qtHiTraceEnabled = Q_BASIC_ATOMIC_INITIALIZER(false);
208
209Q_CONSTRUCTOR_FUNCTION(qtHiTraceWatchStatus)
210Q_DESTRUCTOR_FUNCTION(qtHiTraceUnwatchStatus)
211
212QT_END_NAMESPACE
constexpr int bitsPerHexDigit
Definition qhitrace.cpp:27
bool startsSurrogatePair(Iterator unit, Iterator end)
Definition qhitrace.cpp:104
constexpr char16_t firstPrintable
Definition qhitrace.cpp:21
constexpr char separatorReplacement
Definition qhitrace.cpp:25
QByteArray elided(QStringView value, qsizetype maximumSize)
Definition qhitrace.cpp:132
constexpr char unicodeEscape
Definition qhitrace.cpp:24
char shortEscape(QChar unit)
Definition qhitrace.cpp:45
FittingUnits fittingUnits(Iterator unit, Iterator end, qsizetype maximumSize)
Definition qhitrace.cpp:115
bool isSeparator(QChar unit)
Definition qhitrace.cpp:34
void qtHiTraceUnwatchStatus()
Definition qhitrace.cpp:167
void qtHiTraceWatchStatus()
Definition qhitrace.cpp:151
qsizetype escapedSize(QChar unit)
Definition qhitrace.cpp:65
QByteArray escaped(QStringView text)
Definition qhitrace.cpp:72
constexpr int32_t unregisteredListener
Definition qhitrace.cpp:30
constexpr qsizetype shortEscapeSize
Definition qhitrace.cpp:28
void qtHiTraceStatusChanged(bool enabled)
Definition qhitrace.cpp:146
constexpr char16_t lastPrintable
Definition qhitrace.cpp:22
bool isWrittenVerbatim(QChar unit)
Definition qhitrace.cpp:39
constexpr char escapeMark
Definition qhitrace.cpp:23
constexpr char elidedMark[]
Definition qhitrace.cpp:20
constexpr int escapeDigits
Definition qhitrace.cpp:26
constexpr qsizetype unicodeEscapeSize
Definition qhitrace.cpp:29
QByteArray qtHiTraceArgument(const char *value, qsizetype maximumSize)
Definition qhitrace.cpp:175
const char * qtHiTraceFormatArguments(int sliceNameSize, const char *format,...)
Definition qhitrace.cpp:185
QByteArray qtHiTraceArgument(const QString &value, qsizetype maximumSize)
Definition qhitrace.cpp:180