souffle  2.0.2-371-g6315b36
Reader.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2016, The Souffle Developers. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 #pragma once
10 
16 #include "souffle/profile/Rule.h"
18 #include <cassert>
19 #include <chrono>
20 #include <cstdlib>
21 #include <ctime>
22 #include <fstream>
23 #include <iostream>
24 #include <memory>
25 #include <string>
26 #include <thread>
27 #include <unordered_map>
28 #include <utility>
29 #include <vector>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 
33 namespace souffle {
34 namespace profile {
35 
36 namespace {
37 template <typename T>
38 class DSNVisitor : public Visitor {
39 public:
40  DSNVisitor(T& base) : base(base) {}
41  void visit(TextEntry& text) override {
42  if (text.getKey() == "source-locator") {
43  base.setLocator(text.getText());
44  }
45  }
46  void visit(DurationEntry& duration) override {
47  if (duration.getKey() == "runtime") {
48  base.setStarttime(duration.getStart());
49  base.setEndtime(duration.getEnd());
50  }
51  }
52  void visit(SizeEntry& size) override {
53  if (size.getKey() == "num-tuples") {
54  base.setNumTuples(size.getSize());
55  }
56  }
57  void visit(DirectoryEntry& /* ruleEntry */) override {}
58 
59 protected:
60  T& base;
61 };
62 
63 /**
64  * Visit ProfileDB atom frequencies.
65  * atomrule : {atom: {num-tuples: num}}
66  */
67 class AtomFrequenciesVisitor : public Visitor {
68 public:
69  AtomFrequenciesVisitor(Rule& rule) : rule(rule) {}
70  void visit(DirectoryEntry& directory) override {
71  const std::string& clause = directory.getKey();
72 
73  for (auto& key : directory.getKeys()) {
74  auto* level = dynamic_cast<SizeEntry*>(directory.readDirectoryEntry(key)->readEntry("level"));
75  auto* frequency =
76  dynamic_cast<SizeEntry*>(directory.readDirectoryEntry(key)->readEntry("num-tuples"));
77  // Handle older logs
78  size_t intFreq = frequency == nullptr ? 0 : frequency->getSize();
79  size_t intLevel = level == nullptr ? 0 : level->getSize();
80  rule.addAtomFrequency(clause, key, intLevel, intFreq);
81  }
82  }
83 
84 private:
85  Rule& rule;
86 };
87 
88 /**
89  * Visit ProfileDB recursive rule.
90  * ruleversion: {DSN}
91  */
92 class RecursiveRuleVisitor : public DSNVisitor<Rule> {
93 public:
94  RecursiveRuleVisitor(Rule& rule) : DSNVisitor(rule) {}
95  void visit(DirectoryEntry& directory) override {
96  if (directory.getKey() == "atom-frequency") {
97  AtomFrequenciesVisitor atomFrequenciesVisitor(base);
98  for (auto& key : directory.getKeys()) {
99  directory.readDirectoryEntry(key)->accept(atomFrequenciesVisitor);
100  }
101  }
102  }
103 };
104 
105 /**
106  * Visit ProfileDB non-recursive rules.
107  * rule: {versionNum : {DSN}, versionNum+1: {DSN}}
108  */
109 class RecursiveRulesVisitor : public Visitor {
110 public:
111  RecursiveRulesVisitor(Iteration& iteration, Relation& relation)
113  void visit(DirectoryEntry& ruleEntry) override {
114  for (const auto& key : ruleEntry.getKeys()) {
115  auto& versions = *ruleEntry.readDirectoryEntry(key);
116  auto rule = std::make_shared<Rule>(
117  ruleEntry.getKey(), std::stoi(key), relation.createRecID(ruleEntry.getKey()));
118  RecursiveRuleVisitor visitor(*rule);
119  for (const auto& versionKey : versions.getKeys()) {
120  versions.readEntry(versionKey)->accept(visitor);
121  }
122  // To match map keys defined in Iteration::addRule()
123  std::string ruleKey = key + rule->getLocator() + key;
124  iteration.addRule(ruleKey, rule);
125  }
126  }
127 
128 protected:
129  Iteration& iteration;
130  Relation& relation;
131 };
132 
133 /**
134  * Visit ProfileDB non-recursive rule.
135  * rule: {DSN}
136  */
137 class NonRecursiveRuleVisitor : public DSNVisitor<Rule> {
138 public:
139  NonRecursiveRuleVisitor(Rule& rule) : DSNVisitor(rule) {}
140  void visit(DirectoryEntry& directory) override {
141  if (directory.getKey() == "atom-frequency") {
142  AtomFrequenciesVisitor atomFrequenciesVisitor(base);
143  for (auto& key : directory.getKeys()) {
144  directory.readDirectoryEntry(key)->accept(atomFrequenciesVisitor);
145  }
146  }
147  }
148 };
149 
150 /**
151  * Visit ProfileDB non-recursive rules.
152  * non-recursive-rule: {rule1: {DSN}, ...}
153  */
154 class NonRecursiveRulesVisitor : public Visitor {
155 public:
156  NonRecursiveRulesVisitor(Relation& relation) : relation(relation) {}
157  void visit(DirectoryEntry& ruleEntry) override {
158  auto rule = std::make_shared<Rule>(ruleEntry.getKey(), relation.createID());
159  NonRecursiveRuleVisitor visitor(*rule);
160  for (const auto& key : ruleEntry.getKeys()) {
161  ruleEntry.readEntry(key)->accept(visitor);
162  }
163  relation.addRule(rule);
164  }
165 
166 protected:
167  Relation& relation;
168 };
169 
170 /**
171  * Visit a ProfileDB relation iteration.
172  * iterationNumber: {DSN, recursive-rule: {}}
173  */
174 class IterationVisitor : public DSNVisitor<Iteration> {
175 public:
176  IterationVisitor(Iteration& iteration, Relation& relation) : DSNVisitor(iteration), relation(relation) {}
177  void visit(DurationEntry& duration) override {
178  if (duration.getKey() == "copytime") {
179  auto copytime = (duration.getEnd() - duration.getStart());
180  base.setCopytime(copytime);
181  }
182  DSNVisitor::visit(duration);
183  }
184  void visit(DirectoryEntry& directory) override {
185  if (directory.getKey() == "recursive-rule") {
186  RecursiveRulesVisitor rulesVisitor(base, relation);
187  for (const auto& key : directory.getKeys()) {
188  directory.readEntry(key)->accept(rulesVisitor);
189  }
190  }
191  if (directory.getKey() == "maxRSS") {
192  auto* preMaxRSS = dynamic_cast<SizeEntry*>(directory.readEntry("pre"));
193  auto* postMaxRSS = dynamic_cast<SizeEntry*>(directory.readEntry("post"));
194  relation.setPreMaxRSS(preMaxRSS->getSize());
195  relation.setPostMaxRSS(postMaxRSS->getSize());
196  }
197  }
198 
199 protected:
200  Relation& relation;
201 };
202 
203 /**
204  * Visit ProfileDB iterations.
205  * iteration: {num: {}, num2: {}, ...}
206  */
207 class IterationsVisitor : public Visitor {
208 public:
209  IterationsVisitor(Relation& relation) : relation(relation) {}
210  void visit(DirectoryEntry& ruleEntry) override {
211  auto iteration = std::make_shared<Iteration>();
212  relation.addIteration(iteration);
213  IterationVisitor visitor(*iteration, relation);
214  for (const auto& key : ruleEntry.getKeys()) {
215  ruleEntry.readEntry(key)->accept(visitor);
216  }
217  }
218 
219 protected:
220  Relation& relation;
221 };
222 
223 /**
224  * Visit ProfileDB relations.
225  * relname: {DSN, non-recursive-rule: {}, iteration: {...}}
226  */
227 class RelationVisitor : public DSNVisitor<Relation> {
228 public:
229  RelationVisitor(Relation& relation) : DSNVisitor(relation) {}
230  void visit(DurationEntry& duration) override {
231  if (duration.getKey() == "loadtime") {
232  auto loadtime = (duration.getEnd() - duration.getStart());
233  base.setLoadtime(loadtime);
234  } else if (duration.getKey() == "savetime") {
235  auto savetime = (duration.getEnd() - duration.getStart());
236  base.setSavetime(savetime);
237  }
238  DSNVisitor::visit(duration);
239  }
240  void visit(DirectoryEntry& directory) override {
241  if (directory.getKey() == "iteration") {
242  IterationsVisitor iterationsVisitor(base);
243  for (const auto& key : directory.getKeys()) {
244  directory.readEntry(key)->accept(iterationsVisitor);
245  }
246  } else if (directory.getKey() == "non-recursive-rule") {
247  NonRecursiveRulesVisitor rulesVisitor(base);
248  for (const auto& key : directory.getKeys()) {
249  directory.readEntry(key)->accept(rulesVisitor);
250  }
251  } else if (directory.getKey() == "maxRSS") {
252  auto* preMaxRSS = dynamic_cast<SizeEntry*>(directory.readEntry("pre"));
253  auto* postMaxRSS = dynamic_cast<SizeEntry*>(directory.readEntry("post"));
254  base.setPreMaxRSS(preMaxRSS->getSize());
255  base.setPostMaxRSS(postMaxRSS->getSize());
256  }
257  }
258  void visit(SizeEntry& size) override {
259  if (size.getKey() == "reads") {
260  base.addReads(size.getSize());
261  } else {
262  DSNVisitor::visit(size);
263  }
264  }
265 };
266 } // namespace
267 
268 /*
269  * Input reader and processor for log files
270  */
271 class Reader {
272 private:
273  std::string file_loc;
274  std::streampos gpos;
275  const ProfileDatabase& db = ProfileEventSingleton::instance().getDB();
276  bool loaded = false;
277  bool online{true};
278 
279  std::unordered_map<std::string, std::shared_ptr<Relation>> relationMap{};
280  int rel_id{0};
281 
282 public:
283  std::shared_ptr<ProgramRun> run;
284 
285  Reader(std::string filename, std::shared_ptr<ProgramRun> run)
286  : file_loc(std::move(filename)), run(std::move(run)) {
287  try {
289  } catch (const std::exception& e) {
290  fatal("exception whilst reading profile DB: %s", e.what());
291  }
292  }
293 
294  Reader(std::shared_ptr<ProgramRun> run) : run(std::move(run)) {}
295  /**
296  * Read the contents from file into the class
297  */
298  void processFile() {
299  rel_id = 0;
300  relationMap.clear();
301  auto programDuration = dynamic_cast<DurationEntry*>(db.lookupEntry({"program", "runtime"}));
302  if (programDuration == nullptr) {
303  auto startTimeEntry = dynamic_cast<TimeEntry*>(db.lookupEntry({"program", "starttime"}));
304  if (startTimeEntry != nullptr) {
305  run->setStarttime(startTimeEntry->getTime());
306  run->setEndtime(std::chrono::duration_cast<microseconds>(now().time_since_epoch()));
307  }
308  } else {
309  run->setStarttime(programDuration->getStart());
310  run->setEndtime(programDuration->getEnd());
311  online = false;
312  }
313 
314  auto relations = dynamic_cast<DirectoryEntry*>(db.lookupEntry({"program", "relation"}));
315  if (relations == nullptr) {
316  // Souffle hasn't generated any profiling information yet.
317  return;
318  }
319  for (const auto& cur : relations->getKeys()) {
320  auto relation = dynamic_cast<DirectoryEntry*>(db.lookupEntry({"program", "relation", cur}));
321  if (relation != nullptr) {
323  }
324  }
325  for (const auto& relation : relationMap) {
326  for (const auto& rule : relation.second->getRuleMap()) {
327  for (const auto& atom : rule.second->getAtoms()) {
328  std::string relationName = extractRelationNameFromAtom(atom);
329  relationMap[relationName]->addReads(atom.frequency);
330  }
331  }
332  for (const auto& iteration : relation.second->getIterations()) {
333  for (const auto& rule : iteration->getRules()) {
334  for (const auto& atom : rule.second->getAtoms()) {
335  std::string relationName = extractRelationNameFromAtom(atom);
336  if (relationName.substr(0, 6) == "@delta") {
337  relationName = relationName.substr(7);
338  }
339  assert(relationMap.count(relationName) > 0 || "Relation name for atom not found");
340  relationMap[relationName]->addReads(atom.frequency);
341  }
342  }
343  }
344  }
345  run->setRelationMap(this->relationMap);
346  loaded = true;
347  }
348 
349  void save(std::string f_name);
350 
351  inline bool isLive() {
352  return online;
353  }
354 
355  void addRelation(const DirectoryEntry& relation) {
356  const std::string& name = cleanRelationName(relation.getKey());
357 
358  relationMap.emplace(name, std::make_shared<Relation>(name, createId()));
359  auto& rel = *relationMap[name];
360  RelationVisitor relationVisitor(rel);
361 
362  for (const auto& key : relation.getKeys()) {
363  relation.readEntry(key)->accept(relationVisitor);
364  }
365  }
366 
367  inline bool isLoaded() {
368  return loaded;
369  }
370 
371  std::string RelationcreateId() {
372  return "R" + std::to_string(++rel_id);
373  }
374 
375  std::string createId() {
376  return "R" + std::to_string(++rel_id);
377  }
378 
379 protected:
380  std::string cleanRelationName(const std::string& relationName) {
381  std::string cleanName = relationName;
382  for (auto& cur : cleanName) {
383  if (cur == '-') {
384  cur = '.';
385  }
386  }
387  return cleanName;
388  }
389  std::string extractRelationNameFromAtom(const Atom& atom) {
390  return cleanRelationName(atom.identifier.substr(0, atom.identifier.find('(')));
391  }
392 };
393 
394 } // namespace profile
395 } // namespace souffle
souffle::profile::Reader::online
bool online
Definition: Reader.h:277
TCB_SPAN_NAMESPACE_NAME::detail::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.h:198
souffle::profile::Reader::RelationcreateId
std::string RelationcreateId()
Definition: Reader.h:371
souffle::profile::Reader::cleanRelationName
std::string cleanRelationName(const std::string &relationName)
Definition: Reader.h:380
souffle::ProfileEventSingleton::instance
static ProfileEventSingleton & instance()
get instance
Definition: ProfileEvent.h:70
e
l j a showGridBackground &&c b raw series this eventEmitter e
Definition: htmlJsChartistMin.h:15
souffle::profile::Reader::save
void save(std::string f_name)
relation
Relation & relation
Definition: Reader.h:130
souffle::profile::Reader::Reader
Reader(std::shared_ptr< ProgramRun > run)
Definition: Reader.h:294
souffle::profile::Reader::isLive
bool isLive()
Definition: Reader.h:351
base
T & base
Definition: Reader.h:60
relations
std::vector< Own< Relation > > relations
Definition: ComponentInstantiation.cpp:65
iteration
Iteration & iteration
Definition: Reader.h:129
ProfileEvent.h
souffle::profile::Reader::loaded
bool loaded
Definition: Reader.h:276
ProgramRun.h
souffle::profile::Reader::createId
std::string createId()
Definition: Reader.h:375
souffle::profile::Reader::extractRelationNameFromAtom
std::string extractRelationNameFromAtom(const Atom &atom)
Definition: Reader.h:389
souffle::profile::Reader
Definition: Reader.h:271
souffle::now
time_point now()
Definition: MiscUtil.h:89
souffle::profile::Reader::rel_id
int rel_id
Definition: Reader.h:280
Iteration.h
souffle::profile::Atom
Definition: Rule.h:24
souffle::profile::Reader::file_loc
std::string file_loc
Definition: Reader.h:273
souffle::profile::Reader::addRelation
void addRelation(const DirectoryEntry &relation)
Definition: Reader.h:355
souffle::profile::Reader::db
const ProfileDatabase & db
Definition: Reader.h:275
souffle::test::duration
long duration(const time_point &start, const time_point &end)
Definition: btree_multiset_test.cpp:406
StringUtils.h
std
Definition: Brie.h:3053
souffle::profile::Reader::processFile
void processFile()
Read the contents from file into the class.
Definition: Reader.h:298
Rule.h
rule
Rule & rule
Definition: Reader.h:85
souffle::profile::Atom::identifier
const std::string identifier
Definition: Rule.h:26
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
souffle::ProfileEventSingleton::setDBFromFile
void setDBFromFile(const std::string &databaseFilename)
Definition: ProfileEvent.h:172
souffle
Definition: AggregateOp.h:25
ProfileDatabase.h
souffle::ProfileEventSingleton::getDB
const profile::ProfileDatabase & getDB() const
Definition: ProfileEvent.h:168
souffle::profile::Reader::gpos
std::streampos gpos
Definition: Reader.h:274
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::profile::Reader::isLoaded
bool isLoaded()
Definition: Reader.h:367
souffle::profile::Reader::run
std::shared_ptr< ProgramRun > run
Definition: Reader.h:283
Relation.h
souffle::profile::Reader::Reader
Reader(std::string filename, std::shared_ptr< ProgramRun > run)
Definition: Reader.h:285
souffle::profile::Reader::relationMap
std::unordered_map< std::string, std::shared_ptr< Relation > > relationMap
Definition: Reader.h:279