39 #include <unordered_map> 
   43 #include <sys/ioctl.h> 
   73         std::chrono::microseconds 
time;
 
   83     Tui(std::string filename, 
bool live, 
bool ) {
 
   88         this->f_name = filename;
 
   92         this->reader = std::make_shared<Reader>(filename, run);
 
   96         this->loaded = 
reader->isLoaded();
 
  101         this->reader = std::make_shared<Reader>(run);
 
  105         updater = std::thread([
this]() {
 
  107             std::chrono::milliseconds interval(30000);
 
  110                 std::this_thread::sleep_for(std::chrono::milliseconds(500));
 
  130             std::cout << 
"Error: File cannot be loaded\n";
 
  146             std::cout << 
"\x1b[3D";
 
  147             std::cout << 
"\x1b[27A";
 
  149             std::cout << 
"\x1b[B> ";
 
  150         } 
else if (c[0] == 
"top") {
 
  152         } 
else if (c[0] == 
"rel") {
 
  155             } 
else if (c.size() == 1) {
 
  158                 std::cout << 
"Invalid parameters to rel command.\n";
 
  160         } 
else if (c[0] == 
"rul") {
 
  162                 if (c.size() == 3 && c[1] == 
"id") {
 
  165                 } 
else if (c.size() == 2 && c[1] == 
"id") {
 
  167                 } 
else if (c.size() == 2) {
 
  170                     std::cout << 
"Invalid parameters to rul command.\n";
 
  175         } 
else if (c[0] == 
"graph") {
 
  176             if (c.size() == 3 && c[1].find(
".") == std::string::npos) {
 
  178             } 
else if (c.size() == 3 && c[1].at(0) == 
'C') {
 
  180             } 
else if (c.size() == 4 && c[1] == 
"ver" && c[2].at(0) == 
'C') {
 
  183                 std::cout << 
"Invalid parameters to graph command.\n";
 
  185         } 
else if (c[0] == 
"memory") {
 
  187         } 
else if (c[0] == 
"usage") {
 
  189                 if (c[1][0] == 
'R') {
 
  197         } 
else if (c[0] == 
"help") {
 
  199         } 
else if (c[0] == 
"limit") {
 
  206                     std::cout << 
"Invalid parameters to limit command.\n";
 
  209         } 
else if (c[0] == 
"configuration") {
 
  212             std::cout << 
"Unknown command. Use \"help\" for a list of commands.\n";
 
  218             std::cout << 
"Error: File cannot be floaded\n";
 
  222             std::cout << 
"SouffleProf\n";
 
  233             std::cout << std::endl;
 
  235                 std::cout << 
"Unknown command. Type help for a list of commands.\n";
 
  243             if (c[0] == 
"q" || c[0] == 
"quit") {
 
  246             } 
else if (c[0] == 
"sort") {
 
  247                 if (c.size() == 2 && std::stoi(c[1]) < 7) {
 
  250                     std::cout << 
"Invalid column, please select a number between 0 and 6.\n";
 
  261         auto beginTime = run->getStarttime();
 
  262         auto endTime = run->getEndtime();
 
  263         ss << R
"_({"top":[)_" << (endTime - beginTime).count() / 1000000.0 << "," << run->getTotalSize()
 
  264            << 
"," << run->getTotalLoadtime().count() / 1000000.0 << 
"," 
  265            << run->getTotalSavetime().count() / 1000000.0 << 
"]";
 
  269     std::stringstream& 
genJsonRelations(std::stringstream& 
ss, 
const std::string& name, 
size_t maxRows) {
 
  272         auto comma = [&
ss](
bool& first, 
const std::string& delimiter = 
", ") {
 
  280         ss << 
'"' << name << R
"_(":{)_"; 
  281         bool firstRow = 
true;
 
  283         std::stable_sort(rows.begin(), rows.end(), [](std::shared_ptr<Row> left, std::shared_ptr<Row> right) {
 
  284             return (*left)[0]->getDoubleVal() > (*right)[0]->getDoubleVal();
 
  286         maxRows = std::min(rows.size(), maxRows);
 
  288         for (
size_t i = 0; 
i < maxRows; ++
i) {
 
  289             comma(firstRow, 
",\n");
 
  292             ss << 
'"' << row[6]->toString(0) << R
"_(": [)_"; 
  295             ss << row[0]->getDoubleVal() << ", ";
 
  296             ss << row[1]->getDoubleVal() << 
", ";
 
  297             ss << row[2]->getDoubleVal() << 
", ";
 
  298             ss << row[3]->getDoubleVal() << 
", ";
 
  299             ss << row[4]->getLongVal() << 
", ";
 
  300             ss << row[12]->getLongVal() << 
", ";
 
  303             bool firstCol = 
true;
 
  305                 Row rel_row = *_rel_row;
 
  308                     ss << 
'"' << rel_row[6]->toString(0) << 
'"';
 
  312             std::vector<std::shared_ptr<Iteration>> iter =
 
  313                     run->getRelation(row[5]->
toString(0))->getIterations();
 
  314             ss << R
"_({"tot_t": [)_"; 
  316             for (
auto& 
i : iter) {
 
  318                 ss << 
i->getRuntime().count();
 
  320             ss << R
"_(], "copy_t": [)_"; 
  322             for (
auto& 
i : iter) {
 
  324                 ss << 
i->getCopytime().count();
 
  326             ss << R
"_(], "tuples": [)_"; 
  328             for (
auto& 
i : iter) {
 
  339     std::stringstream& 
genJsonRules(std::stringstream& 
ss, 
const std::string& name, 
size_t maxRows) {
 
  342         auto comma = [&
ss](
bool& first, 
const std::string& delimiter = 
", ") {
 
  350         ss << 
'"' << name << R
"_(":{)_"; 
  352         bool firstRow = 
true;
 
  354         std::stable_sort(rows.begin(), rows.end(), [](std::shared_ptr<Row> left, std::shared_ptr<Row> right) {
 
  355             return (*left)[0]->getDoubleVal() > (*right)[0]->getDoubleVal();
 
  357         maxRows = std::min(rows.size(), maxRows);
 
  359         for (
size_t i = 0; 
i < maxRows; ++
i) {
 
  363             std::string strRel = 
"R" + part[0].substr(1);
 
  367             if (versionTable.rows.
size() > 0) {
 
  368                 if (versionTable.rows[0]->cells[9] != 
nullptr) {
 
  369                     src = (*versionTable.rows[0])[9]->
toString(0);
 
  374                 src = row[10]->toString(-1);
 
  379             ss << 
'"' << row[6]->toString(0) << R
"_(": [)_"; 
  382             ss << row[0]->getDoubleVal() << ", ";
 
  383             ss << row[1]->getDoubleVal() << 
", ";
 
  384             ss << row[2]->getDoubleVal() << 
", ";
 
  385             ss << row[4]->getLongVal() << 
", ";
 
  387             ss << 
'"' << src << R
"_(", )_"; 
  390             bool has_ver = 
false;
 
  391             bool firstCol = 
true;
 
  392             for (
auto& _ver_row : versionTable.getRows()) {
 
  395                 Row ver_row = *_ver_row;
 
  399                 ss << ver_row[0]->getDoubleVal() << ", ";
 
  400                 ss << ver_row[1]->getDoubleVal() << 
", ";
 
  401                 ss << ver_row[2]->getDoubleVal() << 
", ";
 
  402                 ss << ver_row[4]->getLongVal() << 
", ";
 
  403                 ss << 
'"' << src << R
"_(", )_"; 
  404                 ss << ver_row[8]->getLongVal(); 
  410             if (row[6]->
toString(0).at(0) != 
'C') {
 
  413                 ss << R
"_({"tot_t": [)_"; 
  415                 std::vector<uint64_t> iteration_tuples; 
  416                 bool firstCol = 
true;
 
  417                 for (
auto& 
i : run->getRelation(row[7]->toString(0))->getIterations()) {
 
  419                     std::chrono::microseconds totalTime{};
 
  420                     uint64_t totalSize = 0L;
 
  421                     for (
auto& 
rul : 
i->getRules()) {
 
  422                         if (
rul.second->getId() == row[6]->toString(0)) {
 
  423                             totalTime += 
rul.second->getRuntime();
 
  425                             totalSize += 
rul.second->size();
 
  431                         ss << totalTime.count();
 
  432                         iteration_tuples.push_back(totalSize);
 
  435                 ss << R
"_(], "tuples": [)_"; 
  437                 for (
auto& 
i : iteration_tuples) {
 
  445                     ss << R
"_("tot_t": [)_"; 
  448                     for (
auto& row : versionTable.rows) {
 
  450                         ss << (*row)[0]->getDoubleVal();
 
  452                     ss << R
"_(], "tuples": [)_"; 
  455                     for (
auto& row : versionTable.rows) {
 
  457                         ss << (*row)[4]->getLongVal();
 
  471         auto comma = [&
ss](
bool& first, 
const std::string& delimiter = 
", ") {
 
  480         std::string source_file_loc = 
Tools::split(source_loc, 
" ").at(0);
 
  481         std::ifstream source_file(source_file_loc);
 
  482         if (!source_file.is_open()) {
 
  483             std::cout << 
"Error opening \"" << source_file_loc << 
"\", creating GUI without source locator." 
  487             ss << R
"_("code": [)_"; 
  488             bool firstCol = 
true;
 
  489             while (getline(source_file, 
str)) {
 
  490                 comma(firstCol, 
",\n");
 
  499         auto beginTime = run->getStarttime();
 
  501         ss << R
"_("usage": [)_"; 
  502         bool firstRow = 
true;
 
  503         Usage previousUsage = *usages.begin();
 
  504         previousUsage.time = beginTime;
 
  505         for (
auto usage : usages) {
 
  508             ss << (
usage.time - beginTime).
count() / 1000000.0 << 
", ";
 
  509             ss << 100.0 * (
usage.usertime - previousUsage.usertime) / (
usage.time - previousUsage.time)
 
  511             ss << 100.0 * (
usage.systemtime - previousUsage.systemtime) / (
usage.time - previousUsage.time)
 
  513             ss << 
usage.maxRSS * 1024 << 
", ";
 
  515             bool firstCol = 
true;
 
  518                 ss << cur->getName();
 
  522             previousUsage = 
usage;
 
  529         auto comma = [&
ss](
bool& first, 
const std::string& delimiter = 
", ") {
 
  538         ss << R
"_("configuration": {)_"; 
  539         bool firstRow = 
true;
 
  552         auto comma = [&
ss](
bool& first, 
const std::string& delimiter = 
", ") {
 
  560         ss << R
"_("atoms": {)_"; 
  562         bool firstRow = 
true;
 
  563         for (
auto& 
relation : run->getRelationMap()) {
 
  566                 comma(firstRow, 
", \n");
 
  567                 ss << 
'"' << 
rule.second->getId() << R
"_(": [)_"; 
  568                 bool firstCol = 
true;
 
  569                 for (
auto& atom : 
rule.second->getAtoms()) {
 
  571                     std::string relationName = atom.identifier;
 
  572                     relationName = relationName.substr(0, relationName.find(
'('));
 
  574                     std::string relationSize = 
relation == 
nullptr ? 
"" : std::to_string(
relation->size());
 
  578                     ss << relationSize << ", ";
 
  579                     ss << atom.frequency << 
']';
 
  586                     comma(firstRow, 
", \n");
 
  587                     ss << 
'"' << 
rule.second->getId() << R
"_(": [)_"; 
  588                     bool firstCol = 
true;
 
  589                     for (
auto& atom : 
rule.second->getAtoms()) {
 
  591                         std::string relationName = atom.identifier;
 
  592                         relationName = relationName.substr(0, relationName.find(
'('));
 
  594                         std::string relationSize =
 
  599                         ss << relationSize << ", ";
 
  600                         ss << atom.frequency << 
']';
 
  612         std::stringstream 
ss;
 
  637         std::cout << 
"SouffleProf\n";
 
  638         std::cout << 
"Generating HTML files...\n";
 
  643         if (filename.find(
'/') != std::string::npos) {
 
  644             std::string path = filename.substr(0, filename.find(
'/'));
 
  645             if ((dir = opendir(path.c_str())) != 
nullptr) {
 
  652                 nError = mkdir(path.c_str(), nMode);
 
  654                     std::cerr << 
"directory " << path
 
  655                               << 
" could not be created. Please create it and try again.";
 
  660         std::string filetype = 
".html";
 
  661         std::string newFile = filename;
 
  663         if (filename.size() <= filetype.size() ||
 
  664                 !std::equal(filetype.rbegin(), filetype.rend(), filename.rbegin())) {
 
  668                 newFile = filename + std::to_string(
i) + 
".html";
 
  672         std::ofstream outfile(newFile);
 
  676         std::cout << 
"file output to: " << newFile << std::endl;
 
  686         std::cout << 
"\nAvailable profiling commands:" << std::endl;
 
  687         std::printf(
"  %-30s%-5s %s\n", 
"rel", 
"-", 
"display relation table.");
 
  688         std::printf(
"  %-30s%-5s %s\n", 
"rel <relation id>", 
"-", 
"display all rules of a given relation.");
 
  689         std::printf(
"  %-30s%-5s %s\n", 
"rul", 
"-", 
"display rule table");
 
  690         std::printf(
"  %-30s%-5s %s\n", 
"rul <rule id>", 
"-", 
"display all version of given rule.");
 
  691         std::printf(
"  %-30s%-5s %s\n", 
"rul id", 
"-", 
"display all rules names and ids.");
 
  693                 "  %-30s%-5s %s\n", 
"rul id <rule id>", 
"-", 
"display the rule name for the given rule id.");
 
  694         std::printf(
"  %-30s%-5s %s\n", 
"graph <relation id> <type>", 
"-",
 
  695                 "graph a relation by type: (tot_t/copy_t/tuples).");
 
  696         std::printf(
"  %-30s%-5s %s\n", 
"graph <rule id> <type>", 
"-",
 
  697                 "graph recursive(C) rule by type(tot_t/tuples).");
 
  698         std::printf(
"  %-30s%-5s %s\n", 
"graph ver <rule id> <type>", 
"-",
 
  699                 "graph recursive(C) rule versions by type(tot_t/copy_t/tuples).");
 
  700         std::printf(
"  %-30s%-5s %s\n", 
"top", 
"-", 
"display top-level summary of program run.");
 
  701         std::printf(
"  %-30s%-5s %s\n", 
"configuration", 
"-", 
"display configuration settings for this run.");
 
  702         std::printf(
"  %-30s%-5s %s\n", 
"usage [relation id|rule id]", 
"-",
 
  703                 "display CPU usage graphs for a relation or rule.");
 
  704         std::printf(
"  %-30s%-5s %s\n", 
"memory", 
"-", 
"display memory usage.");
 
  705         std::printf(
"  %-30s%-5s %s\n", 
"help", 
"-", 
"print this.");
 
  707         std::cout << 
"\nInteractive mode only commands:" << std::endl;
 
  710         std::printf(
"  %-30s%-5s %s\n", 
"limit <row count>", 
"-", 
"limit number of results shown.");
 
  711         std::printf(
"  %-30s%-5s %s\n", 
"sort <col number>", 
"-", 
"sort tables by given column number.");
 
  712         std::printf(
"  %-30s%-5s %s\n", 
"q", 
"-", 
"exit program.");
 
  716         std::vector<std::vector<std::string>> formattedRelationTable =
 
  718         std::string name = 
"";
 
  720         for (
auto& row : formattedRelationTable) {
 
  721             if (row[5] == 
id || row[6] == 
id) {
 
  728             std::cout << 
"Relation does not exist.\n";
 
  738         std::string relName = 
"";
 
  739         std::string srcLocator = 
"";
 
  741         for (
auto& row : formattedRuleTable) {
 
  742             if (row[5] == 
id || row[6] == 
id) {
 
  744                 srcLocator = row[10];
 
  750             std::cout << 
"Rule does not exist.\n";
 
  755         if (
rel == 
nullptr) {
 
  756             std::cout << 
"Relation ceased to exist. Odd." << std::endl;
 
  759         if (
rel->getRuleMap().count(srcLocator) == 0) {
 
  760             std::cout << 
"Rule ceased to exist. Odd." << std::endl;
 
  764         auto& 
rul = 
rel->getRuleMap().at(srcLocator);
 
  769         std::set<Usage> usages;
 
  770         DirectoryEntry* usageStats = 
dynamic_cast<DirectoryEntry*
>(
 
  772         if (usageStats == 
nullptr || usageStats->getKeys().size() < 2) {
 
  775         std::chrono::microseconds endTime{};
 
  776         std::chrono::microseconds startTime{};
 
  777         std::chrono::microseconds timeStep{};
 
  779         std::set<Usage> allUsages;
 
  780         for (
auto& currentKey : usageStats->getKeys()) {
 
  781             Usage currentUsage{};
 
  782             uint64_t cur = std::stoul(currentKey);
 
  783             currentUsage.time = std::chrono::duration<uint64_t, std::micro>(cur);
 
  784             cur = 
dynamic_cast<SizeEntry*
>(
 
  785                     usageStats->readDirectoryEntry(currentKey)->readEntry(
"systemtime"))
 
  787             currentUsage.systemtime = std::chrono::duration<uint64_t, std::micro>(cur);
 
  788             cur = 
dynamic_cast<SizeEntry*
>(usageStats->readDirectoryEntry(currentKey)->readEntry(
"usertime"))
 
  790             currentUsage.usertime = std::chrono::duration<uint64_t, std::micro>(cur);
 
  791             currentUsage.maxRSS =
 
  792                     dynamic_cast<SizeEntry*
>(usageStats->readDirectoryEntry(currentKey)->readEntry(
"maxRSS"))
 
  796             if (allUsages.find(currentUsage) != allUsages.end()) {
 
  797                 auto& existing = *allUsages.find(currentUsage);
 
  798                 currentUsage.systemtime = std::max(existing.systemtime, currentUsage.systemtime);
 
  799                 currentUsage.usertime = std::max(existing.usertime, currentUsage.usertime);
 
  800                 currentUsage.maxRSS = std::max(existing.maxRSS, currentUsage.maxRSS);
 
  801                 allUsages.erase(currentUsage);
 
  803             allUsages.insert(currentUsage);
 
  807         for (
auto it = ++allUsages.begin(); it != allUsages.end(); ++it) {
 
  808             auto previous = std::prev(it);
 
  809             if (it->usertime < previous->usertime || it->systemtime < previous->systemtime ||
 
  810                     it->time == previous->time) {
 
  811                 it = allUsages.erase(it);
 
  817         startTime = allUsages.begin()->time;
 
  818         endTime = allUsages.rbegin()->time;
 
  821         if (allUsages.size() < width) {
 
  825         timeStep = (endTime - startTime) / width;
 
  828         for (uint32_t 
i = 1; 
i <= width; ++
i) {
 
  829             auto it = allUsages.upper_bound(Usage{startTime + timeStep * 
i, 0, {}, {}});
 
  830             if (it != allUsages.begin()) {
 
  840         usage({}, {}, height);
 
  843     void usage(std::chrono::microseconds endTime, std::chrono::microseconds startTime, uint32_t height = 20) {
 
  848         if (usages.size() < 2) {
 
  849             for (uint8_t 
i = 0; 
i < height + 2; ++
i) {
 
  850                 std::cout << std::endl;
 
  852             std::cout << 
"Insufficient data for usage statistics." << std::endl;
 
  856         double maxIntervalUsage = 0;
 
  859         if (startTime.count() == 0) {
 
  860             startTime = usages.begin()->time;
 
  862         if (endTime.count() == 0) {
 
  863             endTime = usages.rbegin()->time;
 
  866         if (usages.size() < width) {
 
  867             width = usages.size();
 
  871         Usage previousUsage{{}, 0, {}, {}};
 
  872         for (
auto& currentUsage : usages) {
 
  873             double usageDiff = (currentUsage.systemtime - previousUsage.systemtime + currentUsage.usertime -
 
  874                                 previousUsage.usertime)
 
  876             usageDiff /= (currentUsage.time - previousUsage.time).
count();
 
  877             if (usageDiff > maxIntervalUsage) {
 
  878                 maxIntervalUsage = usageDiff;
 
  881             previousUsage = currentUsage;
 
  884         double intervalUsagePercent = 100.0 * maxIntervalUsage;
 
  889         char grid[height][width];
 
  890         for (uint32_t 
i = 0; 
i < height; ++
i) {
 
  891             for (uint32_t 
j = 0; 
j < width; ++
j) {
 
  896         previousUsage = {{}, 0, {}, {}};
 
  898         for (
const Usage& currentUsage : usages) {
 
  899             uint64_t curHeight = 0;
 
  900             uint64_t curSystemHeight = 0;
 
  902             if (maxIntervalUsage != 0) {
 
  903                 curHeight = (currentUsage.systemtime - previousUsage.systemtime + currentUsage.usertime -
 
  904                              previousUsage.usertime)
 
  906                 curHeight /= (currentUsage.time - previousUsage.time).
count();
 
  907                 curHeight *= height / maxIntervalUsage;
 
  909                 curSystemHeight = (currentUsage.systemtime - previousUsage.systemtime).
count();
 
  910                 curSystemHeight /= (currentUsage.time - previousUsage.time).
count();
 
  911                 curSystemHeight *= height / maxIntervalUsage;
 
  913             for (uint32_t row = 0; row < curHeight; ++row) {
 
  914                 grid[row][col] = 
'*';
 
  916             for (uint32_t row = curHeight - curSystemHeight; row < curHeight; ++row) {
 
  917                 grid[row][col] = 
'+';
 
  919             previousUsage = currentUsage;
 
  924         for (int32_t row = height - 1; row >= 0; --row) {
 
  925             printf(
"%6d%% ", uint32_t(intervalUsagePercent * (row + 1) / height));
 
  926             for (uint32_t col = 0; col < width; ++col) {
 
  927                 std::cout << grid[row][col];
 
  929             std::cout << std::endl;
 
  931         for (uint32_t col = 0; col < 8; ++col) {
 
  934         for (uint32_t col = 0; col < width; ++col) {
 
  937         std::cout << std::endl;
 
  944     void memoryUsage(std::chrono::microseconds , std::chrono::microseconds ,
 
  945             uint32_t height = 20) {
 
  947         uint64_t maxMaxRSS = 0;
 
  950         char grid[height][width];
 
  951         for (uint32_t 
i = 0; 
i < height; ++
i) {
 
  952             for (uint32_t 
j = 0; 
j < width; ++
j) {
 
  957         for (
auto& 
usage : usages) {
 
  958             maxMaxRSS = std::max(maxMaxRSS, 
usage.maxRSS);
 
  961         for (
const Usage& currentUsage : usages) {
 
  962             uint64_t curHeight = height * currentUsage.maxRSS / maxMaxRSS;
 
  963             for (uint32_t row = 0; row < curHeight; ++row) {
 
  964                 grid[row][col] = 
'*';
 
  970         for (int32_t row = height - 1; row >= 0; --row) {
 
  972             for (uint32_t col = 0; col < width; ++col) {
 
  973                 std::cout << grid[row][col];
 
  975             std::cout << std::endl;
 
  977         for (uint32_t col = 0; col < 8; ++col) {
 
  980         for (uint32_t col = 0; col < width; ++col) {
 
  983         std::cout << std::endl;
 
 1010         std::cout << 
"Configuration" << 
'\n';
 
 1011         printf(
"%30s      %s", 
"Key", 
"Value\n\n");
 
 1014             if (kvp.first == 
"") {
 
 1015                 printf(
"%30s      %s\n", 
"Datalog input file", kvp.second.c_str());
 
 1018             printf(
"%30s      %s\n", kvp.first.c_str(), kvp.second.c_str());
 
 1020         std::cout << std::endl;
 
 1025         auto* totalRelationsEntry =
 
 1027                         {
"program", 
"configuration", 
"relationCount"}));
 
 1028         auto* totalRulesEntry =
 
 1030                         {
"program", 
"configuration", 
"ruleCount"}));
 
 1031         size_t totalRelations = 0;
 
 1032         if (totalRelationsEntry != 
nullptr) {
 
 1033             totalRelations = std::stoul(totalRelationsEntry->getText());
 
 1035             totalRelations = run->getRelationMap().size();
 
 1037         size_t totalRules = 0;
 
 1038         if (totalRulesEntry != 
nullptr) {
 
 1039             totalRules = std::stoul(totalRulesEntry->getText());
 
 1043         std::printf(
"%11s%10s%10s%10s%10s%20s\n", 
"runtime", 
"loadtime", 
"savetime", 
"relations", 
"rules",
 
 1044                 "tuples generated");
 
 1046         std::printf(
"%11s%10s%10s%10s%10s%14s\n", run->getRuntime().c_str(),
 
 1047                 run->formatTime(run->getTotalLoadtime()).c_str(),
 
 1048                 run->formatTime(run->getTotalSavetime()).c_str(), run->formatNum(0, totalRelations).c_str(),
 
 1049                 run->formatNum(0, totalRules).c_str(),
 
 1050                 run->formatNum(
precision, run->getTotalSize()).c_str());
 
 1054         size_t processedRelations = run->getRelationMap().size();
 
 1056         if (
alive && totalRelationsEntry != 
nullptr) {
 
 1057             std::cout << 
"Progress ";
 
 1058             for (
size_t i = 0; 
i < screenWidth; ++
i) {
 
 1059                 if (screenWidth * processedRelations / totalRelations > 
i) {
 
 1066         std::cout << std::endl;
 
 1068         std::cout << 
"Slowest relations to fully evaluate\n";
 
 1073         std::cout << 
"Slowest rules to fully evaluate\n";
 
 1086     void rel(
size_t limit, 
bool showLimit = 
true) {
 
 1088         std::cout << 
" ----- Relation Table -----\n";
 
 1089         std::printf(
"%8s%8s%8s%8s%8s%8s%8s%8s%8s%6s %s\n\n", 
"TOT_T", 
"NREC_T", 
"REC_T", 
"COPY_T", 
"LOAD_T",
 
 1090                 "SAVE_T", 
"TUPLES", 
"READS", 
"TUP/s", 
"ID", 
"NAME");
 
 1093             if (++
count > limit) {
 
 1100             std::printf(
"%8s%8s%8s%8s%8s%8s%8s%8s%8s%6s %s\n", row[0].c_str(), row[1].c_str(), row[2].c_str(),
 
 1101                     row[3].c_str(), row[9].c_str(), row[10].c_str(), row[4].c_str(), row[12].c_str(),
 
 1102                     row[8].c_str(), row[6].c_str(), row[5].c_str());
 
 1106     void rul(
size_t limit, 
bool showLimit = 
true) {
 
 1108         std::cout << 
"  ----- Rule Table -----\n";
 
 1110                 "%8s%8s%8s%8s%8s%8s %s\n\n", 
"TOT_T", 
"NREC_T", 
"REC_T", 
"TUPLES", 
"TUP/s", 
"ID", 
"RELATION");
 
 1113             if (++
count > limit) {
 
 1119             std::printf(
"%8s%8s%8s%8s%8s%8s %s\n", row[0].c_str(), row[1].c_str(), row[2].c_str(),
 
 1120                     row[4].c_str(), row[9].c_str(), row[6].c_str(), row[7].c_str());
 
 1124     void id(std::string col) {
 
 1130             for (
auto& row : table) {
 
 1131                 std::printf(
"%7s%2s%s\n", row[6].c_str(), 
"", row[5].c_str());
 
 1134             for (
auto& row : table) {
 
 1135                 if (row[6] == col) {
 
 1136                     std::printf(
"%7s%2s%s\n", row[6].c_str(), 
"", row[5].c_str());
 
 1146         std::vector<std::vector<std::string>> formattedRelationTable =
 
 1149         std::cout << 
"  ----- Rules of a Relation -----\n";
 
 1150         std::printf(
"%8s%8s%8s%8s%8s %s\n\n", 
"TOT_T", 
"NREC_T", 
"REC_T", 
"TUPLES", 
"ID", 
"NAME");
 
 1151         std::string name = 
"";
 
 1152         for (
auto& row : formattedRelationTable) {
 
 1154             if (row[5] == 
str || row[6] == 
str) {
 
 1155                 std::printf(
"%8s%8s%8s%8s%8s %s\n", row[0].c_str(), row[1].c_str(), row[2].c_str(),
 
 1156                         row[4].c_str(), row[6].c_str(), row[5].c_str());
 
 1161         std::cout << 
" ---------------------------------------------------------\n";
 
 1162         for (
auto& row : formattedRuleTable) {
 
 1163             if (row[7] == name) {
 
 1164                 std::printf(
"%8s%8s%8s%8s%8s %s\n", row[0].c_str(), row[1].c_str(), row[2].c_str(),
 
 1165                         row[4].c_str(), row[6].c_str(), row[7].c_str());
 
 1168         std::string src = 
"";
 
 1170         if (run->getRelation(name) != 
nullptr) {
 
 1171             src = run->getRelation(name)->getLocator();
 
 1173         std::cout << 
"\nSrc locator: " << src << 
"\n\n";
 
 1174         for (
auto& row : formattedRuleTable) {
 
 1175             if (row[7] == name) {
 
 1176                 std::printf(
"%7s%2s%s\n", row[6].c_str(), 
"", row[5].c_str());
 
 1182         if (
str.find(
".") == std::string::npos) {
 
 1183             std::cout << 
"Rule does not exist\n";
 
 1187         std::string strRel = 
"R" + part[0].substr(1);
 
 1197         std::string ruleName;
 
 1198         std::string srcLocator;
 
 1200         for (
auto& row : formattedRuleTable) {
 
 1201             if (row[6] == 
str) {
 
 1202                 std::cout << row[5] << std::endl;
 
 1205                 srcLocator = row[10];
 
 1211             if (versionTable.rows.size() > 0) {
 
 1212                 if (versionTable.rows[0]->cells[9] != 
nullptr) {
 
 1213                     std::cout << 
"Src locator-: " << (*versionTable.rows[0])[9]->getStringVal() << 
"\n\n";
 
 1215                     std::cout << 
"Src locator-: -\n\n";
 
 1217             } 
else if (formattedRuleTable.size() > 0) {
 
 1218                 std::cout << 
"Src locator-: " << formattedRuleTable[0][10] << 
"\n\n";
 
 1223         std::cout << 
"  ----- Rule Versions Table -----\n";
 
 1224         std::printf(
"%8s%8s%8s%16s%6s\n\n", 
"TOT_T", 
"NREC_T", 
"REC_T", 
"TUPLES", 
"VER");
 
 1225         for (
auto& row : formattedRuleTable) {
 
 1226             if (row[6] == 
str) {
 
 1227                 std::printf(
"%8s%8s%8s%16s%6s\n", row[0].c_str(), row[1].c_str(), row[2].c_str(),
 
 1228                         row[4].c_str(), 
"");
 
 1231         std::cout << 
"   ---------------------------------------------\n";
 
 1232         for (
auto& _row : versionTable.rows) {
 
 1242         if (!versionTable.rows.empty()) {
 
 1253         std::vector<std::shared_ptr<Iteration>> iter;
 
 1254         for (
auto& row : table) {
 
 1256                 std::printf(
"%4s%2s%s\n\n", row[6].c_str(), 
"", row[5].c_str());
 
 1257                 iter = run->getRelation(row[5])->getIterations();
 
 1258                 if (col == 
"tot_t") {
 
 1259                     std::vector<std::chrono::microseconds> list;
 
 1260                     for (
auto& 
i : iter) {
 
 1261                         list.emplace_back(
i->getRuntime());
 
 1265                 } 
else if (col == 
"copy_t") {
 
 1266                     std::vector<std::chrono::microseconds> list;
 
 1267                     for (
auto& 
i : iter) {
 
 1268                         list.emplace_back(
i->getCopytime());
 
 1272                 } 
else if (col == 
"tuples") {
 
 1273                     std::vector<size_t> list;
 
 1274                     for (
auto& 
i : iter) {
 
 1275                         list.emplace_back(
i->size());
 
 1283         for (
auto& row : table) {
 
 1285                 std::printf(
"%4s%2s%s\n\n", row[6].c_str(), 
"", row[5].c_str());
 
 1287                 iter = run->getRelation(row[5])->getIterations();
 
 1288                 if (col == 
"tot_t") {
 
 1289                     std::vector<std::chrono::microseconds> list;
 
 1290                     for (
auto& 
i : iter) {
 
 1291                         list.emplace_back(
i->getRuntime());
 
 1295                 } 
else if (col == 
"copy_t") {
 
 1296                     std::vector<std::chrono::microseconds> list;
 
 1297                     for (
auto& 
i : iter) {
 
 1298                         list.emplace_back(
i->getCopytime());
 
 1302                 } 
else if (col == 
"tuples") {
 
 1303                     std::vector<size_t> list;
 
 1304                     for (
auto& 
i : iter) {
 
 1305                         list.emplace_back(
i->size());
 
 1317         std::vector<std::shared_ptr<Iteration>> iter;
 
 1318         for (
auto& row : table) {
 
 1320                 std::printf(
"%6s%2s%s\n\n", row[6].c_str(), 
"", row[5].c_str());
 
 1322                 iter = run->getRelation(row[7])->getIterations();
 
 1323                 if (col == 
"tot_t") {
 
 1324                     std::vector<std::chrono::microseconds> list;
 
 1325                     for (
auto& 
i : iter) {
 
 1327                         std::chrono::microseconds totalTime{};
 
 1328                         for (
auto& 
rul : 
i->getRules()) {
 
 1329                             if (
rul.second->getId() == c) {
 
 1330                                 totalTime += 
rul.second->getRuntime();
 
 1335                             list.emplace_back(totalTime);
 
 1340                 } 
else if (col == 
"tuples") {
 
 1341                     std::vector<size_t> list;
 
 1342                     for (
auto& 
i : iter) {
 
 1344                         size_t totalSize = 0L;
 
 1345                         for (
auto& 
rul : 
i->getRules()) {
 
 1346                             if (
rul.second->getId() == c) {
 
 1347                                 totalSize += 
rul.second->size();
 
 1352                             list.emplace_back(totalSize);
 
 1364         if (c.find(
'.') == std::string::npos) {
 
 1365             std::cout << 
"Rule does not exist";
 
 1370         std::string strRel = 
"R" + part[0].substr(1);
 
 1373         std::printf(
"%6s%2s%s\n\n", (*versionTable.rows[0])[6]->toString(0).c_str(), 
"",
 
 1374                 (*versionTable.rows[0])[5]->toString(0).c_str());
 
 1375         if (col == 
"tot_t") {
 
 1376             std::vector<std::chrono::microseconds> list;
 
 1377             for (
auto& row : versionTable.rows) {
 
 1378                 list.emplace_back((*row)[0]->getTimeVal());
 
 1382         } 
else if (col == 
"copy_t") {
 
 1383             std::vector<std::chrono::microseconds> list;
 
 1384             for (
auto& row : versionTable.rows) {
 
 1385                 list.emplace_back((*row)[3]->getTimeVal());
 
 1389         } 
else if (col == 
"tuples") {
 
 1390             std::vector<size_t> list;
 
 1391             for (
auto& row : versionTable.rows) {
 
 1392                 list.emplace_back((*row)[4]->getLongVal());
 
 1400         std::chrono::microseconds max{};
 
 1401         for (
auto& 
d : list) {
 
 1407         std::sort(list.begin(), list.end());
 
 1408         std::reverse(list.begin(), list.end());
 
 1410         for (
auto& 
d : list) {
 
 1411             uint32_t len = 67.0 * 
d.count() / max.count();
 
 1412             std::string bar = 
"";
 
 1413             for (uint32_t 
j = 0; 
j < len; 
j++) {
 
 1417             std::printf(
"%4d %10.8f | %s\n", 
i++, (
d.count() / 1000000.0), bar.c_str());
 
 1423         for (
auto& 
l : list) {
 
 1428         std::sort(list.begin(), list.end());
 
 1429         std::reverse(list.begin(), list.end());
 
 1431         for (
auto& 
l : list) {
 
 1432             size_t len = max == 0 ? 0 : 64.0 * 
l / max;
 
 1433             std::string bar = 
"";
 
 1434             for (uint32_t 
j = 0; 
j < len; 
j++) {
 
 1443     void verAtoms(Table& atomTable, 
const std::string& ruleName = 
"") {
 
 1446         if (atomTable.rows.empty()) {
 
 1449         bool firstRun = 
true;
 
 1450         std::string lastRule = ruleName;
 
 1451         for (
auto& _row : atomTable.rows) {
 
 1454             if (
rule != lastRule) {
 
 1456                 std::cout << 
"     " << row[0]->toString(
precision) << std::endl;
 
 1460                 std::printf(
"      %-16s%-16s%s\n", 
"FREQ", 
"RELSIZE", 
"ATOM");
 
 1463             std::string relationName = row[1]->getStringVal();
 
 1464             relationName = relationName.substr(0, relationName.find(
'('));
 
 1466             std::string relationSize = 
relation == 
nullptr ? 
"--" : std::to_string(
relation->size());
 
 1468                     row[1]->getStringVal().c_str());
 
 1479         struct winsize w {};
 
 1480         ioctl(0, TIOCGWINSZ, &w);
 
 1481         uint32_t width = w.ws_col > 0 ? w.ws_col : 80;