// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qqmljscompilerstatsreporter_p.h" #include QT_BEGIN_NAMESPACE namespace QQmlJS { using namespace Qt::StringLiterals; AotStatsReporter::AotStatsReporter(const AotStats &aotstats, const QStringList &emptyModules, const QStringList &onlyBytecodeModules) : m_aotstats(aotstats), m_emptyModules(emptyModules), m_onlyBytecodeModules(onlyBytecodeModules) { for (const auto &[moduleUri, fileEntries] : aotstats.entries().asKeyValueRange()) { for (const auto &[filepath, statsEntries] : fileEntries.asKeyValueRange()) { for (const auto &entry : statsEntries) { m_fileCounters[moduleUri][filepath].codegens += 1; if (entry.codegenResult == CodegenResult::Success) { m_fileCounters[moduleUri][filepath].successes += 1; m_successDurations.append(entry.codegenDuration); } else if (entry.codegenResult == CodegenResult::Skip) { m_fileCounters[moduleUri][filepath].skips += 1; } } m_moduleCounters[moduleUri].codegens += m_fileCounters[moduleUri][filepath].codegens; m_moduleCounters[moduleUri].successes += m_fileCounters[moduleUri][filepath].successes; m_moduleCounters[moduleUri].skips += m_fileCounters[moduleUri][filepath].skips; } m_totalCounters.codegens += m_moduleCounters[moduleUri].codegens; m_totalCounters.successes += m_moduleCounters[moduleUri].successes; m_totalCounters.skips += m_moduleCounters[moduleUri].skips; } } void AotStatsReporter::formatDetailedStats(QTextStream &s) const { s << "############ AOT COMPILATION STATS ############\n"; QStringList sortedModuleKeys = m_aotstats.entries().keys(); sortedModuleKeys.sort(); for (const auto &moduleUri : std::as_const(sortedModuleKeys)) { const auto &fileStats = m_aotstats.entries()[moduleUri]; s << u"Module %1:\n"_s.arg(moduleUri); if (fileStats.empty()) { s << "No attempts at compiling a binding or function\n"; continue; } QStringList sortedFileKeys = fileStats.keys(); sortedFileKeys.sort(); for (const auto &filename : std::as_const(sortedFileKeys)) { const auto &entries = fileStats[filename]; s << u"--File %1\n"_s.arg(filename); if (entries.empty()) { s << " No attempts at compiling a binding or function\n"; continue; } int successes = m_fileCounters[moduleUri][filename].successes; int skips = m_fileCounters[moduleUri][filename].skips; s << " " << formatSuccessRate(entries.size(), successes, skips) << "\n"; for (const auto &stat : std::as_const(entries)) { s << u" %1: [%2:%3:%4]\n"_s.arg(stat.functionName) .arg(QFileInfo(filename).fileName()) .arg(stat.line) .arg(stat.column); s << u" result: "_s; switch (stat.codegenResult) { case QQmlJS::CodegenResult::Success: s << u"Success\n"_s; break; case QQmlJS::CodegenResult::Skip: s << u"Skip: %1\n"_s.arg(stat.message); break; case QQmlJS::CodegenResult::Failure: s << u"Error: %1\n"_s.arg(stat.message); break; } s << u" duration: %1us\n"_s.arg(stat.codegenDuration.count()); } s << "\n"; } } } void AotStatsReporter::formatSummary(QTextStream &s) const { s << "############ AOT COMPILATION STATS SUMMARY ############\n"; if (m_totalCounters.codegens == 0 && m_emptyModules.empty() && m_onlyBytecodeModules.empty()) { s << "No attempted compilations to Cpp for bindings or functions.\n"; return; } QStringList sortedKeys = m_aotstats.entries().keys(); sortedKeys.sort(); for (const auto &moduleUri : std::as_const(sortedKeys)) { const auto &counters = m_moduleCounters[moduleUri]; s << u"Module %1: "_s.arg(moduleUri) << formatSuccessRate(counters.codegens, counters.successes, counters.skips) << "\n"; } for (const auto &module : std::as_const(m_emptyModules)) s << u"Module %1: No .qml files to compile.\n"_s.arg(module); for (const auto &module : std::as_const(m_onlyBytecodeModules)) s << u"Module %1: No .qml files compiled (--only-bytecode).\n"_s.arg(module); s << "Total results: " << formatSuccessRate(m_totalCounters.codegens, m_totalCounters.successes, m_totalCounters.skips); s << "\n"; if (m_totalCounters.successes != 0) { auto totalDuration = std::accumulate(m_successDurations.cbegin(), m_successDurations.cend(), std::chrono::microseconds(0)); const auto averageDuration = totalDuration.count() / m_totalCounters.successes; s << u"Successful codegens took an average of %1us\n"_s.arg(averageDuration); } } QString AotStatsReporter::format() const { QString output; QTextStream s(&output); formatDetailedStats(s); formatSummary(s); return output; } QString AotStatsReporter::formatSuccessRate(int codegens, int successes, int skips) const { if (codegens == 0) return u"No attempted compilations"_s; return u"%1 of %2 (%3%4) %5bindings or functions compiled to Cpp successfully"_s .arg(successes) .arg(codegens) .arg(double(successes) / codegens * 100, 0, 'g', 4) .arg(u"%"_s) .arg(skips ? u"(%1 skipped) "_s.arg(skips) : u""_s); } } // namespace QQmlJS QT_END_NAMESPACE