1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include "qqmljscompilerstatsreporter_p.h" |
5 | |
6 | #include <QFileInfo> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | namespace QQmlJS { |
11 | |
12 | using namespace Qt::StringLiterals; |
13 | |
14 | AotStatsReporter::AotStatsReporter(const AotStats &aotstats, const QStringList &emptyModules, |
15 | const QStringList &onlyBytecodeModules) |
16 | : m_aotstats(aotstats), m_emptyModules(emptyModules), m_onlyBytecodeModules(onlyBytecodeModules) |
17 | { |
18 | for (const auto &[moduleUri, fileEntries] : aotstats.entries().asKeyValueRange()) { |
19 | for (const auto &[filepath, statsEntries] : fileEntries.asKeyValueRange()) { |
20 | for (const auto &entry : statsEntries) { |
21 | m_fileCounters[moduleUri][filepath].codegens += 1; |
22 | if (entry.codegenSuccessful) { |
23 | m_fileCounters[moduleUri][filepath].successes += 1; |
24 | m_successDurations.append(t: entry.codegenDuration); |
25 | } |
26 | } |
27 | m_moduleCounters[moduleUri].codegens += m_fileCounters[moduleUri][filepath].codegens; |
28 | m_moduleCounters[moduleUri].successes += m_fileCounters[moduleUri][filepath].successes; |
29 | } |
30 | m_totalCounters.codegens += m_moduleCounters[moduleUri].codegens; |
31 | m_totalCounters.successes += m_moduleCounters[moduleUri].successes; |
32 | } |
33 | } |
34 | |
35 | void AotStatsReporter::formatDetailedStats(QTextStream &s) const |
36 | { |
37 | s << "############ AOT COMPILATION STATS ############\n" ; |
38 | QStringList sortedModuleKeys = m_aotstats.entries().keys(); |
39 | sortedModuleKeys.sort(); |
40 | for (const auto &moduleUri : std::as_const(t&: sortedModuleKeys)) { |
41 | const auto &fileStats = m_aotstats.entries()[moduleUri]; |
42 | s << u"Module %1:\n"_s .arg(a: moduleUri); |
43 | if (fileStats.empty()) { |
44 | s << "No attempts at compiling a binding or function\n" ; |
45 | continue; |
46 | } |
47 | |
48 | QStringList sortedFileKeys = fileStats.keys(); |
49 | sortedFileKeys.sort(); |
50 | for (const auto &filename : std::as_const(t&: sortedFileKeys)) { |
51 | const auto &entries = fileStats[filename]; |
52 | s << u"--File %1\n"_s .arg(a: filename); |
53 | if (entries.empty()) { |
54 | s << " No attempts at compiling a binding or function\n" ; |
55 | continue; |
56 | } |
57 | |
58 | int successes = m_fileCounters[moduleUri][filename].successes; |
59 | s << " " << formatSuccessRate(codegens: entries.size(), successes) << "\n" ; |
60 | |
61 | for (const auto &stat : std::as_const(t: entries)) { |
62 | s << u" %1: [%2:%3:%4]\n"_s .arg(a: stat.functionName) |
63 | .arg(a: QFileInfo(filename).fileName()) |
64 | .arg(a: stat.line) |
65 | .arg(a: stat.column); |
66 | s << u" result: "_s << (stat.codegenSuccessful |
67 | ? u"Success\n"_s |
68 | : u"Error: "_s + stat.errorMessage + u'\n'); |
69 | s << u" duration: %1us\n"_s .arg(a: stat.codegenDuration.count()); |
70 | } |
71 | s << "\n" ; |
72 | } |
73 | } |
74 | } |
75 | |
76 | void AotStatsReporter::formatSummary(QTextStream &s) const |
77 | { |
78 | s << "############ AOT COMPILATION STATS SUMMARY ############\n" ; |
79 | if (m_totalCounters.codegens == 0 && m_emptyModules.empty() && m_onlyBytecodeModules.empty()) { |
80 | s << "No attempted compilations to Cpp for bindings or functions.\n" ; |
81 | return; |
82 | } |
83 | |
84 | QStringList sortedKeys = m_aotstats.entries().keys(); |
85 | sortedKeys.sort(); |
86 | for (const auto &moduleUri : std::as_const(t&: sortedKeys)) { |
87 | const auto &counters = m_moduleCounters[moduleUri]; |
88 | s << u"Module %1: "_s .arg(a: moduleUri) |
89 | << formatSuccessRate(codegens: counters.codegens, successes: counters.successes) << "\n" ; |
90 | } |
91 | |
92 | for (const auto &module : std::as_const(t: m_emptyModules)) |
93 | s << u"Module %1: No .qml files to compile.\n"_s .arg(a: module); |
94 | |
95 | for (const auto &module : std::as_const(t: m_onlyBytecodeModules)) |
96 | s << u"Module %1: No .qml files compiled (--only-bytecode).\n"_s .arg(a: module); |
97 | |
98 | s << "Total results: " << formatSuccessRate(codegens: m_totalCounters.codegens, successes: m_totalCounters.successes); |
99 | s << "\n" ; |
100 | |
101 | if (m_totalCounters.successes != 0) { |
102 | auto totalDuration = std::accumulate(first: m_successDurations.cbegin(), last: m_successDurations.cend(), |
103 | init: std::chrono::microseconds(0)); |
104 | const auto averageDuration = totalDuration.count() / m_totalCounters.successes; |
105 | s << u"Successful codegens took an average of %1us\n"_s .arg(a: averageDuration); |
106 | } |
107 | } |
108 | |
109 | QString AotStatsReporter::format() const |
110 | { |
111 | QString output; |
112 | QTextStream s(&output); |
113 | |
114 | formatDetailedStats(s); |
115 | formatSummary(s); |
116 | |
117 | return output; |
118 | } |
119 | |
120 | QString AotStatsReporter::formatSuccessRate(int codegens, int successes) const |
121 | { |
122 | if (codegens == 0) |
123 | return u"No attempted compilations"_s ; |
124 | |
125 | return u"%1 of %2 (%3%4) bindings or functions compiled to Cpp successfully"_s |
126 | .arg(a: successes) |
127 | .arg(a: codegens) |
128 | .arg(a: double(successes) / codegens * 100, fieldWidth: 0, format: 'g', precision: 4) |
129 | .arg(a: u"%"_s ); |
130 | } |
131 | |
132 | } // namespace QQmlJS |
133 | |
134 | QT_END_NAMESPACE |
135 | |