Revision control

Copy as Markdown

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// Qt-Security score:significant
#include "qqmljscompilerstatsreporter_p.h"
#include <QFileInfo>
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