summaryrefslogtreecommitdiffstats
path: root/tests/dummyresourcewritebenchmark.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-12-22 17:40:42 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-12-22 17:40:42 +0100
commit1ea79c5916d6d98f4d15defcc238a319f759798b (patch)
treec1b68cd447453a939d77437047437874d829cbac /tests/dummyresourcewritebenchmark.cpp
parent501a9c3a441a4fbd5629a15e4056a52b54834baf (diff)
downloadsink-1ea79c5916d6d98f4d15defcc238a319f759798b.tar.gz
sink-1ea79c5916d6d98f4d15defcc238a319f759798b.zip
A benchmark for resource writing memory usage
Diffstat (limited to 'tests/dummyresourcewritebenchmark.cpp')
-rw-r--r--tests/dummyresourcewritebenchmark.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/tests/dummyresourcewritebenchmark.cpp b/tests/dummyresourcewritebenchmark.cpp
new file mode 100644
index 0000000..3e8f4c5
--- /dev/null
+++ b/tests/dummyresourcewritebenchmark.cpp
@@ -0,0 +1,227 @@
1#include <QtTest>
2
3#include <QString>
4
5#include <iostream>
6
7#include "dummyresource/resourcefactory.h"
8#include "dummyresource/domainadaptor.h"
9#include "clientapi.h"
10#include "commands.h"
11#include "entitybuffer.h"
12#include "pipeline.h"
13#include "log.h"
14#include "resourceconfig.h"
15#include "definitions.h"
16
17#include "hawd/dataset.h"
18#include "hawd/formatter.h"
19
20#include "event_generated.h"
21#include "entity_generated.h"
22#include "metadata_generated.h"
23#include "createentity_generated.h"
24
25#include "getrssusage.h"
26
27static double variance(const QList<double> &values)
28{
29 double mean = 0;
30 for (auto value : values) {
31 mean += value;
32 }
33 mean = mean / static_cast<double>(values.size());
34 double variance = 0;
35 for (auto value : values) {
36 variance += pow(static_cast<double>(value) - mean, 2);
37 }
38 variance = variance / static_cast<double>(values.size() - 1);
39 return variance;
40}
41
42static double maxDifference(const QList<double> &values)
43{
44 auto max = values.first();
45 auto min = values.first();
46 for (auto value : values) {
47 if (value > max) {
48 max = value;
49 }
50 if (value < min) {
51 min = value;
52 }
53 }
54 return max - min;
55}
56
57static QByteArray createEntityBuffer(int &bufferSize)
58{
59 flatbuffers::FlatBufferBuilder eventFbb;
60 eventFbb.Clear();
61 {
62 auto summary = eventFbb.CreateString("summary");
63 Akonadi2::ApplicationDomain::Buffer::EventBuilder eventBuilder(eventFbb);
64 eventBuilder.add_summary(summary);
65 auto eventLocation = eventBuilder.Finish();
66 Akonadi2::ApplicationDomain::Buffer::FinishEventBuffer(eventFbb, eventLocation);
67 }
68
69 flatbuffers::FlatBufferBuilder localFbb;
70 {
71 auto uid = localFbb.CreateString("testuid");
72 auto localBuilder = Akonadi2::ApplicationDomain::Buffer::EventBuilder(localFbb);
73 localBuilder.add_uid(uid);
74 auto location = localBuilder.Finish();
75 Akonadi2::ApplicationDomain::Buffer::FinishEventBuffer(localFbb, location);
76 }
77
78 flatbuffers::FlatBufferBuilder entityFbb;
79 Akonadi2::EntityBuffer::assembleEntityBuffer(entityFbb, 0, 0, eventFbb.GetBufferPointer(), eventFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize());
80 bufferSize = entityFbb.GetSize();
81
82 flatbuffers::FlatBufferBuilder fbb;
83 auto type = fbb.CreateString(Akonadi2::ApplicationDomain::getTypeName<Akonadi2::ApplicationDomain::Event>().toStdString().data());
84 auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize());
85 Akonadi2::Commands::CreateEntityBuilder builder(fbb);
86 builder.add_domainType(type);
87 builder.add_delta(delta);
88 auto location = builder.Finish();
89 Akonadi2::Commands::FinishCreateEntityBuffer(fbb, location);
90
91 return QByteArray(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
92}
93
94/**
95 * Benchmark writing in the synchronizer process.
96 */
97class DummyResourceWriteBenchmark : public QObject
98{
99 Q_OBJECT
100
101 QList<double> mRssGrowthPerEntity;
102 QList<double> mTimePerEntity;
103
104 void writeInProcess(int num)
105 {
106 DummyResource::removeFromDisk("org.kde.dummy.instance1");
107
108
109 QTime time;
110 time.start();
111
112 auto pipeline = QSharedPointer<Akonadi2::Pipeline>::create("org.kde.dummy.instance1");
113 DummyResource resource("org.kde.dummy.instance1", pipeline);
114
115 int bufferSize = 0;
116 auto command = createEntityBuffer(bufferSize);
117
118 const auto startingRss = getCurrentRSS();
119 for (int i = 0; i < num; i++) {
120 resource.processCommand(Akonadi2::Commands::CreateEntityCommand, command);
121 }
122 auto appendTime = time.elapsed();
123 auto bufferSizeTotal = bufferSize * num;
124
125 //Wait until all messages have been processed
126 resource.processAllMessages().exec().waitForFinished();
127
128 auto allProcessedTime = time.elapsed();
129
130 const auto finalRss = getCurrentRSS();
131 const auto rssGrowth = finalRss - startingRss;
132 //Since the database is memory mapped it is attributted to the resident set size.
133 const auto rssWithoutDb = finalRss - DummyResource::diskUsage("org.kde.dummy.instance1");
134 const auto peakRss = getPeakRSS();
135 //How much peak deviates from final rss in percent
136 const auto percentageRssError = static_cast<double>(peakRss - finalRss)*100.0/static_cast<double>(finalRss);
137 auto rssGrowthPerEntity = rssGrowth/num;
138 std::cout << "Current Rss usage [kb]: " << finalRss/1024 << std::endl;
139 std::cout << "Peak Rss usage [kb]: " << peakRss/1024 << std::endl;
140 std::cout << "Rss growth [kb]: " << rssGrowth/1024 << std::endl;
141 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl;
142 std::cout << "Rss without db [kb]: " << rssWithoutDb/1024 << std::endl;
143 std::cout << "Percentage peak rss error: " << percentageRssError << std::endl;
144
145 auto onDisk = DummyResource::diskUsage("org.kde.dummy.instance1");
146 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal);
147 std::cout << "On disk [kb]: " << onDisk/1024 << std::endl;
148 std::cout << "Buffer size total [kb]: " << bufferSizeTotal/1024 << std::endl;
149 std::cout << "Write amplification: " << writeAmplification << std::endl;
150
151
152 mTimePerEntity << static_cast<double>(allProcessedTime)/static_cast<double>(num);
153 mRssGrowthPerEntity << rssGrowthPerEntity;
154
155 QVERIFY(percentageRssError < 10);
156 //TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase,
157 //so it doesn't look like that memory is being duplicated.
158 QVERIFY(rssGrowthPerEntity < 2500);
159
160 // HAWD::Dataset dataset("dummy_write_in_process", m_hawdState);
161 // HAWD::Dataset::Row row = dataset.row();
162 //
163 // row.setValue("rows", num);
164 // row.setValue("append", (qreal)num/appendTime);
165 // row.setValue("total", (qreal)num/allProcessedTime);
166 // dataset.insertRow(row);
167 // HAWD::Formatter::print(dataset);
168
169 // Print memory layout, RSS is what is in memory
170 // std::system("exec pmap -x \"$PPID\"");
171 }
172
173
174private Q_SLOTS:
175 void initTestCase()
176 {
177 Akonadi2::Log::setDebugOutputLevel(Akonadi2::Log::Warning);
178 }
179
180 void cleanup()
181 {
182 }
183
184 void test1k()
185 {
186 writeInProcess(1000);
187 }
188
189 void test2k()
190 {
191 writeInProcess(2000);
192 }
193
194 void test5k()
195 {
196 writeInProcess(5000);
197 }
198
199 // void test20k()
200 // {
201 // writeInProcess(20000);
202 // }
203 //
204 void ensureUsedMemoryRemainsStable()
205 {
206 auto rssStandardDeviation = sqrt(variance(mRssGrowthPerEntity));
207 auto timeStandardDeviation = sqrt(variance(mTimePerEntity));
208 std::cout << "Rss standard deviation " << rssStandardDeviation << std::endl;
209 std::cout << "Rss max difference [byte]" << maxDifference(mRssGrowthPerEntity) << std::endl;
210 std::cout << "Time standard deviation " << timeStandardDeviation << std::endl;
211 std::cout << "Time max difference [ms]" << maxDifference(mTimePerEntity) << std::endl;
212 QVERIFY(rssStandardDeviation < 1000);
213 QVERIFY(timeStandardDeviation < 1);
214 }
215
216 //This allows to run individual parts without doing a cleanup, but still cleaning up normally
217 void testCleanupForCompleteTest()
218 {
219 DummyResource::removeFromDisk("org.kde.dummy.instance1");
220 }
221
222private:
223 HAWD::State m_hawdState;
224};
225
226QTEST_MAIN(DummyResourceWriteBenchmark)
227#include "dummyresourcewritebenchmark.moc"