From nobody Tue Jul 28 19:29:22 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h8lry36JJz6n9ZV for ; Tue, 28 Jul 2026 19:29:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h8lry2YQFz43v5 for ; Tue, 28 Jul 2026 19:29:22 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785266962; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=InPw567OL3HWL+qCFHXCpbjx3IEkB9FLd8wRxWP/s7I=; b=W6gUjy4m29P6qVUWUkwOVg/raR3Ddrl0ETJnUWxEE62R9ugGvEqgCp9wStQ8CZbdTzR1YN JH3+AvKbGnE8kbImWSMxGmjmxJptuxqcgXrSlcNngp6XdJ2r1LqlvW+QPXb4q+K0wJtFW7 13ZGKhijGsyRtWpm7HAHqREKRuj1FLz6mtce8zzY1zB57sOVAa3Q+DnDjIZpMr4nQPwcON aQgpap89BB7Ng2/diO3k0gHkQFDUthESElT9WfTS5lxK1jbUTGOUPDkXHC4QrSHmeAMV/C fWlZKryldCseFdZAd0QaFXk6f8cyblL35eAaOx5she9CSRCUI83QdJgxOOLWDQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1785266962; a=rsa-sha256; cv=none; b=CyIvW7iulPyXUDKqde4iSU0wxLAET2hVFqWnF3H0wCzx45IbMBa9gBD6DhAk3mtja/oZeH gyfaOnnqHpoSLWfFbcyk+vgz/9TulvBNCHdWuSsliSbiLb+evo47t5IbWV2UUyKD2NvGwz mx2KZCqxFZsk+vBHk51C61ySGb9x8Vrh92Z+F0JtPwY8YUG0VBLe5dCQUWYdqhwsQJf7Jr cbaQ6CHrfiuW9Uk6G4xzN8HLUHm27wuACVoUao0CCnu9N7Eh1eYLXTi/qqxNLlH/ihhQT4 iKl19vbt0Qq87r+iKgPxp/XFICCsmmj29LXqMQx6pH7CJdPOX3foDdgmKBT4cw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785266962; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=InPw567OL3HWL+qCFHXCpbjx3IEkB9FLd8wRxWP/s7I=; b=a+WvjDuSDLzV0HjiR0oDdRDOEZyKLAbKJPAyJzkhG35ioiSixVcwykbGpxEkcIY0+a45ZQ HM/8umsfa59WPk7B+MBYO1eOIcr3ULLEkAuauQSGnQojtiy+o36Ft0U/1VSUM/+iPu90a4 xSNLF3KJFYh68WJW3m5YXM5/G86tZwWssIgMEmPnQFuVIn2zAK43hsBpHad1VqOLPhqhSe fzQdTDu4eWehbFkzmV/dVxvrDKNFQXP3tXA3YVrpipdSbhuSKEWzve8p4eu4ARynC25q1g jMsrjYP362E5Lbdq9HJHjHer2KWlgFszlw/479Z89afpgu/JVbzzzpqPwxIrXg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h8lry10YxztJD for ; Tue, 28 Jul 2026 19:29:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 43502 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 28 Jul 2026 19:29:22 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Ali Mashtizadeh From: Warner Losh Subject: git: a53d2e4f5db5 - main - pmc: console configuration and table rendering for new PMC tools List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a53d2e4f5db588cfd59cdebf04536b6ca7a70e4b Auto-Submitted: auto-generated Date: Tue, 28 Jul 2026 19:29:22 +0000 Message-Id: <6a690312.43502.47493578@gitrepo.freebsd.org> The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=a53d2e4f5db588cfd59cdebf04536b6ca7a70e4b commit a53d2e4f5db588cfd59cdebf04536b6ca7a70e4b Author: Ali Mashtizadeh AuthorDate: 2026-07-28 17:46:14 +0000 Commit: Warner Losh CommitDate: 2026-07-28 19:27:44 +0000 pmc: console configuration and table rendering for new PMC tools Initializes the terminal rendering code used by the new pmc tools. Then provides a table abstraction for collecting, sorting and rendering tables. It provides pretty printed results with typed fields that print several types used throughout the new PMC tools. By default the fields are formatted in engineering notation. Sponsored by: Netflix Reviewed by: adrian, imp Differential Revision: https://reviews.freebsd.org/D57775 --- usr.sbin/pmc/display.cc | 571 ++++++++++++++++++++++++++++++++++++++++++++++++ usr.sbin/pmc/display.hh | 105 +++++++++ 2 files changed, 676 insertions(+) diff --git a/usr.sbin/pmc/display.cc b/usr.sbin/pmc/display.cc new file mode 100644 index 000000000000..454cb74e29bd --- /dev/null +++ b/usr.sbin/pmc/display.cc @@ -0,0 +1,571 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026, Netflix, Inc. + * + * This software was developed by Ali Mashtizadeh under the sponsorship from + * Netflix, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "display.hh" + +enum termmode { + TERMMODE_BASIC, + TERMMODE_VT, + TERMMODE_XTERM +}; + +static termmode tmode; +static int disp_height; +static int disp_width; + +#define TITLE_TITLE 0 +#define TITLE_SUBTITLE 1 + +static const char **title_char; + +static const char *title_vt[] = { + "\xe2\x95\x90", "\xe2\x94\x80" +}; +static const char *title_basic[] = { "=", "-" }; + +#define ARROW_DOWN 0 +#define ARROW_UP 1 + +static const char **arrow_char; + +static const char *arrow_vt[] = { + "\xe2\x96\xbc", "\xe2\x96\xb2" +}; +static const char *arrow_basic[] = { "D", "U" }; + +#define BORDER_HBAR 0 +#define BORDER_VBAR 1 +#define BORDER_TOPRIGHT 2 +#define BORDER_TOPLEFT 3 +#define BORDER_BOTTOMLEFT 4 +#define BORDER_BOTTOMRIGHT 5 +#define BORDER_TOPSPLIT 6 +#define BORDER_BOTTOMSPLIT 7 +#define BORDER_RIGHTSPLIT 8 +#define BORDER_LEFTSPLIT 9 +#define BORDER_CROSS 10 + +static const char **border_char; + +static const char *border_vt[] = { + "\xe2\x94\x80", "\xe2\x94\x82", + "\xe2\x94\x8c", "\xe2\x94\x90", "\xe2\x94\x94", "\xe2\x94\x98", + "\xe2\x94\xac", "\xe2\x94\xb4", "\xe2\x94\xa4", "\xe2\x94\x9c", + "\xe2\x94\xbc" +}; +static const char *border_basic[] = { "-", "|", "+", "+", "+", "+", "+", "+", "+", "+" }; + +static char tc_boldbuf[16]; +static char tc_sgr0buf[16]; +static char tc_afbuf[16]; +static char tc_green[16]; +static char tc_yellow[16]; +static char tc_red[16]; + +static const char *TC_BOLD; +static const char *TC_SGR0; +static const char *TC_SETAF; + +void +tcemit(const char *c) +{ + if (c) + tputs(c, 1, putchar); +} + +void +tcfg(int n) +{ + if (TC_SETAF) + tputs(tgoto(TC_SETAF, 0, n), 1, putchar); +} + +static void +setup_termcap(const char *term) +{ + bool xcolor; + char *buf; + char *clicolor; + char termcapbuf[4096]; + + if (tgetent(termcapbuf, "xterm-256color") != 1) { + TC_BOLD = NULL; + TC_SGR0 = NULL; + TC_SETAF = NULL; + return; + } + + buf = tc_boldbuf; + TC_BOLD = tgetstr("md", &buf); + buf = tc_sgr0buf; + TC_SGR0 = tgetstr("me", &buf); + buf = tc_afbuf; + TC_SETAF = tgetstr("AF", &buf); + + clicolor = getenv("CLICOLOR"); + if (clicolor == NULL || strcmp(clicolor, "1") != 0) { + return; + } + + if (strcmp(term, "xterm-256color") == 0) { + xcolor = true; + } else { + xcolor = false; + } + + buf = tgoto(TC_SETAF, 1, xcolor ? COLOR256_GREEN : COLOR_GREEN); + if (buf) { + strlcpy(tc_green, buf, sizeof(tc_green)); + } else { + tc_green[0] = '\0'; + } + + buf = tgoto(TC_SETAF, 1, xcolor ? COLOR256_YELLOW : COLOR_YELLOW); + if (buf) { + strlcpy(tc_yellow, buf, sizeof(tc_yellow)); + } else { + tc_yellow[0] = '\0'; + } + + buf = tgoto(TC_SETAF, 1, xcolor ? COLOR256_RED : COLOR_RED); + if (buf) { + strlcpy(tc_red, buf, sizeof(tc_red)); + } else { + tc_red[0] = '\0'; + } +} + +void +setup_screen() +{ + int status; + const char *term; + struct winsize wsz; + + /* Sane defaults */ + tmode = TERMMODE_BASIC; + title_char = title_basic; + arrow_char = arrow_basic; + border_char = border_basic; + disp_height = 25; + disp_width = 80; + + if (isatty(STDOUT_FILENO) == 0) { + tmode = TERMMODE_XTERM; + title_char = title_vt; + arrow_char = arrow_vt; + border_char = border_vt; + return; + } + + status = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); + if (status < 0) { + perror("ioctl(TIOCGWINSZ)"); + return; + } + + disp_height = wsz.ws_row; + disp_width = wsz.ws_col; + + term = getenv("TERM"); + if (term == NULL) { + tmode = TERMMODE_BASIC; + title_char = title_basic; + arrow_char = arrow_basic; + border_char = border_basic; + return; + } + + if (strncmp(term, "xterm", 5) == 0) { + tmode = TERMMODE_XTERM; + title_char = title_vt; + arrow_char = arrow_vt; + border_char = border_vt; + } else if (strncmp(term, "vt", 2) == 0) { + tmode = TERMMODE_VT; + title_char = title_vt; + arrow_char = arrow_vt; + border_char = border_vt; + } + + setup_termcap(term); +} + +void +title(const std::string &t) +{ + size_t i; + + if (tmode != TERMMODE_BASIC) + tcemit(TC_BOLD); + printf("%s\n", t.c_str()); + if (tmode != TERMMODE_BASIC) + tcemit(TC_SGR0); + for (i = 0; i < t.size(); i++) + printf("%s", title_char[TITLE_TITLE]); + printf("\n\n"); +} + +void +header(const std::string &h) +{ + size_t i; + + if (tmode != TERMMODE_BASIC) + tcemit(TC_BOLD); + printf("%s\n", h.c_str()); + if (tmode != TERMMODE_BASIC) + tcemit(TC_SGR0); + for (i = 0; i < h.size(); i++) + printf("%s", title_char[TITLE_SUBTITLE]); + printf("\n"); +} + +void +printval(const std::string &msg, uint64_t val, siunit ui) +{ + switch (ui) { + case siunit::seconds: + printf("%s: %" PRIu64 " s\n", msg.c_str(), val); + break; + case siunit::percent: + printf("%s: %" PRIu64 "%%\n", msg.c_str(), val); + break; + case siunit::cycles: + printf("%s: %" PRIu64 " cycles\n", msg.c_str(), val); + break; + } +} + +void +printval(const std::string &msg, float val, siunit ui) +{ + switch (ui) { + case siunit::seconds: + printf("%s: %.2f s\n", msg.c_str(), val); + break; + case siunit::percent: + printf("%s: %6.2f%%\n", msg.c_str(), val); + break; + case siunit::cycles: + printf("%s: %.2f cycles\n", msg.c_str(), val); + break; + } +} + +std::string +format_siprefix(uint64_t count) +{ + unsigned long index = 0; + char prefix[] = " kMGTP"; + char buf[10]; + + while (count > 10000 && index < sizeof(prefix)) { + index++; + count /= 1000; + } + + if (index == 0) { + snprintf(buf, sizeof(buf), "%" PRIu64, count); + } else { + snprintf(buf, sizeof(buf), "%" PRIu64 "%c", count, prefix[index]); + } + + return buf; +} + +std::string +format_binprefix(uint64_t count) +{ + unsigned long index = 0; + char prefix[] = " KMGTP"; + char buf[10]; + + while (count > 10000 && index < sizeof(prefix)) { + index++; + count /= 1000; + } + + if (index == 0) { + snprintf(buf, sizeof(buf), "%" PRIu64 " B", count); + } else { + snprintf(buf, sizeof(buf), "%" PRIu64 " %ciB", count, prefix[index]); + } + + return buf; +} + +std::string +format_sample(uint64_t count, uint64_t total) +{ + char buf[20]; + std::string fmt = format_siprefix(count); + + snprintf(buf, sizeof(buf), "%5s (%4.1f%%)", fmt.c_str(), + 100.0 * (float)count / (float)total); + + return buf; +} + +std::string +format_percent(uint64_t count, uint64_t total) +{ + char buf[20]; + + if (total == 0) { + snprintf(buf, sizeof(buf), "%6s", ""); + } else { + snprintf(buf, sizeof(buf), "%5.1f%%", + 100.0 * (float)count / (float)total); + } + + return buf; +} + +/* fields */ + +field::field(int64_t v) +{ + type = FIELD::INTEGER; + value[0] = v; +} + +field::field(float v) +{ + type = FIELD::FLOAT; + fvalue = v; +} + +field::field(const std::string &s) +{ + type = FIELD::STRING; + svalue = s; +} + +field::field(int64_t c, int64_t t, bool percent) +{ + if (percent) + type = FIELD::PERCENT; + else + type = FIELD::SAMPLE; + value[0] = c; + value[1] = t; +} + +field::field(int64_t uc, int64_t ut, int64_t ku, int64_t kt) +{ + type = FIELD::DSAMPLE; + value[0] = uc; + value[1] = ut; + value[2] = ku; + value[3] = kt; +} + +bool +field::operator>(const field &b) const +{ + switch (type) { + case FIELD::STRING: + return (svalue > b.svalue); + case FIELD::FLOAT: + return (fvalue > b.fvalue); + case FIELD::INTEGER: [[fallthrough]]; + case FIELD::SAMPLE: + return (value[0] > b.value[0]); + case FIELD::DSAMPLE: + return ((value[0] + value[2]) > (b.value[0] + b.value[2])); + case FIELD::PERCENT: + return (((float)value[0] / (float)value[1]) > + ((float)b.value[0] / (float)b.value[1])); + } +} + +bool +field::operator<(const field &b) const +{ + switch (type) { + case FIELD::STRING: + return (svalue < b.svalue); + case FIELD::FLOAT: + return (fvalue < b.fvalue); + case FIELD::INTEGER: [[fallthrough]]; + case FIELD::SAMPLE: + return (value[0] < b.value[0]); + case FIELD::DSAMPLE: + return ((value[0] + value[2]) < (b.value[0] + b.value[2])); + case FIELD::PERCENT: + return (((float)value[0] / (float)value[1]) < + ((float)b.value[0] / (float)b.value[1])); + } +} + +size_t +field::length() +{ + return (to_string().length()); +} + +std::string +field::to_string() +{ + switch (type) { + case FIELD::STRING: + return (svalue); + case FIELD::FLOAT: + return (std::to_string(fvalue)); + case FIELD::INTEGER: + return (std::to_string(value[0])); + case FIELD::SAMPLE: + return (format_sample(value[0], value[1])); + case FIELD::DSAMPLE: + return (format_sample(value[0], value[1]) + " / " + + format_sample(value[2], value[3])); + case FIELD::PERCENT: + return (format_percent(value[0], value[1])); + } +} + +/* table class */ + +table::table() : sortcol(-1), sortdir(true), cols(), align(), rows() +{ +} + +table::~table() +{ +} + +void +table::addcolumn(const std::string &c, bool alignleft) +{ + cols.push_back(c); + align.push_back(alignleft); +} + +void +table::addrow(std::vector r) +{ + rows.push_back(std::move(r)); +} + +void +table::sort(int col, bool descending) +{ + sortcol = col; + sortdir = descending; + if (descending) + std::sort(rows.begin(), rows.end(), [col](auto &a, auto &b) + { return (a[col] > b[col]); }); + else + std::sort(rows.begin(), rows.end(), [col](auto &a, auto &b) + { return (a[col] < b[col]); }); +} + +void +table::print() +{ + unsigned long c; + std::vector width; + + // Compute column width + for (auto h : cols) + width.push_back(h.length() + 1); + if (sortcol != -1) + width[sortcol] += 1; + for (auto &r : rows) { + for (c = 0; c < r.size(); c++) { + if (width[c] < r[c].length()) + width[c] = r[c].length(); + } + } + + for (c = 0; c < width.size(); c++) { + if (align[c]) + std::cout << std::left; + std::cout << std::setw(width[c]); + tcemit(TC_BOLD); + if (c == (unsigned long)sortcol) + std::cout << cols[c] + " " + arrow_char[sortdir ? ARROW_DOWN : ARROW_UP]; + else + std::cout << cols[c]; + tcemit(TC_SGR0); + if (c != (width.size() - 1)) + std::cout << " " << border_char[BORDER_VBAR] << " "; + if (align[c]) + std::cout << std::right; + } + std::cout << std::endl; + + for (c = 0; c < width.size(); c++) { + for (unsigned long i = 0; i < width[c]; i++) + std::cout << border_char[BORDER_HBAR]; + if (c != (width.size() - 1)) + std::cout << border_char[BORDER_HBAR] << + border_char[BORDER_CROSS] << border_char[BORDER_HBAR]; + } + std::cout << std::setfill(' ') << std::endl; + + for (auto &r : rows) { + for (c = 0; c < width.size(); c++) { + if (align[c]) + std::cout << std::left; + std::cout << std::setw(width[c]) << r[c].to_string(); + if (c != (width.size() - 1)) + std::cout << " " << border_char[BORDER_VBAR] << " "; + if (align[c]) + std::cout << std::right; + } + std::cout << std::endl; + } + + std::cout << std::endl; +} + diff --git a/usr.sbin/pmc/display.hh b/usr.sbin/pmc/display.hh new file mode 100644 index 000000000000..4fa67a4beb30 --- /dev/null +++ b/usr.sbin/pmc/display.hh @@ -0,0 +1,105 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026, Netflix, Inc. + * + * This software was developed by Ali Mashtizadeh under the sponsorship from + * Netflix, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define COLOR256_GREEN 46 +#define COLOR256_RED 196 +#define COLOR256_YELLOW 226 + +void setup_screen(); + +/* Formatting */ +std::string format_siprefix(uint64_t count); +std::string format_binprefix(uint64_t count); +std::string format_sample(uint64_t count, uint64_t total); +std::string format_percent(uint64_t count, uint64_t total); + +/* Printing */ +enum class siunit { + seconds, + // Special + cycles, + percent +}; + +void title(const std::string &msg); +void header(const std::string &msg); +void printval(const std::string &msg, uint64_t val, siunit ui); +void printval(const std::string &msg, float val, siunit ui); +void printbar(float percent); + +/* Tables */ +class field +{ +public: + field() { } + field(const std::string &s); + field(int64_t v); + field(float v); + field(int64_t count, int64_t total, bool percent = false); + field(int64_t user_count, int64_t user_total, + int64_t kernel_count, int64_t kernel_total); + virtual ~field() { } + virtual bool operator>(const field &b) const; + virtual bool operator<(const field &b) const; + virtual std::string to_string(); + virtual size_t length(); +private: + enum class FIELD { + STRING, + INTEGER, + FLOAT, + SAMPLE, + DSAMPLE, + PERCENT + }; + FIELD type; + int64_t value[4]; + float fvalue; + std::string svalue; +}; + +class table +{ +public: + table(); + ~table(); + void addcolumn(const std::string &c, bool alignleft = false); + void addrow(std::vector r); + void sort(int col, bool descending = true); + void print(); +private: + int sortcol; + bool sortdir; + std::vector cols; + std::vector align; + std::vector> rows; +}; +