| 1 | /*
|
| 2 | * Souffle - A Datalog Compiler
|
| 3 | * Copyright (c) 2018, 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 | /************************************************************************
|
| 10 | *
|
| 11 | * @file EventProcessor.h
|
| 12 | *
|
| 13 | * Declares classes for event processor that parse profile events and
|
| 14 | * populate the profile database
|
| 15 | *
|
| 16 | ***********************************************************************/
|
| 17 |
|
| 18 | #pragma once
|
| 19 |
|
| 20 | #include "souffle/profile/ProfileDatabase.h"
|
| 21 | #include "souffle/utility/MiscUtil.h"
|
| 22 | #include "souffle/utility/StreamUtil.h"
|
| 23 | #include <cassert>
|
| 24 | #include <chrono>
|
| 25 | #include <cstdarg>
|
| 26 | #include <cstdint>
|
| 27 | #include <cstdlib>
|
| 28 | #include <iostream>
|
| 29 | #include <map>
|
| 30 | #include <string>
|
| 31 | #include <vector>
|
| 32 |
|
| 33 | namespace souffle {
|
| 34 | namespace profile {
|
| 35 | /**
|
| 36 | * Abstract Class for EventProcessor
|
| 37 | */
|
| 38 | class EventProcessor {
|
| 39 | public:
|
| 40 | virtual ~EventProcessor() = default;
|
| 41 |
|
| 42 | /** abstract interface for processing an profile event */
|
| 43 | virtual void process(ProfileDatabase&, const std::vector<std::string>& signature, va_list&) {
|
| 44 | fatal("Unknown profiling processing event: %s", join(signature, " "));
|
| 45 | }
|
| 46 | };
|
| 47 |
|
| 48 | /**
|
| 49 | * Event Processor Singleton
|
| 50 | *
|
| 51 | * Singleton that is the connection point for events
|
| 52 | */
|
| 53 | class EventProcessorSingleton {
|
| 54 | public:
|
| 55 | /** get instance */
|
| 56 | static EventProcessorSingleton& instance() {
|
| 57 | static EventProcessorSingleton singleton;
|
| 58 | return singleton;
|
| 59 | }
|
| 60 |
|
| 61 | /** register an event processor with its keyword */
|
| 62 | void registerEventProcessor(const std::string& keyword, EventProcessor* processor) {
|
| 63 | registry[keyword] = processor;
|
| 64 | }
|
| 65 |
|
| 66 | /** process a profile event */
|
| 67 | void process(ProfileDatabase& db, const char* txt, ...) {
|
| 68 | va_list args;
|
| 69 | va_start(args, txt);
|
| 70 |
|
| 71 | // escape signature
|
| 72 | std::string escapedText = escape(txt);
|
| 73 | // obtain event signature by splitting event text
|
| 74 | std::vector<std::string> eventSignature = splitSignature(escapedText);
|
| 75 |
|
| 76 | // invoke the event processor of the event
|
| 77 | const std::string& keyword = eventSignature[0];
|
| 78 | assert(eventSignature.size() > 0 && "no keyword in event description");
|
| 79 | assert(registry.find(keyword) != registry.end() && "EventProcessor not found!");
|
| 80 | registry[keyword]->process(db, eventSignature, args);
|
| 81 |
|
| 82 | // terminate access to variadic arguments
|
| 83 | va_end(args);
|
| 84 | }
|
| 85 |
|
| 86 | private:
|
| 87 | /** keyword / event processor mapping */
|
| 88 | std::map<std::string, EventProcessor*> registry;
|
| 89 |
|
| 90 | EventProcessorSingleton() = default;
|
| 91 |
|
| 92 | /**
|
| 93 | * Escape escape characters.
|
| 94 | *
|
| 95 | * Remove all escapes, then escape double quotes.
|
| 96 | */
|
| 97 | std::string escape(const std::string& text) {
|
| 98 | std::string str(text);
|
| 99 | std::size_t start_pos = 0;
|
| 100 | // replace backslashes with double backslash
|
| 101 | while ((start_pos = str.find('\\', start_pos)) != std::string::npos) {
|
| 102 | if (start_pos == str.size()) {
|
| 103 | break;
|
| 104 | }
|
| 105 | ++start_pos;
|
| 106 | if (str[start_pos] != 't' && str[start_pos] != '"' && str[start_pos] != '\\' &&
|
| 107 | str[start_pos] != 'n' && str[start_pos] != ';') {
|
| 108 | str.replace(start_pos - 1, 1, "\\\\");
|
| 109 | }
|
| 110 | ++start_pos;
|
| 111 | }
|
| 112 | return str;
|
| 113 | }
|
| 114 |
|
| 115 | /** split string */
|
| 116 | static std::vector<std::string> split(std::string str, std::string split_str) {
|
| 117 | // repeat value when splitting so "a b" -> ["a","b"] not ["a","","","","b"]
|
| 118 | bool repeat = (split_str == " ");
|
| 119 |
|
| 120 | std::vector<std::string> elems;
|
| 121 |
|
| 122 | std::string temp;
|
| 123 | std::string hold;
|
| 124 | for (std::size_t i = 0; i < str.size(); i++) {
|
| 125 | if (repeat) {
|
| 126 | if (str.at(i) == split_str.at(0)) {
|
| 127 | while (str.at(++i) == split_str.at(0)) {
|
| 128 | ; // set i to be at the end of the search string
|
| 129 | }
|
| 130 | elems.push_back(temp);
|
| 131 | temp = "";
|
| 132 | }
|
| 133 | temp += str.at(i);
|
| 134 | } else {
|
| 135 | temp += str.at(i);
|
| 136 | hold += str.at(i);
|
| 137 | for (std::size_t j = 0; j < hold.size(); j++) {
|
| 138 | if (hold[j] != split_str[j]) {
|
| 139 | hold = "";
|
| 140 | }
|
| 141 | }
|
| 142 | if (hold.size() == split_str.size()) {
|
| 143 | elems.push_back(temp.substr(0, temp.size() - hold.size()));
|
| 144 | hold = "";
|
| 145 | temp = "";
|
| 146 | }
|
| 147 | }
|
| 148 | }
|
| 149 | if (!temp.empty()) {
|
| 150 | elems.push_back(temp);
|
| 151 | }
|
| 152 |
|
| 153 | return elems;
|
| 154 | }
|
| 155 |
|
| 156 | /** split string separated by semi-colon */
|
| 157 | static std::vector<std::string> splitSignature(std::string str) {
|
| 158 | for (std::size_t i = 0; i < str.size(); i++) {
|
| 159 | if (i > 0 && str[i] == ';' && str[i - 1] == '\\') {
|
| 160 | // I'm assuming this isn't a thing that will be naturally found in souffle profiler files
|
| 161 | str[i - 1] = '\b';
|
| 162 | str.erase(i--, 1);
|
| 163 | }
|
| 164 | }
|
| 165 | std::vector<std::string> result = split(str, ";");
|
| 166 | for (auto& i : result) {
|
| 167 | for (char& j : i) {
|
| 168 | if (j == '\b') {
|
| 169 | j = ';';
|
| 170 | }
|
| 171 | }
|
| 172 | }
|
| 173 | return result;
|
| 174 | }
|
| 175 | };
|
| 176 |
|
| 177 | /**
|
| 178 | * Non-Recursive Rule Timing Profile Event Processor
|
| 179 | */
|
| 180 | const class NonRecursiveRuleTimingProcessor : public EventProcessor {
|
| 181 | public:
|
| 182 | NonRecursiveRuleTimingProcessor() {
|
| 183 | EventProcessorSingleton::instance().registerEventProcessor("@t-nonrecursive-rule", this);
|
| 184 | }
|
| 185 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 186 | const std::string& relation = signature[1];
|
| 187 | const std::string& srcLocator = signature[2];
|
| 188 | const std::string& rule = signature[3];
|
| 189 | microseconds start = va_arg(args, microseconds);
|
| 190 | microseconds end = va_arg(args, microseconds);
|
| 191 | std::size_t startMaxRSS = va_arg(args, std::size_t);
|
| 192 | std::size_t endMaxRSS = va_arg(args, std::size_t);
|
| 193 | std::size_t size = va_arg(args, std::size_t);
|
| 194 | db.addSizeEntry(
|
| 195 | {"program", "relation", relation, "non-recursive-rule", rule, "maxRSS", "pre"}, startMaxRSS);
|
| 196 | db.addSizeEntry(
|
| 197 | {"program", "relation", relation, "non-recursive-rule", rule, "maxRSS", "post"}, endMaxRSS);
|
| 198 | db.addTextEntry(
|
| 199 | {"program", "relation", relation, "non-recursive-rule", rule, "source-locator"}, srcLocator);
|
| 200 | db.addDurationEntry(
|
| 201 | {"program", "relation", relation, "non-recursive-rule", rule, "runtime"}, start, end);
|
| 202 | db.addSizeEntry({"program", "relation", relation, "non-recursive-rule", rule, "num-tuples"}, size);
|
| 203 | }
|
| 204 | } nonRecursiveRuleTimingProcessor;
|
| 205 |
|
| 206 | /**
|
| 207 | * Non-Recursive Rule Number Profile Event Processor
|
| 208 | */
|
| 209 | const class NonRecursiveRuleNumberProcessor : public EventProcessor {
|
| 210 | public:
|
| 211 | NonRecursiveRuleNumberProcessor() {
|
| 212 | EventProcessorSingleton::instance().registerEventProcessor("@n-nonrecursive-rule", this);
|
| 213 | }
|
| 214 | /** process event input */
|
| 215 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 216 | const std::string& relation = signature[1];
|
| 217 | const std::string& srcLocator = signature[2];
|
| 218 | const std::string& rule = signature[3];
|
| 219 | std::size_t num = va_arg(args, std::size_t);
|
| 220 | db.addTextEntry(
|
| 221 | {"program", "relation", relation, "non-recursive-rule", rule, "source-locator"}, srcLocator);
|
| 222 | db.addSizeEntry({"program", "relation", relation, "non-recursive-rule", rule, "num-tuples"}, num);
|
| 223 | }
|
| 224 | } nonRecursiveRuleNumberProcessor;
|
| 225 |
|
| 226 | /**
|
| 227 | * Non-Recursive Estimate Join Size Profile Event Processor
|
| 228 | */
|
| 229 | const class NonRecursiveEstimateJoinSizeProcessor : public EventProcessor {
|
| 230 | public:
|
| 231 | NonRecursiveEstimateJoinSizeProcessor() {
|
| 232 | EventProcessorSingleton::instance().registerEventProcessor("@non-recursive-estimate-join-size", this);
|
| 233 | }
|
| 234 | /** process event input */
|
| 235 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 236 | const std::string& relation = signature[1];
|
| 237 | const std::string& attributes = signature[2];
|
| 238 | const std::string& constants = signature[3];
|
| 239 | std::string joinSize = std::to_string(va_arg(args, double));
|
| 240 | db.addTextEntry({"program", "statistics", "relation", relation, "attributes", attributes, "constants",
|
| 241 | constants},
|
| 242 | joinSize);
|
| 243 | }
|
| 244 | } nonRecursiveEstimateJoinSizeProcessor;
|
| 245 |
|
| 246 | /**
|
| 247 | * Recursive Estimate Join Size Profile Event Processor
|
| 248 | */
|
| 249 | const class RecursiveEstimateJoinSizeProcessor : public EventProcessor {
|
| 250 | public:
|
| 251 | RecursiveEstimateJoinSizeProcessor() {
|
| 252 | EventProcessorSingleton::instance().registerEventProcessor("@recursive-estimate-join-size", this);
|
| 253 | }
|
| 254 | /** process event input */
|
| 255 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 256 | const std::string& relation = signature[1];
|
| 257 | const std::string& attributes = signature[2];
|
| 258 | const std::string& constants = signature[3];
|
| 259 | std::string joinSize = std::to_string(va_arg(args, double));
|
| 260 | std::string iteration = std::to_string(va_arg(args, std::size_t));
|
| 261 | db.addTextEntry({"program", "statistics", "relation", relation, "iteration", iteration, "attributes",
|
| 262 | attributes, "constants", constants},
|
| 263 | joinSize);
|
| 264 | }
|
| 265 | } recursiveEstimateJoinSizeProcessor;
|
| 266 |
|
| 267 | /**
|
| 268 | * Recursive Rule Timing Profile Event Processor
|
| 269 | */
|
| 270 | const class RecursiveRuleTimingProcessor : public EventProcessor {
|
| 271 | public:
|
| 272 | RecursiveRuleTimingProcessor() {
|
| 273 | EventProcessorSingleton::instance().registerEventProcessor("@t-recursive-rule", this);
|
| 274 | }
|
| 275 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 276 | const std::string& relation = signature[1];
|
| 277 | const std::string& version = signature[2];
|
| 278 | const std::string& srcLocator = signature[3];
|
| 279 | const std::string& rule = signature[4];
|
| 280 | microseconds start = va_arg(args, microseconds);
|
| 281 | microseconds end = va_arg(args, microseconds);
|
| 282 | std::size_t startMaxRSS = va_arg(args, std::size_t);
|
| 283 | std::size_t endMaxRSS = va_arg(args, std::size_t);
|
| 284 | std::size_t size = va_arg(args, std::size_t);
|
| 285 | std::string iteration = std::to_string(va_arg(args, std::size_t));
|
| 286 | db.addSizeEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 287 | version, "maxRSS", "pre"},
|
| 288 | startMaxRSS);
|
| 289 | db.addSizeEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 290 | version, "maxRSS", "post"},
|
| 291 | endMaxRSS);
|
| 292 | db.addTextEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 293 | version, "source-locator"},
|
| 294 | srcLocator);
|
| 295 | db.addDurationEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 296 | version, "runtime"},
|
| 297 | start, end);
|
| 298 | db.addSizeEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 299 | version, "num-tuples"},
|
| 300 | size);
|
| 301 | }
|
| 302 | } recursiveRuleTimingProcessor;
|
| 303 |
|
| 304 | /**
|
| 305 | * Recursive Rule Number Profile Event Processor
|
| 306 | */
|
| 307 | const class RecursiveRuleNumberProcessor : public EventProcessor {
|
| 308 | public:
|
| 309 | RecursiveRuleNumberProcessor() {
|
| 310 | EventProcessorSingleton::instance().registerEventProcessor("@n-recursive-rule", this);
|
| 311 | }
|
| 312 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 313 | const std::string& relation = signature[1];
|
| 314 | const std::string& version = signature[2];
|
| 315 | const std::string& srcLocator = signature[3];
|
| 316 | const std::string& rule = signature[4];
|
| 317 | std::size_t number = va_arg(args, std::size_t);
|
| 318 | std::string iteration = std::to_string(va_arg(args, std::size_t));
|
| 319 | db.addTextEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 320 | version, "source-locator"},
|
| 321 | srcLocator);
|
| 322 | db.addSizeEntry({"program", "relation", relation, "iteration", iteration, "recursive-rule", rule,
|
| 323 | version, "num-tuples"},
|
| 324 | number);
|
| 325 | }
|
| 326 | } recursiveRuleNumberProcessor;
|
| 327 |
|
| 328 | /**
|
| 329 | * Non-Recursive Relation Number Profile Event Processor
|
| 330 | */
|
| 331 | const class NonRecursiveRelationTimingProcessor : public EventProcessor {
|
| 332 | public:
|
| 333 | NonRecursiveRelationTimingProcessor() {
|
| 334 | EventProcessorSingleton::instance().registerEventProcessor("@t-nonrecursive-relation", this);
|
| 335 | }
|
| 336 | /** process event input */
|
| 337 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 338 | const std::string& relation = signature[1];
|
| 339 | const std::string& srcLocator = signature[2];
|
| 340 | microseconds start = va_arg(args, microseconds);
|
| 341 | microseconds end = va_arg(args, microseconds);
|
| 342 | std::size_t startMaxRSS = va_arg(args, std::size_t);
|
| 343 | std::size_t endMaxRSS = va_arg(args, std::size_t);
|
| 344 | std::size_t size = va_arg(args, std::size_t);
|
| 345 | db.addSizeEntry({"program", "relation", relation, "maxRSS", "pre"}, startMaxRSS);
|
| 346 | db.addSizeEntry({"program", "relation", relation, "maxRSS", "post"}, endMaxRSS);
|
| 347 | db.addSizeEntry({"program", "relation", relation, "num-tuples"}, size);
|
| 348 | db.addTextEntry({"program", "relation", relation, "source-locator"}, srcLocator);
|
| 349 | db.addDurationEntry({"program", "relation", relation, "runtime"}, start, end);
|
| 350 | }
|
| 351 | } nonRecursiveRelationTimingProcessor;
|
| 352 |
|
| 353 | /**
|
| 354 | * Non-Recursive Relation Number Profile Event Processor
|
| 355 | */
|
| 356 | const class NonRecursiveRelationNumberProcessor : public EventProcessor {
|
| 357 | public:
|
| 358 | NonRecursiveRelationNumberProcessor() {
|
| 359 | EventProcessorSingleton::instance().registerEventProcessor("@n-nonrecursive-relation", this);
|
| 360 | }
|
| 361 | /** process event input */
|
| 362 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 363 | const std::string& relation = signature[1];
|
| 364 | const std::string& srcLocator = signature[2];
|
| 365 | std::size_t num = va_arg(args, std::size_t);
|
| 366 | db.addTextEntry({"program", "relation", relation, "source-locator"}, srcLocator);
|
| 367 | db.addSizeEntry({"program", "relation", relation, "num-tuples"}, num);
|
| 368 | }
|
| 369 | } nonRecursiveRelationNumberProcessor;
|
| 370 |
|
| 371 | /**
|
| 372 | * Recursive Relation Timing Profile Event Processor
|
| 373 | */
|
| 374 | const class RecursiveRelationTimingProcessor : public EventProcessor {
|
| 375 | public:
|
| 376 | RecursiveRelationTimingProcessor() {
|
| 377 | EventProcessorSingleton::instance().registerEventProcessor("@t-recursive-relation", this);
|
| 378 | }
|
| 379 | /** process event input */
|
| 380 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 381 | const std::string& relation = signature[1];
|
| 382 | const std::string& srcLocator = signature[2];
|
| 383 | microseconds start = va_arg(args, microseconds);
|
| 384 | microseconds end = va_arg(args, microseconds);
|
| 385 | std::size_t startMaxRSS = va_arg(args, std::size_t);
|
| 386 | std::size_t endMaxRSS = va_arg(args, std::size_t);
|
| 387 | std::size_t size = va_arg(args, std::size_t);
|
| 388 | std::string iteration = std::to_string(va_arg(args, std::size_t));
|
| 389 | db.addTextEntry({"program", "relation", relation, "source-locator"}, srcLocator);
|
| 390 | db.addDurationEntry({"program", "relation", relation, "iteration", iteration, "runtime"}, start, end);
|
| 391 | db.addSizeEntry(
|
| 392 | {"program", "relation", relation, "iteration", iteration, "maxRSS", "pre"}, startMaxRSS);
|
| 393 | db.addSizeEntry(
|
| 394 | {"program", "relation", relation, "iteration", iteration, "maxRSS", "post"}, endMaxRSS);
|
| 395 | db.addSizeEntry({"program", "relation", relation, "iteration", iteration, "num-tuples"}, size);
|
| 396 | }
|
| 397 | } recursiveRelationTimingProcessor;
|
| 398 |
|
| 399 | /**
|
| 400 | * Recursive Relation Timing Profile Event Processor
|
| 401 | */
|
| 402 | const class RecursiveRelationNumberProcessor : public EventProcessor {
|
| 403 | public:
|
| 404 | RecursiveRelationNumberProcessor() {
|
| 405 | EventProcessorSingleton::instance().registerEventProcessor("@n-recursive-relation", this);
|
| 406 | }
|
| 407 | /** process event input */
|
| 408 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 409 | const std::string& relation = signature[1];
|
| 410 | const std::string& srcLocator = signature[2];
|
| 411 | std::size_t number = va_arg(args, std::size_t);
|
| 412 | std::string iteration = std::to_string(va_arg(args, std::size_t));
|
| 413 | db.addTextEntry({"program", "relation", relation, "source-locator"}, srcLocator);
|
| 414 | db.addSizeEntry({"program", "relation", relation, "iteration", iteration, "num-tuples"}, number);
|
| 415 | }
|
| 416 | } recursiveRelationNumberProcessor;
|
| 417 |
|
| 418 | /**
|
| 419 | * Recursive Relation Copy Timing Profile Event Processor
|
| 420 | */
|
| 421 | const class RecursiveRelationCopyTimingProcessor : public EventProcessor {
|
| 422 | public:
|
| 423 | RecursiveRelationCopyTimingProcessor() {
|
| 424 | EventProcessorSingleton::instance().registerEventProcessor("@c-recursive-relation", this);
|
| 425 | }
|
| 426 | /** process event input */
|
| 427 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 428 | const std::string& relation = signature[1];
|
| 429 | const std::string& srcLocator = signature[2];
|
| 430 | microseconds start = va_arg(args, microseconds);
|
| 431 | microseconds end = va_arg(args, microseconds);
|
| 432 | std::size_t startMaxRSS = va_arg(args, std::size_t);
|
| 433 | std::size_t endMaxRSS = va_arg(args, std::size_t);
|
| 434 | va_arg(args, std::size_t);
|
| 435 | std::string iteration = std::to_string(va_arg(args, std::size_t));
|
| 436 | db.addSizeEntry(
|
| 437 | {"program", "relation", relation, "iteration", iteration, "maxRSS", "pre"}, startMaxRSS);
|
| 438 | db.addSizeEntry(
|
| 439 | {"program", "relation", relation, "iteration", iteration, "maxRSS", "post"}, endMaxRSS);
|
| 440 | db.addTextEntry({"program", "relation", relation, "source-locator"}, srcLocator);
|
| 441 | db.addDurationEntry(
|
| 442 | {"program", "relation", relation, "iteration", iteration, "copytime"}, start, end);
|
| 443 | }
|
| 444 | } recursiveRelationCopyTimingProcessor;
|
| 445 |
|
| 446 | /**
|
| 447 | * Recursive Relation Copy Timing Profile Event Processor
|
| 448 | */
|
| 449 | const class RelationIOTimingProcessor : public EventProcessor {
|
| 450 | public:
|
| 451 | RelationIOTimingProcessor() {
|
| 452 | EventProcessorSingleton::instance().registerEventProcessor("@t-relation-savetime", this);
|
| 453 | EventProcessorSingleton::instance().registerEventProcessor("@t-relation-loadtime", this);
|
| 454 | }
|
| 455 | /** process event input */
|
| 456 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 457 | const std::string& relation = signature[1];
|
| 458 | const std::string& srcLocator = signature[2];
|
| 459 | const std::string ioType = signature[3];
|
| 460 | microseconds start = va_arg(args, microseconds);
|
| 461 | microseconds end = va_arg(args, microseconds);
|
| 462 | db.addTextEntry({"program", "relation", relation, "source-locator"}, srcLocator);
|
| 463 | db.addDurationEntry({"program", "relation", relation, ioType}, start, end);
|
| 464 | }
|
| 465 | } relationIOTimingProcessor;
|
| 466 |
|
| 467 | /**
|
| 468 | * Program Run Event Processor
|
| 469 | */
|
| 470 | const class ProgramTimepointProcessor : public EventProcessor {
|
| 471 | public:
|
| 472 | ProgramTimepointProcessor() {
|
| 473 | EventProcessorSingleton::instance().registerEventProcessor("@time", this);
|
| 474 | }
|
| 475 | /** process event input */
|
| 476 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 477 | microseconds time = va_arg(args, microseconds);
|
| 478 | auto path = signature;
|
| 479 | path[0] = "program";
|
| 480 | db.addTimeEntry(path, time);
|
| 481 | }
|
| 482 | } programTimepointProcessor;
|
| 483 |
|
| 484 | /**
|
| 485 | * Program Run Event Processor
|
| 486 | */
|
| 487 | const class ProgramRuntimeProcessor : public EventProcessor {
|
| 488 | public:
|
| 489 | ProgramRuntimeProcessor() {
|
| 490 | EventProcessorSingleton::instance().registerEventProcessor("@runtime", this);
|
| 491 | }
|
| 492 | /** process event input */
|
| 493 | void process(
|
| 494 | ProfileDatabase& db, const std::vector<std::string>& /* signature */, va_list& args) override {
|
| 495 | microseconds start = va_arg(args, microseconds);
|
| 496 | microseconds end = va_arg(args, microseconds);
|
| 497 | db.addDurationEntry({"program", "runtime"}, start, end);
|
| 498 | }
|
| 499 | } programRuntimeProcessor;
|
| 500 |
|
| 501 | /**
|
| 502 | * Program Resource Utilisation Event Processor
|
| 503 | */
|
| 504 | const class ProgramResourceUtilisationProcessor : public EventProcessor {
|
| 505 | public:
|
| 506 | ProgramResourceUtilisationProcessor() {
|
| 507 | EventProcessorSingleton::instance().registerEventProcessor("@utilisation", this);
|
| 508 | }
|
| 509 | /** process event input */
|
| 510 | void process(
|
| 511 | ProfileDatabase& db, const std::vector<std::string>& /* signature */, va_list& args) override {
|
| 512 | microseconds time = va_arg(args, microseconds);
|
| 513 | uint64_t systemTime = va_arg(args, uint64_t);
|
| 514 | uint64_t userTime = va_arg(args, uint64_t);
|
| 515 | std::size_t maxRSS = va_arg(args, std::size_t);
|
| 516 | std::string timeString = std::to_string(time.count());
|
| 517 | db.addSizeEntry({"program", "usage", "timepoint", timeString, "systemtime"}, systemTime);
|
| 518 | db.addSizeEntry({"program", "usage", "timepoint", timeString, "usertime"}, userTime);
|
| 519 | db.addSizeEntry({"program", "usage", "timepoint", timeString, "maxRSS"}, maxRSS);
|
| 520 | }
|
| 521 | } programResourceUtilisationProcessor;
|
| 522 |
|
| 523 | /**
|
| 524 | * Frequency Atom Processor
|
| 525 | */
|
| 526 | const class FrequencyAtomProcessor : public EventProcessor {
|
| 527 | public:
|
| 528 | FrequencyAtomProcessor() {
|
| 529 | EventProcessorSingleton::instance().registerEventProcessor("@frequency-atom", this);
|
| 530 | }
|
| 531 | /** process event input */
|
| 532 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 533 | const std::string& relation = signature[1];
|
| 534 | const std::string& version = signature[2];
|
| 535 | const std::string& rule = signature[3];
|
| 536 | const std::string& atom = signature[4];
|
| 537 | const std::string& originalRule = signature[5];
|
| 538 | std::size_t level = std::stoi(signature[6]);
|
| 539 | std::size_t number = va_arg(args, std::size_t);
|
| 540 | std::size_t iteration = va_arg(args, std::size_t);
|
| 541 | // non-recursive rule
|
| 542 | if (rule == originalRule) {
|
| 543 | db.addSizeEntry({"program", "relation", relation, "non-recursive-rule", rule, "atom-frequency",
|
| 544 | rule, atom, "level"},
|
| 545 | level);
|
| 546 | db.addSizeEntry({"program", "relation", relation, "non-recursive-rule", rule, "atom-frequency",
|
| 547 | rule, atom, "num-tuples"},
|
| 548 | number);
|
| 549 | } else {
|
| 550 | db.addSizeEntry(
|
| 551 | {"program", "relation", relation, "iteration", std::to_string(iteration),
|
| 552 | "recursive-rule", originalRule, version, "atom-frequency", rule, atom, "level"},
|
| 553 | level);
|
| 554 | db.addSizeEntry({"program", "relation", relation, "iteration", std::to_string(iteration),
|
| 555 | "recursive-rule", originalRule, version, "atom-frequency", rule, atom,
|
| 556 | "num-tuples"},
|
| 557 | number);
|
| 558 | }
|
| 559 | }
|
| 560 | } frequencyAtomProcessor;
|
| 561 |
|
| 562 | /**
|
| 563 | * Reads Processor
|
| 564 | */
|
| 565 | const class RelationReadsProcessor : public EventProcessor {
|
| 566 | public:
|
| 567 | RelationReadsProcessor() {
|
| 568 | EventProcessorSingleton::instance().registerEventProcessor("@relation-reads", this);
|
| 569 | }
|
| 570 | /** process event input */
|
| 571 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 572 | const std::string& relation = signature[1];
|
| 573 | std::size_t reads = va_arg(args, std::size_t);
|
| 574 | db.addSizeEntry({"program", "relation", relation, "reads"}, reads);
|
| 575 | }
|
| 576 |
|
| 577 | } relationReadsProcessor;
|
| 578 |
|
| 579 | /**
|
| 580 | * Config entry processor
|
| 581 | */
|
| 582 | const class ConfigProcessor : public EventProcessor {
|
| 583 | public:
|
| 584 | ConfigProcessor() {
|
| 585 | EventProcessorSingleton::instance().registerEventProcessor("@config", this);
|
| 586 | }
|
| 587 | void process(
|
| 588 | ProfileDatabase& db, const std::vector<std::string>& /* signature */, va_list& args) override {
|
| 589 | const std::string key = va_arg(args, char*);
|
| 590 | const std::string& value = va_arg(args, char*);
|
| 591 | db.addTextEntry({"program", "configuration", key}, value);
|
| 592 | }
|
| 593 | } configProcessor;
|
| 594 |
|
| 595 | /**
|
| 596 | * Text entry processor
|
| 597 | */
|
| 598 | const class TextProcessor : public EventProcessor {
|
| 599 | public:
|
| 600 | TextProcessor() {
|
| 601 | EventProcessorSingleton::instance().registerEventProcessor("@text", this);
|
| 602 | }
|
| 603 | void process(ProfileDatabase& db, const std::vector<std::string>& signature, va_list& args) override {
|
| 604 | const std::string text = va_arg(args, char*);
|
| 605 | auto path = signature;
|
| 606 | path.front() = "program";
|
| 607 | db.addTextEntry(path, text);
|
| 608 | }
|
| 609 | } textProcessor;
|
| 610 |
|
| 611 | } // namespace profile
|
| 612 | } // namespace souffle
|