11#include <qstringlist.h>
12#include <qtextstream.h>
14using namespace Qt::StringLiterals;
18constexpr QLatin1StringView traceLevel =
"HITRACE_LEVEL_COMMERCIAL"_L1;
19constexpr QLatin1StringView rangeSeparator =
" + "_L1;
20constexpr char flagSeparator =
'+';
22QString sliceName(
const Provider &provider,
const QString &name)
24 return provider.name + u':' + name;
27QString valueBudget(
const Provider &provider,
const QString &tracepointName)
29 return "qtTraceValueBudget_"_L1 + provider.name + u'_' + tracepointName;
32QString sliceConstant(
const Provider &provider,
const QString &tracepointName)
34 return "qtTraceSlice_"_L1 + provider.name + u'_' + tracepointName;
37QString renderFunction(
const Provider &provider,
const QString &tracepointName)
39 return "qtTraceRender_"_L1 + provider.name + u'_' + tracepointName;
42QString sanitized(
const QString &valueExpression,
const QString &budget)
44 return "qtHiTraceArgument("_L1 + valueExpression +
", "_L1 + budget +
").constData()"_L1;
47QString enumConverter(
const QString &type)
49 return "qtTraceEnum_"_L1 + typeToTypeName(type);
52QString flagsConverter(
const QString &type)
54 return "qtTraceFlags_"_L1 + typeToTypeName(type);
60 QStringList arguments;
61 QStringList unusedNames;
66constexpr int numberWidth = 20;
67constexpr int booleanWidth = 5;
68constexpr int floatWidth = 14;
69constexpr int pointerWidth = 18;
71int renderedWidth(QLatin1StringView specifier)
73 if (specifier ==
"%s"_L1)
75 if (specifier ==
"%g"_L1)
77 if (specifier ==
"%p"_L1)
82enum class ValueKind { Scalar, Budgeted };
84void appendScalar(CustomArgs &args, QStringList &pairs,
const QString &name,
85 QLatin1StringView specifier,
const QString &expression,
86 ValueKind kind = ValueKind::Scalar)
88 pairs << name + u'=' + specifier;
89 args.arguments << expression;
90 if (kind == ValueKind::Budgeted)
93 args.scalarWidth += renderedWidth(specifier);
96enum class MemberKind { Integral, Fractional };
98void appendMembers(CustomArgs &args, QStringList &pairs,
const QString &name, MemberKind kind,
99 std::initializer_list<QLatin1StringView> members)
101 for (QLatin1StringView member : members) {
102 const QString accessor = name + u'.' + member +
"()"_L1;
103 const QString pairName = name + u'_' + member;
104 if (kind == MemberKind::Integral) {
105 appendScalar(args, pairs, pairName,
"%lld"_L1,
106 "static_cast<long long>("_L1 + accessor + u')');
108 appendScalar(args, pairs, pairName,
"%g"_L1, accessor);
113CustomArgs customArgsFor(
const Provider &provider,
const Tracepoint &tracepoint)
117 const QString budget = valueBudget(provider, tracepoint.name);
119 for (
int i = 0; i < tracepoint.args.size(); ++i) {
120 const Tracepoint::Argument &arg = tracepoint.args[i];
121 const Tracepoint::Field &field = tracepoint.fields[i];
122 const QString &name = arg.name;
123 const qsizetype before = pairs.size();
125 if (arg.arrayLen == 0) {
126 switch (field.backendType) {
127 case Tracepoint::Field::Integer:
128 if (arg.type.contains(
"unsigned"_L1)) {
129 appendScalar(args, pairs, name,
"%llu"_L1,
130 "static_cast<unsigned long long>("_L1 + name + u')');
132 appendScalar(args, pairs, name,
"%lld"_L1,
133 "static_cast<long long>("_L1 + name + u')');
136 case Tracepoint::Field::IntegerHex:
137 appendScalar(args, pairs, name,
"%#llx"_L1,
138 "static_cast<unsigned long long>("_L1 + name + u')');
140 case Tracepoint::Field::EnumeratedType:
141 appendScalar(args, pairs, name,
"%s"_L1,
142 sanitized(enumConverter(arg.type) + u'(' + name +
").constData()"_L1,
144 ValueKind::Budgeted);
146 case Tracepoint::Field::FlagType:
147 appendScalar(args, pairs, name,
"%s"_L1,
148 sanitized(flagsConverter(arg.type) + u'(' + name +
").constData()"_L1,
150 ValueKind::Budgeted);
152 case Tracepoint::Field::Boolean:
153 appendScalar(args, pairs, name,
"%s"_L1,
154 u'(' + name +
" ? \"true\" : \"false\")"_L1);
156 case Tracepoint::Field::Float:
157 appendScalar(args, pairs, name,
"%g"_L1,
"static_cast<double>("_L1 + name + u')');
159 case Tracepoint::Field::Pointer:
160 appendScalar(args, pairs, name,
"%p"_L1,
161 "static_cast<const void *>("_L1 + name + u')');
163 case Tracepoint::Field::String:
164 case Tracepoint::Field::QtString:
165 appendScalar(args, pairs, name,
"%s"_L1, sanitized(name, budget),
166 ValueKind::Budgeted);
168 case Tracepoint::Field::QtUrl:
169 appendScalar(args, pairs, name,
"%s"_L1, sanitized(name +
".toString()"_L1, budget),
170 ValueKind::Budgeted);
172 case Tracepoint::Field::QtRect:
173 appendMembers(args, pairs, name, MemberKind::Integral,
174 {
"x"_L1,
"y"_L1,
"width"_L1,
"height"_L1 });
176 case Tracepoint::Field::QtRectF:
177 appendMembers(args, pairs, name, MemberKind::Fractional,
178 {
"x"_L1,
"y"_L1,
"width"_L1,
"height"_L1 });
180 case Tracepoint::Field::QtSize:
181 appendMembers(args, pairs, name, MemberKind::Integral, {
"width"_L1,
"height"_L1 });
183 case Tracepoint::Field::QtSizeF:
184 appendMembers(args, pairs, name, MemberKind::Fractional,
185 {
"width"_L1,
"height"_L1 });
187 case Tracepoint::Field::QtByteArray:
188 appendScalar(args, pairs, name,
"%s"_L1,
189 sanitized(name +
".toHex().constData()"_L1, budget),
190 ValueKind::Budgeted);
192 case Tracepoint::Field::Sequence:
193 case Tracepoint::Field::Unknown:
198 if (pairs.size() == before) {
199 args.unusedNames << name;
200 printf(
"Warning: '%s' argument '%s' has no HiTrace representation "
201 "and is left out of the trace.\n",
206 args.format = pairs.join(u',');
210void writeEnumConverter(QTextStream &stream,
const TraceEnum &enumeration)
212 stream <<
"inline QByteArray " << enumConverter(enumeration.name) <<
"(" << enumeration.name
215 <<
" const long long raw = static_cast<long long>(value);\n";
217 for (
const TraceEnum::EnumValue &v : enumeration.values) {
219 stream <<
" if (raw >= " << v.value <<
" && raw <= " << v.range <<
")\n"
220 <<
" return QByteArrayLiteral(\"" << v.name << rangeSeparator
221 <<
"\") + QByteArray::number(raw - " << v.value <<
");\n";
225 stream <<
" switch (raw) {\n";
227 for (
const TraceEnum::EnumValue &v : enumeration.values) {
228 if (v.range == 0 && !handled.contains(v.value)) {
229 stream <<
" case " << v.value <<
": return QByteArrayLiteral(\""
230 << aggregateListValues(v.value, enumeration.values) <<
"\");\n";
231 handled.append(v.value);
234 stream <<
" default: break;\n"
236 <<
" return QByteArray::number(raw);\n"
240void writeFlagsConverter(QTextStream &stream,
const TraceFlags &flag)
242 stream <<
"inline QByteArray " << flagsConverter(flag.name) <<
"(" << flag.name <<
" value)\n"
244 <<
" const long long raw = static_cast<long long>(value);\n";
246 for (
const TraceFlags::FlagValue &v : flag.values) {
248 stream <<
" if (raw == 0)\n"
249 <<
" return QByteArrayLiteral(\""
250 << aggregateListValues(v.value, flag.values) <<
"\");\n";
255 stream <<
" QByteArray names;\n";
258 for (
const TraceFlags::FlagValue &v : flag.values) {
259 if (v.value != 0 && !handled.contains(v.value)) {
260 handled.append(v.value);
261 stream <<
" if (raw & " << (1LL << (v.value - 1)) <<
") {\n"
262 <<
" if (!names.isEmpty())\n"
263 <<
" names += '" << flagSeparator <<
"';\n"
264 <<
" names += \"" << v.name <<
"\";\n"
268 stream <<
" return names.isEmpty() ? QByteArray::number(raw) : names;\n"
272void writePrologue(QTextStream &stream,
const QString &fileName,
const Provider &provider)
274 writeCommonPrologue(stream);
275 const QString guard = includeGuard(fileName);
278 <<
"#include <hitrace/trace.h>\n"
279 <<
"#include <private/qhitrace_p.h>\n\n";
281 stream <<
"#if !defined(" << guard <<
")\n";
282 stream << qtHeaders();
284 if (!provider.prefixText.isEmpty())
285 stream << provider.prefixText.join(u'\n') <<
"\n\n";
286 stream <<
"#endif\n\n";
288 stream <<
"#if !defined(" << guard <<
")\n";
289 stream <<
"#define " << guard <<
"\n\n";
291 const QString namespaceGuard = guard +
QStringLiteral(
"_USE_NAMESPACE");
292 stream <<
"#if !defined(" << namespaceGuard <<
")\n"
293 <<
"#define " << namespaceGuard <<
"\n"
294 <<
"QT_USE_NAMESPACE\n"
295 <<
"#endif // " << namespaceGuard <<
"\n\n";
297 if (provider.enumerations.isEmpty() && provider.flags.isEmpty())
300 stream <<
"QT_BEGIN_NAMESPACE\n"
301 <<
"namespace QtPrivate {\n";
303 for (
const TraceEnum &enumeration : provider.enumerations)
304 writeEnumConverter(stream, enumeration);
305 for (
const TraceFlags &flag : provider.flags)
306 writeFlagsConverter(stream, flag);
308 stream <<
"} // namespace QtPrivate\n"
309 <<
"QT_END_NAMESPACE\n\n";
312void writeRenderDefinition(QTextStream &stream,
const Tracepoint &tracepoint,
313 const CustomArgs &customArgs,
const Provider &provider)
315 if (customArgs.format.isEmpty())
318 const QString &name = tracepoint.name;
319 const QString guardName =
QStringLiteral(
"TPDEF_%1_%2").arg(provider.name, name).toUpper();
322 <<
"#if defined(TRACEPOINT_DEFINE) && !defined(" << guardName <<
")\n"
323 <<
"#define " << guardName <<
"\n"
324 <<
"QT_BEGIN_NAMESPACE\n"
325 <<
"namespace QtPrivate {\n"
326 <<
"const char *" << renderFunction(provider, name) <<
"("
327 << formatFunctionSignature(tracepoint.args) <<
")\n"
329 for (
const QString &unusedName : customArgs.unusedNames)
330 stream <<
" Q_UNUSED(" << unusedName <<
");\n";
331 stream <<
" return qtHiTraceFormatArguments(sizeof(" << sliceConstant(provider, name)
332 <<
") - 1, \"" << customArgs.format <<
"\", " << customArgs.arguments.join(
", "_L1)
335 <<
"} // namespace QtPrivate\n"
336 <<
"QT_END_NAMESPACE\n"
337 <<
"#endif // " << guardName <<
"\n";
340void writeEpilogue(QTextStream &stream,
const QString &fileName)
343 stream <<
"#endif // " << includeGuard(fileName) <<
"\n";
346void writeWrapper(QTextStream &stream,
const Tracepoint &tracepoint,
const CustomArgs &customArgs,
347 const Provider &provider)
349 const QString argList = formatFunctionSignature(tracepoint.args);
350 const QString paramList =
351 formatParameterList(provider, tracepoint.args, tracepoint.fields, HITRACE);
352 const QString &name = tracepoint.name;
353 const QString guardName =
QStringLiteral(
"TP_%1_%2").arg(provider.name, name).toUpper();
354 const QString slice = sliceName(provider, name);
355 const QString sliceIdentifier = sliceConstant(provider, name);
356 const bool hasCustomArgs = !customArgs.format.isEmpty();
359 <<
"#ifndef " << guardName <<
"\n"
360 <<
"#define " << guardName <<
"\n"
361 <<
"QT_BEGIN_NAMESPACE\n"
362 <<
"namespace QtPrivate {\n";
364 stream <<
"inline constexpr char " << sliceIdentifier <<
"[] = \"" << slice <<
"\";\n";
365 if (customArgs.stringCount > 0) {
366 stream <<
"inline constexpr int " << valueBudget(provider, name)
367 <<
" = qtHiTraceValueBudget(sizeof(" << sliceIdentifier <<
") - 1, "
368 << customArgs.format.size() + customArgs.scalarWidth <<
", "
369 << customArgs.stringCount <<
");\n";
372 const QString render = renderFunction(provider, name);
375 stream <<
"const char *" << render <<
"(" << argList <<
");\n";
377 stream <<
"inline void do_trace_" << name <<
"(" << argList <<
")\n"
380 if (!hasCustomArgs) {
381 for (
const QString &unusedName : customArgs.unusedNames)
382 stream <<
" Q_UNUSED(" << unusedName <<
");\n";
385 const QString startTrace =
386 "OH_HiTrace_StartTraceEx("_L1 + traceLevel +
", "_L1 + sliceIdentifier +
", "_L1;
389 stream <<
" " << startTrace <<
"qtHiTraceIsEnabled() ? " << render <<
"("
390 << paramList <<
") : \"\");\n";
392 stream <<
" " << startTrace <<
"\"\");\n";
394 stream <<
" OH_HiTrace_FinishTraceEx(" << traceLevel <<
");\n";
398 stream <<
"inline void trace_" << name <<
"(" << argList <<
") { do_trace_" << name <<
"("
399 << paramList <<
"); }\n";
401 stream <<
"inline bool trace_" << name <<
"_enabled()\n"
403 <<
" return qtHiTraceIsEnabled();\n"
406 stream <<
"} // namespace QtPrivate\n"
407 <<
"QT_END_NAMESPACE\n"
408 <<
"#endif // " << guardName <<
"\n";
415 QTextStream stream(&file);
417 const QString fileName = QFileInfo(file.fileName()).fileName();
419 QList<CustomArgs> customArgs;
420 for (
const Tracepoint &t : provider.tracepoints)
421 customArgs << customArgsFor(provider, t);
423 writePrologue(stream, fileName, provider);
424 for (qsizetype i = 0; i < provider.tracepoints.size(); ++i)
425 writeWrapper(stream, provider.tracepoints[i], customArgs[i], provider);
426 writeEpilogue(stream, fileName);
428 for (qsizetype i = 0; i < provider.tracepoints.size(); ++i)
429 writeRenderDefinition(stream, provider.tracepoints[i], customArgs[i], provider);
431 stream <<
"#include <private/qtrace_p.h>\n";
void writeHiTrace(QFile &file, const Provider &provider)
const QString & asString(const QString &s)
#define qPrintable(string)
#define QStringLiteral(str)