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 "qqmljscompilerstats_p.h"
5
6#include <QFile>
7#include <QJsonArray>
8#include <QJsonDocument>
9#include <QJsonObject>
10#include <QTextStream>
11
12QT_BEGIN_NAMESPACE
13
14namespace QQmlJS {
15
16using namespace Qt::StringLiterals;
17
18std::unique_ptr<AotStats> QQmlJSAotCompilerStats::s_instance = std::make_unique<AotStats>();
19QString QQmlJSAotCompilerStats::s_moduleId;
20bool QQmlJSAotCompilerStats::s_recordAotStats = false;
21
22bool QQmlJS::AotStatsEntry::operator<(const AotStatsEntry &other) const
23{
24 if (line == other.line)
25 return column < other.column;
26 return line < other.line;
27}
28
29void AotStats::insert(const AotStats &other)
30{
31 for (const auto &[moduleUri, moduleStats] : other.m_entries.asKeyValueRange()) {
32 m_entries[moduleUri].insert(hash: moduleStats);
33 }
34}
35
36std::optional<QList<QString>> AotStats::readAllLines(const QString &path)
37{
38 QFile aotstatsListFile(path);
39 if (!aotstatsListFile.open(flags: QIODevice::ReadOnly | QIODevice::Text)) {
40 qDebug().noquote() << u"Could not open \"%1\" for reading"_s.arg(a: aotstatsListFile.fileName());
41 return std::nullopt;
42 }
43
44 QStringList aotstatsFiles;
45 QTextStream stream(&aotstatsListFile);
46 while (!stream.atEnd())
47 aotstatsFiles.append(t: stream.readLine());
48
49 return aotstatsFiles;
50}
51
52std::optional<AotStats> AotStats::parseAotstatsFile(const QString &aotstatsPath)
53{
54 QFile file(aotstatsPath);
55 if (!file.open(flags: QIODevice::ReadOnly | QIODevice::Text)) {
56 qDebug().noquote() << u"Could not open \"%1\""_s.arg(a: aotstatsPath);
57 return std::nullopt;
58 }
59
60 return AotStats::fromJsonDocument(QJsonDocument::fromJson(json: file.readAll()));
61}
62
63std::optional<AotStats> AotStats::aggregateAotstatsList(const QString &aotstatsListPath)
64{
65 const auto aotstatsFiles = readAllLines(path: aotstatsListPath);
66 if (!aotstatsFiles.has_value())
67 return std::nullopt;
68
69 AotStats aggregated;
70 if (aotstatsFiles->empty())
71 return aggregated;
72
73 for (const auto &aotstatsFile : aotstatsFiles.value()) {
74 auto parsed = parseAotstatsFile(aotstatsPath: aotstatsFile);
75 if (!parsed.has_value())
76 return std::nullopt;
77 aggregated.insert(other: parsed.value());
78 }
79
80 return aggregated;
81}
82
83AotStats AotStats::fromJsonDocument(const QJsonDocument &document)
84{
85 QJsonArray modulesArray = document.array();
86
87 QQmlJS::AotStats result;
88 for (const auto &modulesArrayEntry : modulesArray) {
89 const auto &moduleObject = modulesArrayEntry.toObject();
90 QString moduleId = moduleObject[u"moduleId"_s].toString();
91 const QJsonArray &filesArray = moduleObject[u"moduleFiles"_s].toArray();
92
93 QHash<QString, QList<AotStatsEntry>> files;
94 for (const auto &filesArrayEntry : filesArray) {
95 const QJsonObject &fileObject = filesArrayEntry.toObject();
96 QString filepath = fileObject[u"filepath"_s].toString();
97 const QJsonArray &statsArray = fileObject[u"entries"_s].toArray();
98
99 QList<AotStatsEntry> stats;
100 for (const auto &statsArrayEntry : statsArray) {
101 const auto &statsObject = statsArrayEntry.toObject();
102 QQmlJS::AotStatsEntry stat;
103 auto micros = statsObject[u"durationMicroseconds"_s].toInteger();
104 stat.codegenDuration = std::chrono::microseconds(micros);
105 stat.functionName = statsObject[u"functionName"_s].toString();
106 stat.errorMessage = statsObject[u"errorMessage"_s].toString();
107 stat.line = statsObject[u"line"_s].toInt();
108 stat.column = statsObject[u"column"_s].toInt();
109 stat.codegenSuccessful = statsObject[u"codegenSuccessfull"_s].toBool();
110 stats.append(t: std::move(stat));
111 }
112
113 std::sort(first: stats.begin(), last: stats.end());
114 files[filepath] = stats;
115 }
116
117 result.m_entries[moduleId] = files;
118 }
119
120 return result;
121}
122
123QJsonDocument AotStats::toJsonDocument() const
124{
125 QJsonArray modulesArray;
126 for (auto it1 = m_entries.begin(); it1 != m_entries.end(); ++it1) {
127 const QString moduleId = it1.key();
128 const QHash<QString, QList<AotStatsEntry>> &files = it1.value();
129
130 QJsonArray filesArray;
131 for (auto it2 = files.begin(); it2 != files.end(); ++it2) {
132 const QString &filename = it2.key();
133 const QList<AotStatsEntry> &stats = it2.value();
134
135 QJsonArray statsArray;
136 for (const auto &stat : stats) {
137 QJsonObject statObject;
138 auto micros = static_cast<qint64>(stat.codegenDuration.count());
139 statObject.insert(key: u"durationMicroseconds", value: micros);
140 statObject.insert(key: u"functionName", value: stat.functionName);
141 statObject.insert(key: u"errorMessage", value: stat.errorMessage);
142 statObject.insert(key: u"line", value: stat.line);
143 statObject.insert(key: u"column", value: stat.column);
144 statObject.insert(key: u"codegenSuccessfull", value: stat.codegenSuccessful);
145 statsArray.append(value: statObject);
146 }
147
148 QJsonObject o;
149 o.insert(key: u"filepath"_s, value: filename);
150 o.insert(key: u"entries"_s, value: statsArray);
151 filesArray.append(value: o);
152 }
153
154 QJsonObject o;
155 o.insert(key: u"moduleId"_s, value: moduleId);
156 o.insert(key: u"moduleFiles"_s, value: filesArray);
157 modulesArray.append(value: o);
158 }
159
160 return QJsonDocument(modulesArray);
161}
162
163void AotStats::registerFile(const QString &moduleId, const QString &filepath)
164{
165 m_entries[moduleId][filepath] = {};
166}
167
168void AotStats::addEntry(const QString &moduleId, const QString &filepath,
169 const AotStatsEntry &entry)
170{
171 m_entries[moduleId][filepath].append(t: entry);
172}
173
174bool AotStats::saveToDisk(const QString &filepath) const
175{
176 QFile file(filepath);
177 if (!file.open(flags: QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
178 qDebug().noquote() << u"Could not open \"%1\""_s.arg(a: filepath);
179 return false;
180 }
181
182 file.write(data: this->toJsonDocument().toJson(format: QJsonDocument::Indented));
183 return true;
184}
185
186void QQmlJSAotCompilerStats::registerFile(const QString &filepath)
187{
188 QQmlJSAotCompilerStats::instance()->registerFile(moduleId: s_moduleId, filepath);
189}
190
191void QQmlJSAotCompilerStats::addEntry(const QString &filepath, const QQmlJS::AotStatsEntry &entry)
192{
193 auto *aotstats = QQmlJSAotCompilerStats::instance();
194 aotstats->addEntry(moduleId: s_moduleId, filepath, entry);
195}
196
197} // namespace QQmlJS
198
199QT_END_NAMESPACE
200

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qmlcompiler/qqmljscompilerstats.cpp