AutoPas  3.0.0
Loading...
Searching...
No Matches
LogToSQLiteWriter.h
1#pragma once
2
3#include <sqlite3.h>
4
5#include <fstream>
6#include <sstream>
7#include <stdexcept>
8#include <tuple>
9
12
19template <class T>
20void toStringHelper(std::ostream &in, const T &val) {
21 in << val << ' ';
22}
23
24template <class... Payload>
25auto toString(const Payload &...payload) {
26 std::stringstream stream;
27 (toStringHelper(stream, payload), ...);
28 return stream.str();
29}
30
31template <class... Payload>
32std::tuple<Payload...> fromString(std::stringstream &stream) {
33 std::tuple<Payload...> tuple{};
34 ((stream >> std::get<Payload>(tuple)), ...);
35 return tuple;
36}
37
38std::string writeEvidence(long time, size_t iteration, const Configuration &config) {
39 return toString(std::string{"evidence"}, time, iteration, config);
40}
41
42std::tuple<long, size_t, Configuration> readEvidence(std::stringstream &str) {
43 return fromString<long, size_t, Configuration>(str);
44}
45
46std::string writeTune() { return toString(std::string{"tune"}); }
47
48bool readTune(std::stringstream &str) { return std::get<0>(fromString<bool>(str)); }
49
50std::string writeReset(size_t iteration) { return toString(std::string{"reset"}, iteration); }
51
52size_t readReset(std::stringstream &str) { return std::get<0>(fromString<size_t>(str)); }
53
54std::string writeLiveInfo(const LiveInfo &liveInfo) { return toString(std::string{"liveInfo"}, liveInfo); }
55
56LiveInfo readLiveInfo(std::stringstream &str) { return std::get<0>(fromString<LiveInfo>(str)); }
57}; // namespace autopas::tuningLogEntry
58
63static int callback(void *, int argc, char **argv, char **azColName) {
64 for (int i = 0; i < argc; ++i) {
65 std::cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << " ";
66 }
67 std::cout << std::endl;
68 return 0;
69}
70
76static std::string escapeSingleQuotesForSQL(const std::string &str) {
77 std::string result;
78 // If we call this function, we expect that there often are single quotes in the string.
79 // In many cases, there isn't just one, so reserve a bit of extra memory to decrease the
80 // chance that two resizes are necessary.
81 result.reserve(str.size() + 6);
82
83 for (char c : str) {
84 result.push_back(c);
85 if (c == '\'') {
86 result.push_back('\'');
87 }
88 }
89
90 return result;
91}
92
99 public:
104 explicit LogToSQLiteWriter(const std::string &databaseName) : _db(nullptr) {
105 auto failed = sqlite3_open(databaseName.c_str(), &_db);
106
107 if (failed) {
108 AutoPasLog(ERROR, "Can't open database {}: {}", databaseName, sqlite3_errmsg(_db));
109 throw std::invalid_argument{databaseName};
110 }
111
112 createSchema();
113 }
114
120 void write(const char *filename) {
121 std::ifstream in{filename};
122
123 if (not in.is_open()) {
124 AutoPasLog(ERROR, "Could not open file {}", filename);
125 AutoPasLog(ERROR, "Exiting!");
126 exit(-1);
127 }
128
129 auto escapedFilename = escapeSingleQuotesForSQL(filename);
130 std::stringstream insertScenarios;
131 std::stringstream insertMeasurements;
132 insertScenarios << "INSERT INTO ScenarioRaw VALUES ";
133 insertMeasurements << "INSERT INTO MeasurementRaw VALUES ";
134 char sepScenarios = ' ';
135 char sepMeasurements = ' ';
136 while (not in.eof()) {
137 std::string line;
138 std::getline(in, line, '\n');
139
140 std::stringstream stream{line};
141 std::string type;
142 std::getline(stream, type, ' ');
143
144 if (type == "evidence") {
145 const auto &[time, iteration, config] = autopas::tuningLogEntry::readEvidence(stream);
146 insertMeasurements << sepMeasurements << "(\'" << escapedFilename << "\',\'" << config.container << "\',"
147 << config.cellSizeFactor << ",\'" << config.traversal << "\',\'" << config.loadEstimator
148 << "\',\'" << config.dataLayout << "\',\'" << config.newton3 << "\'," << iteration << ","
149 << time << ")";
150 sepMeasurements = ',';
151 } else if (type == "tune") {
152 // Do nothing in former tune
153 } else if (type == "liveInfo") {
154 const auto &liveInfo = autopas::tuningLogEntry::readLiveInfo(stream);
155 const auto &d = liveInfo.get();
156 auto toStr = [](const auto &variant) {
157 return std::visit([](const auto &val) { return std::to_string(val); }, variant);
158 };
159 insertScenarios << sepScenarios << "( \'" << escapedFilename << "\'," << toStr(d.at("avgParticlesPerCell"))
160 << "," << toStr(d.at("cutoff")) << "," << toStr(d.at("domainSizeX")) << ","
161 << toStr(d.at("domainSizeY")) << "," << toStr(d.at("domainSizeZ")) << ","
162 << toStr(d.at("maxParticlesPerCell")) << "," << toStr(d.at("minParticlesPerCell")) << ","
163 << toStr(d.at("numCells")) << "," << toStr(d.at("numEmptyCells")) << ","
164 << toStr(d.at("numHaloParticles")) << "," << toStr(d.at("numParticles")) << ","
165 << toStr(d.at("particleSize")) << "," << toStr(d.at("particleSizeNeededByFunctor")) << ","
166 << toStr(d.at("particlesPerBlurredCellStdDev")) << "," << toStr(d.at("particlesPerCellStdDev"))
167 << "," << toStr(d.at("skin")) << "," << toStr(d.at("threadCount")) << ","
168 << toStr(d.at("rebuildFrequency")) << "," << toStr(d.at("estimatedNumNeighborInteractions"))
169 << ")";
170 sepScenarios = ',';
171 } else if (type == "reset" || in.eof()) {
172 // Do nothing on reset
173 }
174 }
175
176 std::cout << insertScenarios.str() << std::endl;
177 std::cout << insertMeasurements.str() << std::endl;
178 sendQuery(insertScenarios.str().c_str());
179 sendQuery(insertMeasurements.str().c_str());
180 }
181
185 ~LogToSQLiteWriter() { sqlite3_close(_db); }
186
187 private:
191 void createSchema() { sendQuery(schemaSQL); }
192
198 void sendQuery(const char *query) {
199 char *errMsg = nullptr;
200 auto returnCode = sqlite3_exec(_db, query, callback, nullptr, &errMsg);
201
202 if (returnCode != SQLITE_OK) {
203 AutoPasLog(ERROR, "SQL error: {}", errMsg);
204 sqlite3_free(errMsg);
205 }
206 }
207
208 private:
212 sqlite3 *_db;
213
217 static constexpr const char *schemaSQL = R"SQL(
218CREATE TABLE ScenarioRaw (
219 filename VARCHAR(1024) PRIMARY KEY,
220 avgParticlesPerCell FLOAT,
221 cutoff FLOAT,
222 domainSizeX FLOAT,
223 domainSizeY FLOAT,
224 domainSizeZ FLOAT,
225 maxParticlesPerCell INTEGER,
226 minParticlesPerCell INTEGER,
227 numCells INTEGER,
228 numEmptyCells INTEGER,
229 numHaloParticles INTEGER,
230 numParticles INTEGER,
231 particleSize INTEGER,
232 particleSizeNeededByFunctor INTEGER,
233 particlesPerBlurredCellStdDev FLOAT,
234 particlesPerCellStdDev FLOAT,
235 skin FLOAT,
236 threadCount INTEGER,
237 rebuildFrequency INTEGER,
238 estimatedNumNeighborInteractions INTEGER
239);
240CREATE TABLE MeasurementRaw (
241 scenario VARCHAR(1024),
242 container VARCHAR(64),
243 cellSizeFactor FLOAT,
244 traversal VARCHAR(64),
245 loadEstimator VARCHAR(64),
246 dataLayout VARCHAR(64),
247 newton3 VARCHAR(64),
248 iteration INTEGER,
249 nsRuntime BIGINT,
250 FOREIGN KEY (scenario) REFERENCES Scenario(filename),
251 PRIMARY KEY (
252 scenario,
253 container,
254 cellSizeFactor,
255 traversal,
256 loadEstimator,
257 dataLayout,
258 newton3
259 )
260);
261
262CREATE VIEW Scenario AS
263SELECT
264 *
265FROM
266 ScenarioRaw
267;
268
269CREATE VIEW Measurement AS
270SELECT
271 *
272FROM
273 MeasurementRaw
274;
275
276CREATE VIEW numDifferentConfigs AS
277SELECT
278 COUNT(*)
279FROM
280 (SELECT
281 1
282 FROM
283 Measurement
284 GROUP BY container, traversal, dataLayout, newton3, loadEstimator
285 )
286;
287
288CREATE VIEW bestConfigurations AS
289SELECT
290 container,
291 dataLayout,
292 newton3,
293 loadEstimator,
294 traversal,
295 MIN(nsRuntime) as nsMinRuntime,
296 scenario
297FROM
298 Measurement
299group by
300 scenario
301ORDER BY
302 container,
303 dataLayout,
304 newton3,
305 loadEstimator,
306 traversal
307 /* bestConfigurations(container,dataLayout,newton3,loadEstimator,traversal,nsMinRuntime,scenario) */
308;
309
310CREATE VIEW configWinners AS
311SELECT
312 container,
313 dataLayout,
314 newton3,
315 loadEstimator,
316 traversal,
317 COUNT(*) AS Wins
318FROM
319 bestConfigurations
320GROUP BY
321 container,
322 dataLayout,
323 newton3,
324 loadEstimator,
325 traversal
326ORDER BY
327 COUNT(*) DESC
328 /* configWinners(container,dataLayout,newton3,loadEstimator,traversal,Wins) */
329;
330
331CREATE VIEW measuredConfigs AS
332SELECT DISTINCT
333 container,
334 traversal,
335 dataLayout,
336 newton3,
337 loadEstimator
338FROM
339 Measurement;
340
341CREATE VIEW loserConfigs AS
342SELECT
343 container,
344 traversal,
345 dataLayout,
346 newton3,
347 loadEstimator
348FROM
349 measuredConfigs
350 NATURAL LEFT OUTER JOIN configWinners
351WHERE
352 Wins IS NULL
353;
354
355CREATE VIEW containerWinners AS
356SELECT
357 container,
358 SUM(Wins)
359FROM
360 configWinners
361GROUP BY
362 container
363ORDER BY
364 SUM(Wins) DESC
365 /* containerWinners(container,"SUM(Wins)") */
366;
367
368CREATE VIEW traversalWinners AS
369SELECT
370 traversal,
371 SUM(Wins)
372FROM
373 configWinners
374GROUP BY
375 traversal
376ORDER BY
377 SUM(Wins) DESC
378 /* traversalWinners(traversal, "SUM(Wins)") */
379;
380
381CREATE VIEW MeasurementWithRankInScenario AS
382SELECT
383 *,
384 RANK() OVER(
385 PARTITION BY scenario
386 ORDER BY
387 nsRuntime
388 ) AS rank
389FROM
390 Measurement
391ORDER BY
392 rank
393 /* MeasurementWithRankInScenario(scenario,container,cellSizeFactor,traversal,loadEstimator,dataLayout,newton3,iteration,nsRuntime,rank) */
394;
395
396CREATE VIEW MeasurementRankFactor AS
397SELECT
398 *,
399 RANK() OVER sameScenarioRuntimeOrdered AS rank,
400 CAST(nsRuntime AS DOUBLE) / MIN(nsRuntime) OVER sameScenarioRuntimeOrdered AS factorWorseThanBest
401FROM
402 Measurement WINDOW sameScenarioRuntimeOrdered AS (
403 PARTITION BY scenario
404 ORDER BY
405 nsRuntime
406 )
407ORDER BY
408 rank
409 /* MeasurementRankFactor(scenario,container,cellSizeFactor,traversal,loadEstimator,dataLayout,newton3,iteration,nsRuntime,rank,factorWorseThanBest) */
410;
411
412CREATE VIEW configRanks AS
413SELECT
414 container,
415 dataLayout,
416 newton3,
417 traversal,
418 loadEstimator,
419 MAX(rank) - MIN(rank) AS diffMinMaxRank,
420 MAX(rank) AS maxRank,
421 MIN(rank) AS minRank,
422 AVG(rank) AS avgRank,
423 MAX(factorWorseThanBest) / MIN(factorWorseThanBest) AS factorWorseToBestFactor,
424 MAX(factorWorseThanBest) AS maxFactorWorseThanBest,
425 MIN(factorWorseThanBest) AS minFactorWorseThanBest,
426 AVG(factorWorseThanBest) AS avgFactorWorseThanBest
427FROM
428 MeasurementRankFactor
429GROUP BY
430 container,
431 dataLayout,
432 newton3,
433 traversal,
434 loadEstimator
435 /* configRanks(container,dataLayout,newton3,traversal,loadEstimator,diffMinMaxRank,maxRank,minRank,avgRank) */
436;
437
438CREATE VIEW ScenarioTuningTime AS
439SELECT
440 scenario,
441 SUM(nsRuntime) AS nsTuningTime
442FROM
443 Measurement
444GROUP BY
445 scenario
446 /* ScenarioTuningTime(scenario,nsTuningTime) */
447;
448
449CREATE VIEW ScenarioWithDerived AS /* Replaces ScenarioTuningTime */
450SELECT
451 scenario,
452 SUM(nsRuntime) AS nsTuningTime,
453 MAX(rank) AS numConfigsMeasured,
454 MIN(nsRuntime) AS nsMinIterationTime,
455 SUM(nsRuntime) / CAST((MIN(nsRuntime) * MAX(rank)) AS DOUBLE) AS factorToOptimalRuntime
456FROM
457 MeasurementRankFactor
458GROUP BY
459 scenario
460ORDER BY
461 factorToOptimalRuntime
462 /* ScenarioTuningTime(scenario,nsTuningTime,numConfigsMeasured,factorToOptimalRuntime) */
463;
464
465CREATE VIEW MeasurementRankFactorTuningTime AS
466SELECT
467 *,
468 RANK() OVER sameScenarioRuntimeOrdered AS rank,
469 CAST(nsRuntime AS DOUBLE) / MIN(nsRuntime) OVER sameScenarioRuntimeOrdered AS factorWorseThanBest,
470 (
471 SUM(CAST(nsRuntime AS DOUBLE)) OVER sameScenarioRuntimeOrdered
472 ) / nsTuningTime AS percentTuningTimeUntil
473FROM
474 Measurement m
475 NATURAL JOIN ScenarioTuningTime WINDOW sameScenarioRuntimeOrdered AS (
476 PARTITION BY m.scenario
477 ORDER BY
478 nsRuntime
479 )
480ORDER BY
481 rank
482 /* MeasurementRankFactorTuningTime(scenario,container,cellSizeFactor,traversal,loadEstimator,dataLayout,newton3,iteration,nsRuntime,nsTuningTime,rank,factorWorseThanBest,percentTuningTimeUntil) */
483;
484
485CREATE VIEW PercentTuningTimePerRank AS
486SELECT
487 rank,
488 MIN(percentTuningTimeUntil) AS minPercent,
489 MAX(percentTuningTimeUntil) AS maxPercent,
490 AVG(percentTuningTimeUntil) AS avgPercent
491FROM
492 MeasurementRankFactorTuningTime
493WHERE
494 ( SELECT
495 numConfigsMeasured
496 FROM
497 ScenarioWithDerived s
498 WHERE
499 MeasurementRankFactorTuningTime.scenario = s.scenario
500 ) = (SELECT * FROM numDifferentConfigs)
501GROUP BY
502 rank
503ORDER BY
504 rank
505 /* PercentTuningTimePerRank(rank,minPercent,maxPercent,avgPercent) */
506;
507
508CREATE VIEW lastConfigsOfUnfinishedScenarios AS
509SELECT
510 *
511FROM
512 ScenarioWithDerived
513 NATURAL JOIN MeasurementRankFactor
514WHERE
515 numConfigsMeasured < (SELECT * FROM numDifferentConfigs)
516 AND numConfigsMeasured = rank
517;
518
519CREATE VIEW runtimeFactorBinning AS
520SELECT
521 CAST(maxFactorBin AS VARCHAR(10)) AS maxFactorBin,
522 numConfigsUntil - LAG(numConfigsUntil, 1, 0) OVER (ORDER BY maxFactorBin ASC) AS configsInBucket
523FROM (
524 SELECT
525 maxFactorBin,
526 COUNT(*) AS numConfigsUntil
527 FROM
528 MeasurementRankFactor,
529 (
530 SELECT
531 column1 AS maxFactorBin
532 FROM
533 (VALUES (1.0), (1.2), (1.5), (2), (3.5), (5), (7.5), (10), (15), (25), (50), (100), (250), (500), (1000), (2000), (1000000))
534 )
535 WHERE
536 factorWorseThanBest <= maxFactorBin
537 GROUP BY
538 maxFactorBin
539 )
540;
541
542CREATE VIEW uselessConfigsAndTheirSupercedingConfigs AS
543SELECT
544 worseConfig.container AS worseContainer,
545 worseConfig.traversal AS worseTraversal,
546 worseConfig.dataLayout AS worseDataLayout,
547 worseConfig.newton3 AS worseNewton3,
548 worseConfig.loadEstimator AS worseLoadEstimator,
549 betterConfig.container AS betterContainer,
550 betterConfig.traversal AS betterTraversal,
551 betterConfig.dataLayout AS betterDataLayout,
552 betterConfig.newton3 AS betterNewton3,
553 betterConfig.loadEstimator AS betterLoadEstimator
554FROM
555 measuredConfigs betterConfig, measuredConfigs worseConfig
556WHERE
557 NOT EXISTS (
558 SELECT
559 *
560 FROM
561 MeasurementRankFactor worse,
562 MeasurementRankFactor better
563 WHERE
564 worse.scenario = better.scenario
565
566 AND worse.container = worseConfig.container
567 AND worse.traversal = worseConfig.traversal
568 AND worse.loadEstimator = worseConfig.loadEstimator
569 AND worse.dataLayout = worseConfig.dataLayout
570 AND worse.newton3 = worseConfig.newton3
571
572 AND better.container = betterConfig.container
573 AND better.traversal = betterConfig.traversal
574 AND better.loadEstimator = betterConfig.loadEstimator
575 AND better.dataLayout = betterConfig.dataLayout
576 AND better.newton3 = betterConfig.newton3
577
578 AND worse.rank <= better.rank
579 )
580;
581
582)SQL";
583};
#define AutoPasLog(lvl, fmt,...)
Macro for logging providing common meta information without filename.
Definition: Logger.h:24
This class creates a SQLite3 database with a schema for tuning log entries, and offers methods to wri...
Definition: LogToSQLiteWriter.h:98
void write(const char *filename)
Write a file containing tuning log entries to the database.
Definition: LogToSQLiteWriter.h:120
LogToSQLiteWriter(const std::string &databaseName)
The constructor.
Definition: LogToSQLiteWriter.h:104
~LogToSQLiteWriter()
The destructor.
Definition: LogToSQLiteWriter.h:185
This class is able to gather and store important information for a tuning phase from a container and ...
Definition: LiveInfo.h:33
const auto & get() const
Returns a map of all infos.
Definition: LiveInfo.h:429
Contains some helpers to write and read the tuning log entries.
Definition: namespaces.h:97
std::string writeTune()
Writes a tune entry for the log file into a string.
Definition: TuningLogEntry.cpp:19
bool readTune(std::stringstream &str)
Reads the arguments of a tune entry from the stringstream.
Definition: TuningLogEntry.cpp:21
auto toString(const Payload &...payload)
Writes multiple arguments into a string using their << operator.
Definition: TuningLogEntry.h:35
std::string writeReset(size_t iteration)
Writes a reset entry in the log file to a string.
Definition: TuningLogEntry.cpp:23
size_t readReset(std::stringstream &str)
Reads the arguments of a reset entry in the log file from a string.
Definition: LogToSQLiteWriter.h:52
std::string writeLiveInfo(const autopas::LiveInfo &liveInfo)
Writes a liveInfo entry in the log file to a string.
Definition: TuningLogEntry.cpp:25
std::tuple< long, size_t, Configuration > readEvidence(std::stringstream &str)
Reads the arguments of an evidence entry in the log file from a stringstream.
Definition: TuningLogEntry.cpp:15
std::tuple< Payload... > fromString(std::stringstream &stream)
Reads multiple values from a stringstream using their >> operator.
Definition: TuningLogEntry.h:48
autopas::LiveInfo readLiveInfo(std::stringstream &str)
Reads the arguments of a live info entry in the log file from a stringstream.
Definition: TuningLogEntry.cpp:27
void toStringHelper(std::ostream &in, const T &val)
Writes the given argument into the given ostream with following white space.
Definition: TuningLogEntry.h:24
std::string writeEvidence(long time, size_t iteration, const autopas::Configuration &config)
Writes evidence to a string.
Definition: TuningLogEntry.cpp:11