| 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 | 
 | 
| 11 | #include "souffle/profile/Iteration.h"
 | 
| 12 | #include "souffle/profile/Rule.h"
 | 
| 13 | #include <algorithm>
 | 
| 14 | #include <chrono>
 | 
| 15 | #include <cstddef>
 | 
| 16 | #include <memory>
 | 
| 17 | #include <sstream>
 | 
| 18 | #include <string>
 | 
| 19 | #include <unordered_map>
 | 
| 20 | #include <utility>
 | 
| 21 | #include <vector>
 | 
| 22 | 
 | 
| 23 | namespace souffle {
 | 
| 24 | namespace profile {
 | 
| 25 | 
 | 
| 26 | /*
 | 
| 27 |  * Stores the iterations and rules of a given relation
 | 
| 28 |  */
 | 
| 29 | class Relation {
 | 
| 30 | private:
 | 
| 31 |     const std::string name;
 | 
| 32 |     std::chrono::microseconds starttime{};
 | 
| 33 |     std::chrono::microseconds endtime{};
 | 
| 34 |     std::chrono::microseconds loadstarttime{};
 | 
| 35 |     std::chrono::microseconds loadendtime{};
 | 
| 36 |     std::chrono::microseconds savetime{};
 | 
| 37 |     std::size_t nonRecTuples = 0;
 | 
| 38 |     std::size_t preMaxRSS = 0;
 | 
| 39 |     std::size_t postMaxRSS = 0;
 | 
| 40 |     const std::string id;
 | 
| 41 |     std::string locator;
 | 
| 42 |     int ruleId = 0;
 | 
| 43 |     int recursiveId = 0;
 | 
| 44 |     std::size_t tuplesRead = 0;
 | 
| 45 | 
 | 
| 46 |     std::vector<std::shared_ptr<Iteration>> iterations;
 | 
| 47 | 
 | 
| 48 |     std::unordered_map<std::string, std::shared_ptr<Rule>> ruleMap;
 | 
| 49 | 
 | 
| 50 |     bool ready = true;
 | 
| 51 | 
 | 
| 52 | public:
 | 
| 53 |     Relation(std::string name, std::string id) : name(std::move(name)), id(std::move(id)) {
 | 
| 54 |         ruleMap = std::unordered_map<std::string, std::shared_ptr<Rule>>();
 | 
| 55 |         iterations = std::vector<std::shared_ptr<Iteration>>();
 | 
| 56 |     }
 | 
| 57 | 
 | 
| 58 |     std::string createID() {
 | 
| 59 |         return "N" + id.substr(1) + "." + std::to_string(++ruleId);
 | 
| 60 |     }
 | 
| 61 | 
 | 
| 62 |     std::string createRecID(std::string name) {
 | 
| 63 |         for (auto& iter : iterations) {
 | 
| 64 |             for (auto& rul : iter->getRules()) {
 | 
| 65 |                 if (rul.second->getName() == name) {
 | 
| 66 |                     return rul.second->getId();
 | 
| 67 |                 }
 | 
| 68 |             }
 | 
| 69 |         }
 | 
| 70 |         return "C" + id.substr(1) + "." + std::to_string(++recursiveId);
 | 
| 71 |     }
 | 
| 72 | 
 | 
| 73 |     std::chrono::microseconds getLoadtime() const {
 | 
| 74 |         return loadendtime - loadstarttime;
 | 
| 75 |     }
 | 
| 76 | 
 | 
| 77 |     std::chrono::microseconds getLoadStarttime() const {
 | 
| 78 |         return loadstarttime;
 | 
| 79 |     }
 | 
| 80 | 
 | 
| 81 |     std::chrono::microseconds getLoadEndtime() const {
 | 
| 82 |         return loadendtime;
 | 
| 83 |     }
 | 
| 84 | 
 | 
| 85 |     std::chrono::microseconds getSavetime() const {
 | 
| 86 |         return savetime;
 | 
| 87 |     }
 | 
| 88 | 
 | 
| 89 |     std::chrono::microseconds getStarttime() const {
 | 
| 90 |         return starttime;
 | 
| 91 |     }
 | 
| 92 | 
 | 
| 93 |     std::chrono::microseconds getEndtime() const {
 | 
| 94 |         return endtime;
 | 
| 95 |     }
 | 
| 96 | 
 | 
| 97 |     std::chrono::microseconds getNonRecTime() const {
 | 
| 98 |         return endtime - starttime;
 | 
| 99 |     }
 | 
| 100 | 
 | 
| 101 |     std::chrono::microseconds getRecTime() const {
 | 
| 102 |         std::chrono::microseconds result{};
 | 
| 103 |         for (auto& iter : iterations) {
 | 
| 104 |             result += iter->getRuntime();
 | 
| 105 |         }
 | 
| 106 |         return result;
 | 
| 107 |     }
 | 
| 108 | 
 | 
| 109 |     std::chrono::microseconds getCopyTime() const {
 | 
| 110 |         std::chrono::microseconds result{};
 | 
| 111 |         for (auto& iter : iterations) {
 | 
| 112 |             result += iter->getCopytime();
 | 
| 113 |         }
 | 
| 114 |         return result;
 | 
| 115 |     }
 | 
| 116 | 
 | 
| 117 |     std::size_t size() const {
 | 
| 118 |         std::size_t result = 0;
 | 
| 119 |         for (auto& iter : iterations) {
 | 
| 120 |             result += iter->size();
 | 
| 121 |         }
 | 
| 122 |         return nonRecTuples + result;
 | 
| 123 |     }
 | 
| 124 | 
 | 
| 125 |     std::size_t getMaxRSSDiff() const {
 | 
| 126 |         return postMaxRSS - preMaxRSS;
 | 
| 127 |     }
 | 
| 128 | 
 | 
| 129 |     std::size_t getTotalRecursiveRuleSize() const {
 | 
| 130 |         std::size_t result = 0;
 | 
| 131 |         for (auto& iter : iterations) {
 | 
| 132 |             for (auto& rul : iter->getRules()) {
 | 
| 133 |                 result += rul.second->size();
 | 
| 134 |             }
 | 
| 135 |         }
 | 
| 136 |         return result;
 | 
| 137 |     }
 | 
| 138 | 
 | 
| 139 |     void setLoadtime(std::chrono::microseconds loadstarttime, std::chrono::microseconds loadendtime) {
 | 
| 140 |         this->loadstarttime = loadstarttime;
 | 
| 141 |         this->loadendtime = loadendtime;
 | 
| 142 |     }
 | 
| 143 | 
 | 
| 144 |     void setSavetime(std::chrono::microseconds savetime) {
 | 
| 145 |         this->savetime = savetime;
 | 
| 146 |     }
 | 
| 147 | 
 | 
| 148 |     void setStarttime(std::chrono::microseconds time) {
 | 
| 149 |         starttime = time;
 | 
| 150 |     }
 | 
| 151 | 
 | 
| 152 |     void setEndtime(std::chrono::microseconds time) {
 | 
| 153 |         endtime = time;
 | 
| 154 |     }
 | 
| 155 | 
 | 
| 156 |     void setNumTuples(std::size_t numTuples) {
 | 
| 157 |         nonRecTuples = numTuples;
 | 
| 158 |     }
 | 
| 159 | 
 | 
| 160 |     void setPostMaxRSS(std::size_t maxRSS) {
 | 
| 161 |         postMaxRSS = std::max(maxRSS, postMaxRSS);
 | 
| 162 |     }
 | 
| 163 | 
 | 
| 164 |     void setPreMaxRSS(std::size_t maxRSS) {
 | 
| 165 |         if (preMaxRSS == 0) {
 | 
| 166 |             preMaxRSS = maxRSS;
 | 
| 167 |             return;
 | 
| 168 |         }
 | 
| 169 |         preMaxRSS = std::min(maxRSS, preMaxRSS);
 | 
| 170 |     }
 | 
| 171 | 
 | 
| 172 |     std::string toString() const {
 | 
| 173 |         std::ostringstream output;
 | 
| 174 |         output << "{\n\"" << name << "\":[" << getNonRecTime().count() << "," << nonRecTuples
 | 
| 175 |                << "],\n\n\"onRecRules\":[\n";
 | 
| 176 |         for (auto& rul : ruleMap) {
 | 
| 177 |             output << rul.second->toString();
 | 
| 178 |         }
 | 
| 179 |         output << "\n],\n\"iterations\":\n";
 | 
| 180 |         output << "[";
 | 
| 181 |         if (iterations.empty()) {
 | 
| 182 |             output << ", ";
 | 
| 183 |         }
 | 
| 184 |         for (auto& iter : iterations) {
 | 
| 185 |             output << iter->toString();
 | 
| 186 |             output << ", ";
 | 
| 187 |         }
 | 
| 188 |         std::string retStr = output.str();
 | 
| 189 |         // substring to remove the last comma
 | 
| 190 |         return retStr.substr(0, retStr.size() - 2) + "]\n}";
 | 
| 191 |     }
 | 
| 192 | 
 | 
| 193 |     std::string getName() const {
 | 
| 194 |         return name;
 | 
| 195 |     }
 | 
| 196 | 
 | 
| 197 |     /**
 | 
| 198 |      * Return a map of Rules, indexed by srcLocator.
 | 
| 199 |      *
 | 
| 200 |      * @return the ruleMap
 | 
| 201 |      */
 | 
| 202 |     const std::unordered_map<std::string, std::shared_ptr<Rule>>& getRuleMap() const {
 | 
| 203 |         return ruleMap;
 | 
| 204 |     }
 | 
| 205 | 
 | 
| 206 |     void addRule(std::shared_ptr<Rule> rule) {
 | 
| 207 |         ruleMap[rule->getLocator()] = rule;
 | 
| 208 |     }
 | 
| 209 | 
 | 
| 210 |     std::vector<std::shared_ptr<Rule>> getRuleRecList() const {
 | 
| 211 |         std::vector<std::shared_ptr<Rule>> temp = std::vector<std::shared_ptr<Rule>>();
 | 
| 212 |         for (auto& iter : iterations) {
 | 
| 213 |             for (auto& rul : iter->getRules()) {
 | 
| 214 |                 temp.push_back(rul.second);
 | 
| 215 |             }
 | 
| 216 |         }
 | 
| 217 |         return temp;
 | 
| 218 |     }
 | 
| 219 | 
 | 
| 220 |     const std::vector<std::shared_ptr<Iteration>>& getIterations() const {
 | 
| 221 |         return iterations;
 | 
| 222 |     }
 | 
| 223 | 
 | 
| 224 |     void addIteration(std::shared_ptr<Iteration> iteration) {
 | 
| 225 |         iterations.push_back(iteration);
 | 
| 226 |         if (endtime < iteration->getEndtime()) {
 | 
| 227 |             endtime = iteration->getEndtime();
 | 
| 228 |         }
 | 
| 229 |         if (starttime.count() == 0 || starttime > iteration->getStarttime()) {
 | 
| 230 |             starttime = iteration->getStarttime();
 | 
| 231 |         }
 | 
| 232 |     }
 | 
| 233 | 
 | 
| 234 |     const std::string& getId() const {
 | 
| 235 |         return id;
 | 
| 236 |     }
 | 
| 237 | 
 | 
| 238 |     const std::string& getLocator() const {
 | 
| 239 |         return locator;
 | 
| 240 |     }
 | 
| 241 | 
 | 
| 242 |     void setLocator(std::string locator) {
 | 
| 243 |         this->locator = locator;
 | 
| 244 |     }
 | 
| 245 | 
 | 
| 246 |     bool isReady() {
 | 
| 247 |         return ready;
 | 
| 248 |     }
 | 
| 249 | 
 | 
| 250 |     void setReady(bool ready) {
 | 
| 251 |         this->ready = ready;
 | 
| 252 |     }
 | 
| 253 | 
 | 
| 254 |     std::size_t getReads() const {
 | 
| 255 |         return tuplesRead;
 | 
| 256 |     }
 | 
| 257 | 
 | 
| 258 |     void addReads(std::size_t tuplesRead) {
 | 
| 259 |         this->tuplesRead += tuplesRead;
 | 
| 260 |     }
 | 
| 261 | };
 | 
| 262 | 
 | 
| 263 | }  // namespace profile
 | 
| 264 | }  // namespace souffle
 |