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