35 virtual ~Visitor() =
default;
38 virtual void visit(DirectoryEntry&
e);
41 virtual void visit(DurationEntry&) {}
42 virtual void visit(SizeEntry&) {}
43 virtual void visit(TextEntry&) {}
44 virtual void visit(TimeEntry&) {}
58 Entry(std::string key) : key(
std::move(key)) {}
59 virtual ~
Entry() =
default;
62 const std::string& getKey()
const {
67 virtual void accept(Visitor& v) = 0;
70 virtual void print(std::ostream& os,
int tabpos)
const = 0;
76 class DirectoryEntry :
public Entry {
78 std::map<std::string, Own<Entry>> entries;
79 mutable std::mutex lock;
82 DirectoryEntry(
const std::string& name) :
Entry(name) {}
85 const std::set<std::string> getKeys()
const {
86 std::set<std::string> result;
87 std::lock_guard<std::mutex> guard(lock);
88 for (
auto const& cur : entries) {
89 result.insert(cur.first);
95 Entry* writeEntry(Own<Entry> entry) {
96 assert(entry !=
nullptr &&
"null entry");
97 std::lock_guard<std::mutex> guard(lock);
98 const std::string& keyToWrite = entry->getKey();
100 if (entries.count(keyToWrite) == 0) {
101 entries[keyToWrite] = std::move(entry);
103 return entries[keyToWrite].get();
107 Entry* readEntry(
const std::string& keyToRead)
const {
108 std::lock_guard<std::mutex> guard(lock);
109 auto it = entries.find(keyToRead);
110 if (it != entries.end()) {
111 return (*it).second.get();
118 DirectoryEntry* readDirectoryEntry(
const std::string& keyToRead)
const {
119 return dynamic_cast<DirectoryEntry*
>(readEntry(keyToRead));
123 void accept(Visitor& v)
override {
128 void print(std::ostream& os,
int tabpos)
const override {
129 os << std::string(tabpos,
' ') <<
'"' << getKey() <<
"\": {" << std::endl;
131 for (
auto const& cur : entries) {
133 os <<
',' << std::endl;
137 cur.second->print(os, tabpos + 1);
139 os << std::endl << std::string(tabpos,
' ') <<
'}';
146 class SizeEntry :
public Entry {
153 size_t getSize()
const {
158 void accept(Visitor& v)
override {
163 void print(std::ostream& os,
int tabpos)
const override {
164 os << std::string(tabpos,
' ') <<
"\"" << getKey() <<
"\": " <<
size;
171 class TextEntry :
public Entry {
177 TextEntry(
const std::string& key, std::string text) :
Entry(key), text(
std::move(text)) {}
180 const std::string& getText()
const {
185 void accept(Visitor& v)
override {
190 void print(std::ostream& os,
int tabpos)
const override {
191 os << std::string(tabpos,
' ') <<
"\"" << getKey() <<
"\": \"" << text <<
"\"";
198 class DurationEntry :
public Entry {
207 DurationEntry(
const std::string& key, microseconds start, microseconds end)
208 :
Entry(key), start(start), end(end) {}
211 microseconds getStart()
const {
216 microseconds getEnd()
const {
221 void accept(Visitor& v)
override {
226 void print(std::ostream& os,
int tabpos)
const override {
227 os << std::string(tabpos,
' ') <<
'"' << getKey();
228 os << R
"_(": { "start": )_";
239 class TimeEntry :
public Entry {
248 microseconds getTime()
const {
253 void accept(Visitor& v)
override {
258 void print(std::ostream& os,
int tabpos)
const override {
259 os << std::string(tabpos,
' ') <<
'"' << getKey();
260 os << R
"_(": { "time": )_";
266 inline void Visitor::visit(DirectoryEntry&
e) {
267 std::cout <<
"Dir " <<
e.getKey() <<
"\n";
268 for (
const auto& cur :
e.getKeys()) {
269 std::cout <<
"\t :" << cur <<
"\n";
270 e.readEntry(cur)->accept(*
this);
274 class Counter :
public Visitor {
280 Counter(std::string key) : key(
std::move(key)) {}
281 void visit(SizeEntry&
e)
override {
282 std::cout <<
"Size entry : " <<
e.getKey() <<
" " <<
e.getSize() <<
"\n";
283 if (
e.getKey() == key) {
287 size_t getCounter()
const {
295 class ProfileDatabase {
297 Own<DirectoryEntry> root;
303 DirectoryEntry* lookupPath(
const std::vector<std::string>& path) {
304 DirectoryEntry* dir = root.get();
305 for (
const std::string& key : path) {
306 assert(!key.empty() &&
"Key is empty!");
307 DirectoryEntry* newDir = dir->readDirectoryEntry(key);
308 if (newDir ==
nullptr) {
309 newDir =
dynamic_cast<DirectoryEntry*
>(dir->writeEntry(mk<DirectoryEntry>(key)));
311 assert(newDir !=
nullptr &&
"Attempting to overwrite an existing entry");
317 void parseJson(
const json11::Json& json, Own<DirectoryEntry>& node) {
319 if (cur.second.is_object()) {
322 if (cur.second.has_shape(
323 {{
"start", json11::Json::NUMBER}, {
"end", json11::Json::NUMBER}},
err)) {
324 auto start = std::chrono::microseconds(cur.second[
"start"].long_value());
325 auto end = std::chrono::microseconds(cur.second[
"end"].long_value());
326 node->writeEntry(mk<DurationEntry>(cur.first, start, end));
327 }
else if (cur.second.has_shape({{
"time", json11::Json::NUMBER}},
err)) {
328 auto time = std::chrono::microseconds(cur.second[
"time"].long_value());
329 node->writeEntry(mk<TimeEntry>(cur.first,
time));
331 auto dir = mk<DirectoryEntry>(cur.first);
332 parseJson(cur.second, dir);
333 node->writeEntry(std::move(dir));
335 }
else if (cur.second.is_string()) {
336 node->writeEntry(mk<TextEntry>(cur.first, cur.second.string_value()));
337 }
else if (cur.second.is_number()) {
338 node->writeEntry(mk<SizeEntry>(cur.first, cur.second.long_value()));
341 cur.second.dump(
err);
342 std::cerr <<
"Unknown types in profile log: " << cur.first <<
": " <<
err << std::endl;
348 ProfileDatabase() : root(
mk<DirectoryEntry>(
"root")) {}
350 ProfileDatabase(
const std::string& filename) : root(
mk<DirectoryEntry>(
"root")) {
351 std::ifstream file(filename);
352 if (!file.is_open()) {
353 throw std::runtime_error(
"Log file could not be opened.");
355 std::string jsonString((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
358 if (!error.empty()) {
359 throw std::runtime_error(
"Parse error: " + error);
361 parseJson(json[
"root"], root);
365 void addSizeEntry(std::vector<std::string> qualifier,
size_t size) {
366 assert(qualifier.size() > 0 &&
"no qualifier");
367 std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
368 DirectoryEntry* dir = lookupPath(path);
370 const std::string& key = qualifier.back();
371 Own<SizeEntry> entry = mk<SizeEntry>(key,
size);
372 dir->writeEntry(std::move(entry));
376 void addTextEntry(std::vector<std::string> qualifier,
const std::string& text) {
377 assert(qualifier.size() > 0 &&
"no qualifier");
378 std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
379 DirectoryEntry* dir = lookupPath(path);
381 const std::string& key = qualifier.back();
382 Own<TextEntry> entry = std::make_unique<TextEntry>(key, text);
383 dir->writeEntry(std::move(entry));
387 void addDurationEntry(std::vector<std::string> qualifier, microseconds start, microseconds end) {
388 assert(qualifier.size() > 0 &&
"no qualifier");
389 std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
390 DirectoryEntry* dir = lookupPath(path);
392 const std::string& key = qualifier.back();
393 Own<DurationEntry> entry = std::make_unique<DurationEntry>(key, start, end);
394 dir->writeEntry(std::move(entry));
398 void addTimeEntry(std::vector<std::string> qualifier, microseconds
time) {
399 assert(qualifier.size() > 0 &&
"no qualifier");
400 std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
401 DirectoryEntry* dir = lookupPath(path);
403 const std::string& key = qualifier.back();
404 Own<TimeEntry> entry = std::make_unique<TimeEntry>(key,
time);
405 dir->writeEntry(std::move(entry));
409 size_t computeSum(
const std::vector<std::string>& qualifier) {
410 assert(qualifier.size() > 0 &&
"no qualifier");
411 std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
412 DirectoryEntry* dir = lookupPath(path);
414 const std::string& key = qualifier.back();
415 std::cout <<
"Key: " << key << std::endl;
418 return ctr.getCounter();
424 Entry* lookupEntry(
const std::vector<std::string>& path)
const {
425 DirectoryEntry* dir = root.get();
426 auto last = --path.end();
427 for (
auto it = path.begin(); it != last; ++it) {
428 dir = dir->readDirectoryEntry(*it);
429 if (dir ==
nullptr) {
433 return dir->readEntry(*last);
439 std::map<std::string, std::string> getStringMap(
const std::vector<std::string>& path)
const {
440 std::map<std::string, std::string> kvps;
441 auto* parent =
dynamic_cast<DirectoryEntry*
>(lookupEntry(path));
442 if (parent ==
nullptr) {
446 for (
const auto& key : parent->getKeys()) {
447 auto* text =
dynamic_cast<TextEntry*
>(parent->readEntry(key));
448 if (text !=
nullptr) {
449 kvps[key] = text->getText();
457 void print(std::ostream& os)
const {
458 os <<
'{' << std::endl;
460 os << std::endl <<
'}' << std::endl;