From 1fc2ca179df4379756b2141320c777301f50d0c9 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 27 Jun 2025 10:18:45 +0200 Subject: [PATCH 1/7] fix(table): Improve table printing for ARM architecture Signed-off-by: Steffen Vogel --- common/include/villas/table.hpp | 8 +++-- common/lib/hist.cpp | 6 ++-- common/lib/table.cpp | 54 +++++++++++++++++++++------------ lib/stats.cpp | 24 +++++++-------- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/common/include/villas/table.hpp b/common/include/villas/table.hpp index 555dd3141..1f35c5dd1 100644 --- a/common/include/villas/table.hpp +++ b/common/include/villas/table.hpp @@ -27,11 +27,12 @@ class TableColumn { int _width; // The real width of this column. Calculated by Table::resize(). int width; // Width of the column. + int precision; // Precision of the column, used for floating point values. public: - TableColumn(int w, enum Alignment a, const std::string &t, + TableColumn(int w, int p, enum Alignment a, const std::string &t, const std::string &f, const std::string &u = "") - : _width(0), width(w), title(t), format(f), unit(u), align(a) {} + : _width(0), width(w), precision(p), title(t), format(f), unit(u), align(a) {} std::string title; // The title as shown in the table header. std::string format; // The format which is used to print the table rows. @@ -46,10 +47,11 @@ class Table { protected: int resize(int w); + void updateRowFormat(); int width; - std::vector columns; + std::string rowFormat; Logger logger; diff --git a/common/lib/hist.cpp b/common/lib/hist.cpp index c18c13519..21ca50950 100644 --- a/common/lib/hist.cpp +++ b/common/lib/hist.cpp @@ -129,9 +129,9 @@ void Hist::plot(Logger logger) const { Hist::cnt_t max = *std::max_element(data.begin(), data.end()); std::vector cols = { - {-9, TableColumn::Alignment::RIGHT, "Value", "%+9.3g"}, - {-6, TableColumn::Alignment::RIGHT, "Count", "%6ju"}, - {0, TableColumn::Alignment::LEFT, "Plot", "%s", "occurrences"}}; + {-9, 3, TableColumn::Alignment::RIGHT, "Value", "g"}, + {-6, -1, TableColumn::Alignment::RIGHT, "Count", "ju"}, + {0, -1, TableColumn::Alignment::LEFT, "Plot", "s", "occurrences"}}; Table table = Table(logger, cols); diff --git a/common/lib/table.cpp b/common/lib/table.cpp index 8c1b50002..54f84e13f 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -53,9 +53,40 @@ int Table::resize(int w) { columns[i]._width = -1 * columns[i].width; } + updateRowFormat(); + return 0; } +void Table::updateRowFormat() { + rowFormat.clear(); + + for (unsigned i = 0; i < columns.size(); ++i) { + auto &column = columns[i]; + + rowFormat += " %"; + if (column.align == TableColumn::Alignment::LEFT) { + rowFormat += "-"; + } + + rowFormat += std::to_string(column._width); + + if (column.precision >= 0) { + rowFormat += "."; + rowFormat += std::to_string(column.precision); + } else if (column.format == "s") { + rowFormat += "."; + rowFormat += std::to_string(column._width); + } + + rowFormat += column.format; + + if (i != columns.size() - 1) { + rowFormat += " " BOX_UD; + } + } +} + void Table::header() { if (width != Log::getInstance().getWidth()) resize(Log::getInstance().getWidth()); @@ -112,31 +143,16 @@ void Table::row(int count, ...) { header(); } + char *line; + va_list args; va_start(args, count); - char *line = nullptr; - - for (unsigned i = 0; i < columns.size(); ++i) { - char *col = vstrf(columns[i].format.c_str(), args); - - int l = strlenp(col); - int r = strlen(col); - int w = columns[i]._width + r - l; - - if (columns[i].align == TableColumn::Alignment::LEFT) - strcatf(&line, " %-*.*s " ANSI_RESET, w, w, col); - else - strcatf(&line, " %*.*s " ANSI_RESET, w, w, col); - - if (i != columns.size() - 1) - strcatf(&line, BOX_UD); - - free(col); - } + vasprintf(&line, rowFormat.c_str(), args); va_end(args); logger->info("{}", line); + free(line); } diff --git a/lib/stats.cpp b/lib/stats.cpp index 7a0aa780c..1337f9640 100644 --- a/lib/stats.cpp +++ b/lib/stats.cpp @@ -51,18 +51,18 @@ std::unordered_map Stats::types = { {Stats::Type::TOTAL, {"total", SignalType::INTEGER}}}; std::vector Stats::columns = { - {10, TableColumn::Alignment::LEFT, "Node", "%s"}, - {10, TableColumn::Alignment::RIGHT, "Recv", "%ju", "pkts"}, - {10, TableColumn::Alignment::RIGHT, "Sent", "%ju", "pkts"}, - {10, TableColumn::Alignment::RIGHT, "Drop", "%ju", "pkts"}, - {10, TableColumn::Alignment::RIGHT, "Skip", "%ju", "pkts"}, - {10, TableColumn::Alignment::RIGHT, "OWD last", "%lf", "secs"}, - {10, TableColumn::Alignment::RIGHT, "OWD mean", "%lf", "secs"}, - {10, TableColumn::Alignment::RIGHT, "Rate last", "%lf", "pkt/sec"}, - {10, TableColumn::Alignment::RIGHT, "Rate mean", "%lf", "pkt/sec"}, - {10, TableColumn::Alignment::RIGHT, "Age mean", "%lf", "secs"}, - {10, TableColumn::Alignment::RIGHT, "Age Max", "%lf", "sec"}, - {8, TableColumn::Alignment::RIGHT, "Signals", "%ju", "signals"}}; + {10, -1, TableColumn::Alignment::LEFT, "Node", "s"}, + {10, -1, TableColumn::Alignment::RIGHT, "Recv", "ju", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "Sent", "ju", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "Drop", "ju", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "Skip", "ju", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "OWD last", "lf", "secs"}, + {10, -1, TableColumn::Alignment::RIGHT, "OWD mean", "lf", "secs"}, + {10, -1, TableColumn::Alignment::RIGHT, "Rate last", "lf", "pkt/sec"}, + {10, -1, TableColumn::Alignment::RIGHT, "Rate mean", "lf", "pkt/sec"}, + {10, -1, TableColumn::Alignment::RIGHT, "Age mean", "lf", "secs"}, + {10, -1, TableColumn::Alignment::RIGHT, "Age Max", "lf", "sec"}, + {8, -1, TableColumn::Alignment::RIGHT, "Signals", "ju", "signals"}}; enum Stats::Format Stats::lookupFormat(const std::string &str) { if (str == "human") From cd87bf4583fac903f9ccbf8a11eac8e057a174a3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 27 Jun 2025 10:18:57 +0200 Subject: [PATCH 2/7] fix(stats,table): Improve table rendering Signed-off-by: Steffen Vogel --- common/include/villas/log.hpp | 2 +- common/lib/log.cpp | 13 +++-- common/lib/table.cpp | 90 +++++++++++++++++++---------------- lib/stats.cpp | 2 +- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/common/include/villas/log.hpp b/common/include/villas/log.hpp index 7859e24f2..6e0acc57a 100644 --- a/common/include/villas/log.hpp +++ b/common/include/villas/log.hpp @@ -54,7 +54,7 @@ class Log { Log(Level level = Level::info); // Get the real usable log output width which fits into one line. - int getWidth(); + static int getWidth(); void parse(json_t *json); diff --git a/common/lib/log.cpp b/common/lib/log.cpp index c1536b6e1..1d919e197 100644 --- a/common/lib/log.cpp +++ b/common/lib/log.cpp @@ -57,10 +57,15 @@ Log::Log(Level lvl) : level(lvl), pattern("%H:%M:%S %^%-4t%$ %-16n %v") { } int Log::getWidth() { - int width = Terminal::getCols() - 50; - - if (!prefix.empty()) - width -= prefix.length(); + int width = Terminal::getCols(); + + width -= 8; // Timestamp + width -= 1; // Space + width -= 4; // Level + width -= 1; // Space + width -= 16; // Name + width -= 1; // Space + width -= getInstance().prefix.length(); return width; } diff --git a/common/lib/table.cpp b/common/lib/table.cpp index 54f84e13f..3e17f42c4 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -25,32 +25,48 @@ using namespace villas::utils; #endif int Table::resize(int w) { - int norm, flex, fixed, total; - width = w; - norm = 0; - flex = 0; - fixed = 0; - total = width - columns.size() * 2; + float norm = 0; + float flex = 0; + float fixed = 0; + float total = width - columns.size() * 3; // Column separators and whitespace // Normalize width - for (unsigned i = 0; i < columns.size(); i++) { - if (columns[i].width > 0) - norm += columns[i].width; - if (columns[i].width == 0) + for (auto &column: columns) { + if (column.width > 0) { + norm += column.width; + } else if (column.width == 0) { flex++; - if (columns[i].width < 0) - fixed += -1 * columns[i].width; + } else if (column.width < 0) { + fixed += -1 * column.width; + } } - for (unsigned i = 0; i < columns.size(); i++) { - if (columns[i].width > 0) - columns[i]._width = columns[i].width * (float)(total - fixed) / norm; - if (columns[i].width == 0) - columns[i]._width = (float)(total - fixed) / flex; - if (columns[i].width < 0) - columns[i]._width = -1 * columns[i].width; + int total_used = 0; + + for (auto &column: columns) { + if (column.width > 0) { + column._width = column.width * (total - fixed) / norm; + } else if (column.width == 0){ + column._width = (total - fixed) / flex; + } else if (column.width < 0) { + column._width = -1 * column.width; + } + + total_used += column._width; + } + + // Distribute remaining space over flex columns + for (auto &column: columns) { + if (total_used >= total) { + break; + } + + if (column.width >= 0) { + column._width++; + total_used++; + } } updateRowFormat(); @@ -88,33 +104,27 @@ void Table::updateRowFormat() { } void Table::header() { - if (width != Log::getInstance().getWidth()) - resize(Log::getInstance().getWidth()); + auto logWidth = Log::getWidth(); + if (width != logWidth) { + resize(logWidth); + } char *line1 = nullptr; char *line2 = nullptr; char *line3 = nullptr; for (unsigned i = 0; i < columns.size(); i++) { - int w, u; - char *col, *unit; - - col = strf(CLR_BLD("%s"), columns[i].title.c_str()); - unit = columns[i].unit.size() ? strf(CLR_YEL("%s"), columns[i].unit.c_str()) - : strf(""); - - w = columns[i]._width + strlen(col) - strlenp(col); - u = columns[i]._width + strlen(unit) - strlenp(unit); + auto &column = columns[i]; - if (columns[i].align == TableColumn::Alignment::LEFT) { - strcatf(&line1, " %-*.*s" ANSI_RESET, w, w, col); - strcatf(&line2, " %-*.*s" ANSI_RESET, u, u, unit); + if (column.align == TableColumn::Alignment::LEFT) { + strcatf(&line1, CLR_BLD(" %*.*s") ANSI_RESET, column._width, column._width, column.title.c_str()); + strcatf(&line2, CLR_YEL(" %*.*s") ANSI_RESET, column._width, column._width, column.unit.empty() ? "" : column.unit.c_str()); } else { - strcatf(&line1, " %*.*s" ANSI_RESET, w, w, col); - strcatf(&line2, " %*.*s" ANSI_RESET, u, u, unit); + strcatf(&line1, CLR_BLD(" %-*.*s") ANSI_RESET, column._width, column._width, column.title.c_str()); + strcatf(&line2, CLR_YEL(" %-*.*s") ANSI_RESET, column._width, column._width, column.unit.empty() ? "" : column.unit.c_str()); } - for (int j = 0; j < columns[i]._width + 2; j++) { + for (int j = 0; j < column._width + 2; j++) { strcatf(&line3, "%s", BOX_LR); } @@ -123,9 +133,6 @@ void Table::header() { strcatf(&line2, " %s", BOX_UD); strcatf(&line3, "%s", BOX_UDLR); } - - free(col); - free(unit); } logger->info("{}", line1); @@ -138,8 +145,9 @@ void Table::header() { } void Table::row(int count, ...) { - if (width != Log::getInstance().getWidth()) { - resize(Log::getInstance().getWidth()); + auto logWidth = Log::getWidth(); + if (width != logWidth) { + resize(logWidth); header(); } diff --git a/lib/stats.cpp b/lib/stats.cpp index 1337f9640..00b0d4639 100644 --- a/lib/stats.cpp +++ b/lib/stats.cpp @@ -62,7 +62,7 @@ std::vector Stats::columns = { {10, -1, TableColumn::Alignment::RIGHT, "Rate mean", "lf", "pkt/sec"}, {10, -1, TableColumn::Alignment::RIGHT, "Age mean", "lf", "secs"}, {10, -1, TableColumn::Alignment::RIGHT, "Age Max", "lf", "sec"}, - {8, -1, TableColumn::Alignment::RIGHT, "Signals", "ju", "signals"}}; + {-7, -1, TableColumn::Alignment::RIGHT, "Signals", "ju", "signals"}}; enum Stats::Format Stats::lookupFormat(const std::string &str) { if (str == "human") From a43399fb8862bd4aedd3768162c1ee08ed7d6e1e Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 27 Jun 2025 10:19:50 +0200 Subject: [PATCH 3/7] fix(config): Make example config for stats hook more useful Signed-off-by: Steffen Vogel --- etc/examples/hooks/stats.conf | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/etc/examples/hooks/stats.conf b/etc/examples/hooks/stats.conf index 983498f1a..53142e269 100644 --- a/etc/examples/hooks/stats.conf +++ b/etc/examples/hooks/stats.conf @@ -1,28 +1,31 @@ # SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University # SPDX-License-Identifier: Apache-2.0 +stats = 1 + nodes = { - udp_node = { - type = "socket" + signal_node = { + type = "signal" + signal = "mixed" + values = 5 + rate = 50 in = { - address = "*:12000" - hooks = ( { type = "stats" verbose = true - warmup = 100 + warmup = 10 buckets = 25 - - output = "stats.log" - format = "json" } ) } - out = { - address = "127.0.0.1:12000" - } } } + +paths = ( + { + in = "signal_node" + } +) From e24fb7db36e2ec450d1425827c9c0d644bbda71a Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 27 Jun 2025 14:06:32 +0200 Subject: [PATCH 4/7] fix(table): Avoid allocations Signed-off-by: Steffen Vogel --- common/include/villas/table.hpp | 13 +++++- common/lib/hist.cpp | 4 +- common/lib/table.cpp | 71 +++++++++------------------------ lib/stats.cpp | 24 +++++------ 4 files changed, 45 insertions(+), 67 deletions(-) diff --git a/common/include/villas/table.hpp b/common/include/villas/table.hpp index 1f35c5dd1..b3296c100 100644 --- a/common/include/villas/table.hpp +++ b/common/include/villas/table.hpp @@ -10,6 +10,8 @@ #include #include +#include + #include namespace villas { @@ -63,7 +65,16 @@ class Table { void header(); // Print table rows. - void row(int count, ...); + template + void row(const Args&... args) { + auto logWidth = Log::getWidth(); + if (width != logWidth) { + resize(logWidth); + header(); + } + + logger->info(rowFormat, args...); + } int getWidth() const { return width; } }; diff --git a/common/lib/hist.cpp b/common/lib/hist.cpp index 21ca50950..de1a2278e 100644 --- a/common/lib/hist.cpp +++ b/common/lib/hist.cpp @@ -130,7 +130,7 @@ void Hist::plot(Logger logger) const { std::vector cols = { {-9, 3, TableColumn::Alignment::RIGHT, "Value", "g"}, - {-6, -1, TableColumn::Alignment::RIGHT, "Count", "ju"}, + {-6, -1, TableColumn::Alignment::RIGHT, "Count", "d"}, {0, -1, TableColumn::Alignment::LEFT, "Plot", "s", "occurrences"}}; Table table = Table(logger, cols); @@ -147,7 +147,7 @@ void Hist::plot(Logger logger) const { for (int i = 0; i < bar; i++) buf = strcatf(&buf, "\u2588"); - table.row(3, value, cnt, buf); + table.row(value, cnt, buf); free(buf); } diff --git a/common/lib/table.cpp b/common/lib/table.cpp index 3e17f42c4..883eff989 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -80,25 +80,21 @@ void Table::updateRowFormat() { for (unsigned i = 0; i < columns.size(); ++i) { auto &column = columns[i]; - rowFormat += " %"; - if (column.align == TableColumn::Alignment::LEFT) { - rowFormat += "-"; - } - + rowFormat += " {:" ; + rowFormat += column.align == TableColumn::Alignment::LEFT ? "<" : ">"; rowFormat += std::to_string(column._width); if (column.precision >= 0) { - rowFormat += "."; - rowFormat += std::to_string(column.precision); + rowFormat += fmt::format(".{}", column.precision); } else if (column.format == "s") { - rowFormat += "."; - rowFormat += std::to_string(column._width); + rowFormat += fmt::format(".{}", column._width); } rowFormat += column.format; + rowFormat += "}"; if (i != columns.size() - 1) { - rowFormat += " " BOX_UD; + rowFormat += "} " BOX_UD; } } } @@ -109,58 +105,29 @@ void Table::header() { resize(logWidth); } - char *line1 = nullptr; - char *line2 = nullptr; - char *line3 = nullptr; + std::string line1; + std::string line2; + std::string line3; for (unsigned i = 0; i < columns.size(); i++) { auto &column = columns[i]; - if (column.align == TableColumn::Alignment::LEFT) { - strcatf(&line1, CLR_BLD(" %*.*s") ANSI_RESET, column._width, column._width, column.title.c_str()); - strcatf(&line2, CLR_YEL(" %*.*s") ANSI_RESET, column._width, column._width, column.unit.empty() ? "" : column.unit.c_str()); - } else { - strcatf(&line1, CLR_BLD(" %-*.*s") ANSI_RESET, column._width, column._width, column.title.c_str()); - strcatf(&line2, CLR_YEL(" %-*.*s") ANSI_RESET, column._width, column._width, column.unit.empty() ? "" : column.unit.c_str()); - } + auto leftAligned = column.align == TableColumn::Alignment::LEFT; + line1 += fmt::format(leftAligned ? CLR_BLD(" {0:<{1}.{1}s}") : CLR_BLD(" {0:>{1}.{1}s}"), column.title, column._width); + line2 += fmt::format(leftAligned ? CLR_YEL(" {0:<{1}.{1}s}") : CLR_YEL(" {0:>{1}.{1}s}"), column.unit, column._width); for (int j = 0; j < column._width + 2; j++) { - strcatf(&line3, "%s", BOX_LR); + line3 += BOX_LR; } if (i != columns.size() - 1) { - strcatf(&line1, " %s", BOX_UD); - strcatf(&line2, " %s", BOX_UD); - strcatf(&line3, "%s", BOX_UDLR); + line1 += " " BOX_UD; + line2 += " " BOX_UD; + line3 += BOX_UDLR; } } - logger->info("{}", line1); - logger->info("{}", line2); - logger->info("{}", line3); - - free(line1); - free(line2); - free(line3); -} - -void Table::row(int count, ...) { - auto logWidth = Log::getWidth(); - if (width != logWidth) { - resize(logWidth); - header(); - } - - char *line; - - va_list args; - va_start(args, count); - - vasprintf(&line, rowFormat.c_str(), args); - - va_end(args); - - logger->info("{}", line); - - free(line); + logger->info(line1); + logger->info(line2); + logger->info(line3); } diff --git a/lib/stats.cpp b/lib/stats.cpp index 00b0d4639..569e7f5bb 100644 --- a/lib/stats.cpp +++ b/lib/stats.cpp @@ -52,17 +52,17 @@ std::unordered_map Stats::types = { std::vector Stats::columns = { {10, -1, TableColumn::Alignment::LEFT, "Node", "s"}, - {10, -1, TableColumn::Alignment::RIGHT, "Recv", "ju", "pkts"}, - {10, -1, TableColumn::Alignment::RIGHT, "Sent", "ju", "pkts"}, - {10, -1, TableColumn::Alignment::RIGHT, "Drop", "ju", "pkts"}, - {10, -1, TableColumn::Alignment::RIGHT, "Skip", "ju", "pkts"}, - {10, -1, TableColumn::Alignment::RIGHT, "OWD last", "lf", "secs"}, - {10, -1, TableColumn::Alignment::RIGHT, "OWD mean", "lf", "secs"}, - {10, -1, TableColumn::Alignment::RIGHT, "Rate last", "lf", "pkt/sec"}, - {10, -1, TableColumn::Alignment::RIGHT, "Rate mean", "lf", "pkt/sec"}, - {10, -1, TableColumn::Alignment::RIGHT, "Age mean", "lf", "secs"}, - {10, -1, TableColumn::Alignment::RIGHT, "Age Max", "lf", "sec"}, - {-7, -1, TableColumn::Alignment::RIGHT, "Signals", "ju", "signals"}}; + {10, -1, TableColumn::Alignment::RIGHT, "Recv", "d", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "Sent", "d", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "Drop", "d", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "Skip", "d", "pkts"}, + {10, -1, TableColumn::Alignment::RIGHT, "OWD last", "f", "secs"}, + {10, -1, TableColumn::Alignment::RIGHT, "OWD mean", "f", "secs"}, + {10, -1, TableColumn::Alignment::RIGHT, "Rate last", "f", "pkt/sec"}, + {10, -1, TableColumn::Alignment::RIGHT, "Rate mean", "f", "pkt/sec"}, + {10, -1, TableColumn::Alignment::RIGHT, "Age mean", "f", "secs"}, + {10, -1, TableColumn::Alignment::RIGHT, "Age Max", "f", "sec"}, + {-7, -1, TableColumn::Alignment::RIGHT, "Signals", "d", "signals"}}; enum Stats::Format Stats::lookupFormat(const std::string &str) { if (str == "human") @@ -142,7 +142,7 @@ void Stats::printPeriodic(FILE *f, enum Format fmt, node::Node *n) const { switch (fmt) { case Format::HUMAN: setupTable(); - table->row(11, n->getNameShort().c_str(), + table->row(n->getNameShort(), (uintmax_t)histograms.at(Metric::OWD).getTotal(), (uintmax_t)histograms.at(Metric::AGE).getTotal(), (uintmax_t)histograms.at(Metric::SMPS_REORDERED).getTotal(), From dbd4f5acc2811bc7e436d7471f896b45cfb0a6d1 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 9 Jul 2025 12:45:27 +0200 Subject: [PATCH 5/7] fix(lint): Format code with clang-format Signed-off-by: Steffen Vogel --- common/include/villas/table.hpp | 8 ++++---- common/lib/log.cpp | 10 +++++----- common/lib/table.cpp | 18 +++++++++++------- lib/stats.cpp | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/common/include/villas/table.hpp b/common/include/villas/table.hpp index b3296c100..2274181be 100644 --- a/common/include/villas/table.hpp +++ b/common/include/villas/table.hpp @@ -28,13 +28,14 @@ class TableColumn { protected: int _width; // The real width of this column. Calculated by Table::resize(). - int width; // Width of the column. + int width; // Width of the column. int precision; // Precision of the column, used for floating point values. public: TableColumn(int w, int p, enum Alignment a, const std::string &t, const std::string &f, const std::string &u = "") - : _width(0), width(w), precision(p), title(t), format(f), unit(u), align(a) {} + : _width(0), width(w), precision(p), title(t), format(f), unit(u), + align(a) {} std::string title; // The title as shown in the table header. std::string format; // The format which is used to print the table rows. @@ -65,8 +66,7 @@ class Table { void header(); // Print table rows. - template - void row(const Args&... args) { + template void row(const Args &...args) { auto logWidth = Log::getWidth(); if (width != logWidth) { resize(logWidth); diff --git a/common/lib/log.cpp b/common/lib/log.cpp index 1d919e197..b8d9716dc 100644 --- a/common/lib/log.cpp +++ b/common/lib/log.cpp @@ -59,12 +59,12 @@ Log::Log(Level lvl) : level(lvl), pattern("%H:%M:%S %^%-4t%$ %-16n %v") { int Log::getWidth() { int width = Terminal::getCols(); - width -= 8; // Timestamp - width -= 1; // Space - width -= 4; // Level - width -= 1; // Space + width -= 8; // Timestamp + width -= 1; // Space + width -= 4; // Level + width -= 1; // Space width -= 16; // Name - width -= 1; // Space + width -= 1; // Space width -= getInstance().prefix.length(); return width; diff --git a/common/lib/table.cpp b/common/lib/table.cpp index 883eff989..a0c9673d8 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -33,7 +33,7 @@ int Table::resize(int w) { float total = width - columns.size() * 3; // Column separators and whitespace // Normalize width - for (auto &column: columns) { + for (auto &column : columns) { if (column.width > 0) { norm += column.width; } else if (column.width == 0) { @@ -45,10 +45,10 @@ int Table::resize(int w) { int total_used = 0; - for (auto &column: columns) { + for (auto &column : columns) { if (column.width > 0) { column._width = column.width * (total - fixed) / norm; - } else if (column.width == 0){ + } else if (column.width == 0) { column._width = (total - fixed) / flex; } else if (column.width < 0) { column._width = -1 * column.width; @@ -58,7 +58,7 @@ int Table::resize(int w) { } // Distribute remaining space over flex columns - for (auto &column: columns) { + for (auto &column : columns) { if (total_used >= total) { break; } @@ -80,7 +80,7 @@ void Table::updateRowFormat() { for (unsigned i = 0; i < columns.size(); ++i) { auto &column = columns[i]; - rowFormat += " {:" ; + rowFormat += " {:"; rowFormat += column.align == TableColumn::Alignment::LEFT ? "<" : ">"; rowFormat += std::to_string(column._width); @@ -113,8 +113,12 @@ void Table::header() { auto &column = columns[i]; auto leftAligned = column.align == TableColumn::Alignment::LEFT; - line1 += fmt::format(leftAligned ? CLR_BLD(" {0:<{1}.{1}s}") : CLR_BLD(" {0:>{1}.{1}s}"), column.title, column._width); - line2 += fmt::format(leftAligned ? CLR_YEL(" {0:<{1}.{1}s}") : CLR_YEL(" {0:>{1}.{1}s}"), column.unit, column._width); + line1 += fmt::format(leftAligned ? CLR_BLD(" {0:<{1}.{1}s}") + : CLR_BLD(" {0:>{1}.{1}s}"), + column.title, column._width); + line2 += fmt::format(leftAligned ? CLR_YEL(" {0:<{1}.{1}s}") + : CLR_YEL(" {0:>{1}.{1}s}"), + column.unit, column._width); for (int j = 0; j < column._width + 2; j++) { line3 += BOX_LR; diff --git a/lib/stats.cpp b/lib/stats.cpp index 569e7f5bb..c92d3da05 100644 --- a/lib/stats.cpp +++ b/lib/stats.cpp @@ -62,7 +62,7 @@ std::vector Stats::columns = { {10, -1, TableColumn::Alignment::RIGHT, "Rate mean", "f", "pkt/sec"}, {10, -1, TableColumn::Alignment::RIGHT, "Age mean", "f", "secs"}, {10, -1, TableColumn::Alignment::RIGHT, "Age Max", "f", "sec"}, - {-7, -1, TableColumn::Alignment::RIGHT, "Signals", "d", "signals"}}; + {-7, -1, TableColumn::Alignment::RIGHT, "Signals", "d", "signals"}}; enum Stats::Format Stats::lookupFormat(const std::string &str) { if (str == "human") From 3c999f71f0cf6b037d51ba7218b942d1afdacbd3 Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Wed, 16 Jul 2025 08:57:36 +0200 Subject: [PATCH 6/7] fix: remove unecessary } in format string in table.cpp Signed-off-by: Niklas Eiling --- common/lib/table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/lib/table.cpp b/common/lib/table.cpp index a0c9673d8..203c8a25b 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -94,7 +94,7 @@ void Table::updateRowFormat() { rowFormat += "}"; if (i != columns.size() - 1) { - rowFormat += "} " BOX_UD; + rowFormat += BOX_UD; } } } From 8207491219fc73e2132cdabf3b3674c0b116295b Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Wed, 16 Jul 2025 09:07:27 +0200 Subject: [PATCH 7/7] fix: improve compatiblity of villas::utils::Table with newer C++ standards Co-authored-by: Philipp Jungkamp Signed-off-by: Niklas Eiling --- common/include/villas/log.hpp | 2 +- common/include/villas/table.hpp | 4 ++-- common/lib/log.cpp | 2 +- common/lib/table.cpp | 11 +++++++---- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/common/include/villas/log.hpp b/common/include/villas/log.hpp index 6e0acc57a..7859e24f2 100644 --- a/common/include/villas/log.hpp +++ b/common/include/villas/log.hpp @@ -54,7 +54,7 @@ class Log { Log(Level level = Level::info); // Get the real usable log output width which fits into one line. - static int getWidth(); + int getWidth(); void parse(json_t *json); diff --git a/common/include/villas/table.hpp b/common/include/villas/table.hpp index 2274181be..5ef77ec81 100644 --- a/common/include/villas/table.hpp +++ b/common/include/villas/table.hpp @@ -67,13 +67,13 @@ class Table { // Print table rows. template void row(const Args &...args) { - auto logWidth = Log::getWidth(); + auto logWidth = Log::getInstance().getWidth(); if (width != logWidth) { resize(logWidth); header(); } - logger->info(rowFormat, args...); + logger->info(fmt::runtime(rowFormat), args...); } int getWidth() const { return width; } diff --git a/common/lib/log.cpp b/common/lib/log.cpp index b8d9716dc..572a5065a 100644 --- a/common/lib/log.cpp +++ b/common/lib/log.cpp @@ -65,7 +65,7 @@ int Log::getWidth() { width -= 1; // Space width -= 16; // Name width -= 1; // Space - width -= getInstance().prefix.length(); + width -= prefix.length(); return width; } diff --git a/common/lib/table.cpp b/common/lib/table.cpp index 203c8a25b..eb727366f 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -100,7 +100,7 @@ void Table::updateRowFormat() { } void Table::header() { - auto logWidth = Log::getWidth(); + auto logWidth = Log::getInstance().getWidth(); if (width != logWidth) { resize(logWidth); } @@ -108,6 +108,9 @@ void Table::header() { std::string line1; std::string line2; std::string line3; + line1.reserve(width); + line2.reserve(width); + line3.reserve(width); for (unsigned i = 0; i < columns.size(); i++) { auto &column = columns[i]; @@ -131,7 +134,7 @@ void Table::header() { } } - logger->info(line1); - logger->info(line2); - logger->info(line3); + logger->info("{}", line1); + logger->info("{}", line2); + logger->info("{}", line3); }