1 /*
2 SPDX-FileCopyrightText: 2014 Frank Reininghaus <frank78ac@googlemail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include <kio/udsentry.h>
8
9 #include <QTest>
10
11 /**
12 * This benchmarks tests four typical uses of UDSEntry:
13 *
14 * (a) Store data in UDSEntries using
15 * UDSEntry::insert(uint, const QString&) and
16 * UDSEntry::insert(uint, long long),
17 * and append the entries to a UDSEntryList.
18 *
19 * (b) Read data from UDSEntries in a UDSEntryList using
20 * UDSEntry::stringValue(uint) and UDSEntry::numberValue(uint).
21 *
22 * (c) Save a UDSEntryList in a QDataStream.
23 *
24 * (d) Load a UDSEntryList from a QDataStream.
25 *
26 * This is done for two different data sets:
27 *
28 * 1. UDSEntries containing the entries which are provided by kio_file.
29 *
30 * 2. UDSEntries with a larger number of "fields".
31 */
32
33 // The following constants control the number of UDSEntries that are considered
34 // in each test, and the number of extra "fields" that are used for large UDSEntries.
35 const int numberOfSmallUDSEntries = 100 * 1000;
36 const int numberOfLargeUDSEntries = 5 * 1000;
37 const int extraFieldsForLargeUDSEntries = 40;
38
39 class UDSEntryBenchmark : public QObject
40 {
41 Q_OBJECT
42
43 public:
44 UDSEntryBenchmark();
45
46 private Q_SLOTS:
47 void createSmallEntries();
48 void createLargeEntries();
49 void readFieldsFromSmallEntries();
50 void readFieldsFromLargeEntries();
51 void saveSmallEntries();
52 void saveLargeEntries();
53 void loadSmallEntries();
54 void loadLargeEntries();
55
56 private:
57 KIO::UDSEntryList m_smallEntries;
58 KIO::UDSEntryList m_largeEntries;
59 QByteArray m_savedSmallEntries;
60 QByteArray m_savedLargeEntries;
61
62 QVector<uint> m_fieldsForLargeEntries;
63 };
64
UDSEntryBenchmark()65 UDSEntryBenchmark::UDSEntryBenchmark()
66 {
67 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_SIZE);
68 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_SIZE_LARGE);
69 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_USER);
70 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ICON_NAME);
71 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_GROUP);
72 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_NAME);
73 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_LOCAL_PATH);
74 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_HIDDEN);
75 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ACCESS);
76 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_MODIFICATION_TIME);
77 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ACCESS_TIME);
78 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_CREATION_TIME);
79 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_FILE_TYPE);
80 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_LINK_DEST);
81 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_URL);
82 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_MIME_TYPE);
83 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_GUESSED_MIME_TYPE);
84 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_XML_PROPERTIES);
85 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_EXTENDED_ACL);
86 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ACL_STRING);
87 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DEFAULT_ACL_STRING);
88 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DISPLAY_NAME);
89 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_TARGET_URL);
90 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DISPLAY_TYPE);
91 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES);
92 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_COMMENT);
93 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DEVICE_ID);
94 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_INODE);
95
96 for (int i = 0; i < extraFieldsForLargeUDSEntries; ++i) {
97 m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_EXTRA + i);
98 }
99 }
100
createSmallEntries()101 void UDSEntryBenchmark::createSmallEntries()
102 {
103 m_smallEntries.clear();
104 m_smallEntries.reserve(numberOfSmallUDSEntries);
105
106 const QString user = QStringLiteral("user");
107 const QString group = QStringLiteral("group");
108
109 QVector<QString> names(numberOfSmallUDSEntries);
110 for (int i = 0; i < numberOfSmallUDSEntries; ++i) {
111 names[i] = QString::number(i);
112 }
113
114 QBENCHMARK_ONCE {
115 for (int i = 0; i < numberOfSmallUDSEntries; ++i) {
116 KIO::UDSEntry entry;
117 entry.reserve(8);
118 entry.fastInsert(KIO::UDSEntry::UDS_NAME, names[i]);
119 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, i);
120 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, i);
121 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, i);
122 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, i);
123 entry.fastInsert(KIO::UDSEntry::UDS_USER, user);
124 entry.fastInsert(KIO::UDSEntry::UDS_GROUP, group);
125 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, i);
126 m_smallEntries.append(entry);
127 }
128 }
129
130 Q_ASSERT(m_smallEntries.count() == numberOfSmallUDSEntries);
131 }
132
createLargeEntries()133 void UDSEntryBenchmark::createLargeEntries()
134 {
135 m_largeEntries.clear();
136 m_largeEntries.reserve(numberOfLargeUDSEntries);
137
138 QVector<QString> names(numberOfLargeUDSEntries);
139 for (int i = 0; i < numberOfLargeUDSEntries; ++i) {
140 names[i] = QString::number(i);
141 }
142
143 QBENCHMARK_ONCE {
144 for (int i = 0; i < numberOfLargeUDSEntries; ++i) {
145 KIO::UDSEntry entry;
146 entry.reserve(m_fieldsForLargeEntries.count());
147 for (uint field : std::as_const(m_fieldsForLargeEntries)) {
148 if (field & KIO::UDSEntry::UDS_STRING) {
149 entry.fastInsert(field, names[i]);
150 } else {
151 entry.fastInsert(field, i);
152 }
153 }
154 m_largeEntries.append(entry);
155 }
156 }
157
158 Q_ASSERT(m_largeEntries.count() == numberOfLargeUDSEntries);
159 }
160
readFieldsFromSmallEntries()161 void UDSEntryBenchmark::readFieldsFromSmallEntries()
162 {
163 // Create the entries if they do not exist yet.
164 if (m_smallEntries.isEmpty()) {
165 createSmallEntries();
166 }
167
168 const QString user = QStringLiteral("user");
169 const QString group = QStringLiteral("group");
170
171 QBENCHMARK {
172 long long i = 0;
173 long long entrySum = 0;
174
175 for (const KIO::UDSEntry &entry : std::as_const(m_smallEntries)) {
176 entrySum += entry.count();
177 /* clang-format off */
178 if (entry.stringValue(KIO::UDSEntry::UDS_NAME).toInt() == i
179 && entry.numberValue(KIO::UDSEntry::UDS_FILE_TYPE) == i
180 && entry.numberValue(KIO::UDSEntry::UDS_ACCESS) == i
181 && entry.numberValue(KIO::UDSEntry::UDS_SIZE) == i
182 && entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) == i
183 && entry.stringValue(KIO::UDSEntry::UDS_USER) == user
184 && entry.stringValue(KIO::UDSEntry::UDS_GROUP) == group
185 && entry.numberValue(KIO::UDSEntry::UDS_ACCESS_TIME) == i) { /* clang-format on */
186 ++i;
187 }
188 }
189
190 QCOMPARE(i, numberOfSmallUDSEntries);
191 QCOMPARE(entrySum, numberOfSmallUDSEntries * 8);
192 }
193 }
194
readFieldsFromLargeEntries()195 void UDSEntryBenchmark::readFieldsFromLargeEntries()
196 {
197 // Create the entries if they do not exist yet.
198 if (m_largeEntries.isEmpty()) {
199 createLargeEntries();
200 }
201
202 QBENCHMARK_ONCE {
203 long long i = 0;
204 long long fieldSum = 0;
205
206 for (const KIO::UDSEntry &entry : std::as_const(m_largeEntries)) {
207 for (uint field : std::as_const(m_fieldsForLargeEntries)) {
208 if (field & KIO::UDSEntry::UDS_STRING) {
209 if (entry.stringValue(field).toInt() == i) {
210 ++fieldSum;
211 }
212 } else if (entry.numberValue(field) == i) {
213 ++fieldSum;
214 }
215 }
216 ++i;
217 }
218
219 QCOMPARE(fieldSum, m_fieldsForLargeEntries.count() * m_largeEntries.count());
220 }
221 }
222
saveSmallEntries()223 void UDSEntryBenchmark::saveSmallEntries()
224 {
225 // Create the entries if they do not exist yet.
226 if (m_smallEntries.isEmpty()) {
227 createSmallEntries();
228 }
229
230 m_savedSmallEntries.clear();
231
232 QBENCHMARK_ONCE {
233 QDataStream stream(&m_savedSmallEntries, QIODevice::WriteOnly);
234 stream << m_smallEntries;
235 }
236 }
237
saveLargeEntries()238 void UDSEntryBenchmark::saveLargeEntries()
239 {
240 // Create the entries if they do not exist yet.
241 if (m_smallEntries.isEmpty()) {
242 createLargeEntries();
243 }
244
245 m_savedLargeEntries.clear();
246
247 QBENCHMARK_ONCE {
248 QDataStream stream(&m_savedLargeEntries, QIODevice::WriteOnly);
249 stream << m_largeEntries;
250 }
251 }
loadSmallEntries()252 void UDSEntryBenchmark::loadSmallEntries()
253 {
254 // Save the entries if that has not been done yet.
255 if (m_savedSmallEntries.isEmpty()) {
256 saveSmallEntries();
257 }
258
259 QDataStream stream(m_savedSmallEntries);
260 KIO::UDSEntryList entries;
261
262 QBENCHMARK_ONCE {
263 stream >> entries;
264 }
265
266 QCOMPARE(entries, m_smallEntries);
267 }
268
loadLargeEntries()269 void UDSEntryBenchmark::loadLargeEntries()
270 {
271 // Save the entries if that has not been done yet.
272 if (m_savedLargeEntries.isEmpty()) {
273 saveLargeEntries();
274 }
275
276 QDataStream stream(m_savedLargeEntries);
277 KIO::UDSEntryList entries;
278
279 QBENCHMARK_ONCE {
280 stream >> entries;
281 }
282
283 QCOMPARE(entries, m_largeEntries);
284 }
285
286 QTEST_MAIN(UDSEntryBenchmark)
287
288 #include "udsentry_benchmark.moc"
289