Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F170779644
D58927.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D58927.id.diff
View Options
diff --git a/usr.sbin/pmc/display.hh b/usr.sbin/pmc/display.hh
--- a/usr.sbin/pmc/display.hh
+++ b/usr.sbin/pmc/display.hh
@@ -103,3 +103,51 @@
std::vector<std::vector<field>> rows;
};
+/* Graphs */
+class histogram
+{
+public:
+ histogram();
+ ~histogram();
+ void setxlabel(const std::string &lbl);
+ void setylabel(const std::string &lbl);
+ void setxaxis(int min, int max);
+ void setxcolors(const std::vector<int> &colors);
+ void addsample(int s);
+ int min();
+ int max();
+ int average();
+ void print();
+private:
+ int xmin, xmax;
+ std::string xlabel;
+ std::string ylabel;
+ std::vector<int> xcolors;
+ std::unordered_map<int, uint64_t> samples;
+};
+
+class bargraph
+{
+public:
+ bargraph();
+ ~bargraph();
+ void addcolumn(const std::string &c);
+ void addsample(const std::string &c, uint64_t s = 1);
+ void print();
+private:
+ std::vector<std::string> cols;
+ std::unordered_map<std::string, uint64_t> samples;
+};
+
+class bitfield
+{
+public:
+ bitfield();
+ ~bitfield();
+ void setwidth(int width);
+ void fill(uint64_t start, uint64_t length, const std::string &str);
+ void print();
+private:
+ std::vector<std::string> bits;
+};
+
diff --git a/usr.sbin/pmc/display.cc b/usr.sbin/pmc/display.cc
--- a/usr.sbin/pmc/display.cc
+++ b/usr.sbin/pmc/display.cc
@@ -42,7 +42,6 @@
#include <unistd.h>
#include <cxxabi.h>
-#include <cstring>
#include <iomanip>
#include <ios>
#include <iostream>
@@ -104,6 +103,34 @@
};
static const char *border_basic[] = { "-", "|", "+", "+", "+", "+", "+", "+", "+", "+" };
+static const char *graph_fancy[5][5] = {
+ { " ", "\xe2\xa2\x80", "\xe2\xa2\xa0", "\xe2\xa2\xb0", "\xe2\xa2\xb8" },
+ { "\xe2\xa1\x80", "\xe2\xa3\x80", "\xe2\xa3\xa0", "\xe2\xa2\xb0", "\xe2\xa2\xb8" },
+ { "\xe2\xa1\x84", "\xe2\xa3\x84", "\xe2\xa3\xa4", "\xe2\xa3\xb4", "\xe2\xa3\xbc" },
+ { "\xe2\xa1\x86", "\xe2\xa3\x86", "\xe2\xa3\xa6", "\xe2\xa3\xb6", "\xe2\xa3\xbe" },
+ { "\xe2\xa1\x87", "\xe2\xa3\x87", "\xe2\xa3\xa7", "\xe2\xa3\xb7", "\xe2\xa3\xbf" },
+};
+static const char *graph_vt[5] = {
+ " ", "\xe2\x96\x91", "\xe2\x96\x92", "\xe2\x96\x93", "\xe2\x96\x88"
+};
+static const char *graph_basic[5] = { " ", " ", "*", "*", "*" };
+
+static const char **bar_char;
+
+static const char *bar_fancy[8] = {
+ "\xe2\x96\x8f", "\xe2\x96\x8e", "\xe2\x96\x8d", "\xe2\x96\x8c",
+ "\xe2\x96\x8b", "\xe2\x96\x8a", "\xe2\x96\x89", "\xe2\x96\x88"
+};
+
+static const char *bar_vt[8] = {
+ "\xe2\x96\x91", "\xe2\x96\x91", "\xe2\x96\x92", "\xe2\x96\x92",
+ "\xe2\x96\x93", "\xe2\x96\x93", "\xe2\x96\x88", "\xe2\x96\x88"
+};
+
+static const char *bar_basic[8] = {
+ " ", " ", " ", " ", "*", "*", "*", "*"
+};
+
static char tc_boldbuf[16];
static char tc_sgr0buf[16];
static char tc_afbuf[16];
@@ -129,6 +156,47 @@
tputs(tgoto(TC_SETAF, 0, n), 1, putchar);
}
+void
+setup_pager()
+{
+ int status;
+ int in[2];
+ char *pager;
+
+ pager = getenv("PAGER");
+ if (pager == NULL)
+ return;
+
+ status = pipe(in);
+ if (status != 0) {
+ perror("pipe");
+ return;
+ }
+
+ status = fork();
+ if (status < 0) {
+ close(in[0]);
+ close(in[1]);
+ perror("fork");
+ return;
+ }
+ if (status == 0) {
+ dup2(in[0], STDIN_FILENO);
+
+ while(tcgetpgrp(STDOUT_FILENO) != getpid())
+ sleep(0);
+
+ execl(pager, pager, "-F", NULL);
+ } else {
+ setpgid(status, 0);
+ tcsetpgrp(STDOUT_FILENO, status);
+
+ dup2(in[1], STDOUT_FILENO);
+
+
+ }
+}
+
static void
setup_termcap(const char *term)
{
@@ -196,6 +264,7 @@
title_char = title_basic;
arrow_char = arrow_basic;
border_char = border_basic;
+ bar_char = bar_basic;
disp_height = 25;
disp_width = 80;
@@ -204,6 +273,7 @@
title_char = title_vt;
arrow_char = arrow_vt;
border_char = border_vt;
+ bar_char = bar_fancy;
return;
}
@@ -222,6 +292,7 @@
title_char = title_basic;
arrow_char = arrow_basic;
border_char = border_basic;
+ bar_char = bar_basic;
return;
}
@@ -230,11 +301,13 @@
title_char = title_vt;
arrow_char = arrow_vt;
border_char = border_vt;
+ bar_char = bar_fancy;
} else if (strncmp(term, "vt", 2) == 0) {
tmode = TERMMODE_VT;
title_char = title_vt;
arrow_char = arrow_vt;
border_char = border_vt;
+ bar_char = bar_vt;
}
setup_termcap(term);
@@ -302,6 +375,27 @@
}
}
+#define BARWIDTH 40
+
+void
+printbar(float percent)
+{
+ int i;
+
+ printf("|");
+ for (i = 1; i <= BARWIDTH; i++) {
+ float bwidth = 100.0 / BARWIDTH;
+ float rem = percent - bwidth * i;
+ int idx = (rem > bwidth) ? 7 : ((int)(rem / bwidth));
+
+ if (rem <= 0)
+ printf(" ");
+ else
+ printf("%s", bar_char[idx]);
+ }
+ printf("|\n");
+}
+
std::string
format_siprefix(uint64_t count)
{
@@ -315,9 +409,9 @@
}
if (index == 0) {
- snprintf(buf, sizeof(buf), "%" PRIu64, count);
+ snprintf(buf, sizeof(buf), "%lu ", count);
} else {
- snprintf(buf, sizeof(buf), "%" PRIu64 "%c", count, prefix[index]);
+ snprintf(buf, sizeof(buf), "%lu%c", count, prefix[index]);
}
return buf;
@@ -336,9 +430,9 @@
}
if (index == 0) {
- snprintf(buf, sizeof(buf), "%" PRIu64 " B", count);
+ snprintf(buf, sizeof(buf), "%lu B", count);
} else {
- snprintf(buf, sizeof(buf), "%" PRIu64 " %ciB", count, prefix[index]);
+ snprintf(buf, sizeof(buf), "%lu %ciB", count, prefix[index]);
}
return buf;
@@ -570,3 +664,352 @@
std::cout << std::endl;
}
+histogram::histogram() : xmin(0), xmax(0), xlabel(), ylabel(), xcolors(), samples()
+{
+}
+
+histogram::~histogram()
+{
+}
+
+void
+histogram::setxlabel(const std::string &lbl)
+{
+ xlabel = lbl;
+}
+
+void
+histogram::setylabel(const std::string &lbl)
+{
+ ylabel = lbl;
+}
+
+void
+histogram::setxaxis(int min, int max)
+{
+ xmin = min;
+ xmax = max;
+}
+
+/*
+ * Set the x-value cut offs for the start of green, yellow and red.
+ */
+void
+histogram::setxcolors(const std::vector<int> &colors)
+{
+ xcolors = colors;
+}
+
+void
+histogram::addsample(int s)
+{
+ auto e = samples.find(s);
+ if (e == samples.end())
+ samples[s] = 1;
+ else
+ e->second++;
+}
+
+int
+histogram::min()
+{
+ int lowest = INT_MAX;
+ for (auto s : samples) {
+ if (s.first < lowest)
+ lowest = s.first;
+ }
+
+ return lowest;
+}
+
+int
+histogram::max()
+{
+ int highest = INT_MIN;
+ for (auto s : samples) {
+ if (s.first > highest)
+ highest = s.first;
+ }
+
+ return highest;
+}
+
+int
+histogram::average()
+{
+ int64_t sum = 0;
+ int64_t count = 0;
+
+ for (auto s : samples) {
+ sum += ((int64_t)s.first) * ((int64_t)s.second);
+ count += (int64_t)s.second;
+ }
+
+ return sum / count;
+}
+
+void
+histogram::print()
+{
+ int i, j;
+ int min, max;
+ int height, width, bwidth;
+ int xgreen, xyellow, xred;
+ uint64_t ymax;
+ std::unordered_map<int, uint64_t> bins = std::unordered_map<int, uint64_t>();
+
+ height = (disp_height / 2);
+ width = disp_width - 8;
+
+ /*
+ * Ensure that graphs are at least 20 high and have even width to make
+ * the rendering routine below simple.
+ */
+ if (height < 20)
+ height = 20;
+ if (width % 2)
+ width -= 1;
+ bwidth = (tmode == TERMMODE_XTERM) ? (2 * width) : width;
+
+ if (samples.begin() == samples.end()) {
+ printf("Histogram does not contain samples\n\n");
+ return;
+ }
+
+ min = samples.begin()->first;
+ max = samples.begin()->first;
+ for (auto s : samples) {
+ if (s.first < min)
+ min = s.first;
+ if (s.first > max)
+ max = s.first;
+ }
+
+ if (min == max) {
+ printf("Histogram does not contain enough samples\n\n");
+ return;
+ }
+
+ // Automatically select a domain of the graph
+ if (xmin == 0 && xmax == 0) {
+ xmin = min;
+ xmax = max;
+ }
+
+ for (i = 0; i < bwidth; i++)
+ bins[i] = 0;
+
+ for (auto s : samples) {
+ int bin = bwidth * (s.first - xmin) / (xmax - xmin);
+ bins[bin] += s.second;
+ }
+
+ // Determine ymax
+ ymax = 0;
+ for (i = 0; i < bwidth; i++) {
+ if (ymax < bins[i])
+ ymax = bins[i];
+ }
+
+ // Compute log graph
+ for (i = 0; i < bwidth; i++) {
+ float val = 4 * height * log10(bins[i]) / log10(ymax);
+ bins[i] = (val < 0) ? 0 : val;
+ }
+
+ /* Compute the color columns */
+ if (xcolors.size() == 3) {
+ xgreen = width * (xcolors[0] - xmin) / (xmax - xmin);
+ xyellow = width * (xcolors[1] - xmin) / (xmax - xmin);
+ xred = width * (xcolors[2] - xmin) / (xmax - xmin);
+ if (bwidth != width) {
+ xgreen *= 2;
+ xyellow *= 2;
+ xred *= 2;
+ }
+ } else {
+ xgreen = INT_MAX;
+ xyellow = INT_MAX;
+ xred = INT_MAX;
+ }
+
+ int vstart = (height - ylabel.length()) / 2;
+ printf(" %s\n", format_siprefix(ymax).c_str());
+ printf(" %s", border_char[BORDER_TOPRIGHT]);
+ for (i = 0; i < width; i++) {
+ printf("%s", border_char[BORDER_HBAR]);
+ }
+ printf("%s\n", border_char[BORDER_TOPLEFT]);
+ for (i = height; i > 0; i--) {
+ char vc;
+ std::string str = "";
+
+ for (j = 0; j < bwidth; j += 2) {
+ uint64_t row = 4 * (i - 1);
+ uint64_t val[2] = { 0, 0 };
+
+ if (bins[j] > row) {
+ val[0] = bins[j] - row;
+ val[0] = (val[0] > 4) ? 4 : val[0];
+ }
+ if (bins[j + 1] > row) {
+ val[1] = bins[j + 1] - row;
+ val[1] = (val[1] > 4) ? 4 : val[1];
+ }
+
+ if (xgreen == j)
+ str.append(tc_green);
+ if (xyellow == j)
+ str.append(tc_yellow);
+ if (xred == j)
+ str.append(tc_red);
+
+ if (tmode == TERMMODE_XTERM) {
+ str.append(graph_fancy[val[0]][val[1]]);
+ } else if (tmode == TERMMODE_VT) {
+ str.append(graph_vt[val[0]]);
+ str.append(graph_vt[val[1]]);
+ } else {
+ str.append(graph_basic[val[0]]);
+ str.append(graph_basic[val[1]]);
+ }
+ }
+ if (TC_SGR0)
+ str.append(TC_SGR0);
+
+ if ((height - i >= vstart) && (height - i - vstart < (int)ylabel.length()))
+ vc = ylabel[height - i - vstart];
+ else
+ vc = ' ';
+ printf(" %c %s%s%s\n", vc, border_char[BORDER_VBAR],
+ str.c_str(), border_char[BORDER_VBAR]);
+ }
+ printf(" 0 %s", border_char[BORDER_BOTTOMLEFT]);
+ for (i = 0; i < width; i++) {
+ printf("%s", border_char[BORDER_HBAR]);
+ }
+ printf("%s\n", border_char[BORDER_BOTTOMRIGHT]);
+
+ /*
+ * Calculate the spacing on either side of the x-axis label we reserve
+ * 10 characters for the x-min and x-max values.
+ */
+ int rwidth = (width - xlabel.length() - 18) / 2;
+ printf(" %-10d%*c%s%*c%10d\n", xmin, rwidth, ' ', xlabel.c_str(),
+ rwidth, ' ', xmax);
+ printf("\n");
+}
+
+bargraph::bargraph() : cols(), samples()
+{
+}
+
+bargraph::~bargraph()
+{
+}
+
+void
+bargraph::addcolumn(const std::string &c)
+{
+ cols.push_back(c);
+ samples[c] = 0;
+}
+
+void
+bargraph::addsample(const std::string &c, uint64_t s)
+{
+ samples[c] += s;
+}
+
+void
+bargraph::print()
+{
+ uint64_t width;
+ uint64_t total;
+
+ total = 0;
+ width = 0;
+ for (auto &s : samples) {
+ total += s.second;
+ if (width < s.first.length())
+ width = s.first.length();
+ }
+
+ if (total == 0) {
+ printf("No samples\n\n");
+ return;
+ }
+
+ for (auto &s : cols) {
+ float pct = 100.0 * samples[s] / total;
+ printf("% 7.2f%% %*s ", pct, (int)width, s.c_str());
+ printbar(pct);
+ }
+ printf("\n");
+}
+
+bitfield::bitfield() : bits()
+{
+}
+
+bitfield::~bitfield()
+{
+}
+
+void
+bitfield::setwidth(int width)
+{
+ bits.resize(width);
+ for (int i = 0; i < width; i++)
+ bits[i] = " ";
+}
+
+void
+bitfield::fill(uint64_t start, uint64_t length, const std::string &val)
+{
+ for (uint64_t i = start; i < start + length && i < bits.size(); i++)
+ bits[i] = val;
+}
+
+void
+bitfield::print()
+{
+ std::string row;
+
+ row = "";
+ for (uint64_t i = 0; i < bits.size(); i++) {
+ if (i == 0)
+ row += border_char[BORDER_TOPRIGHT];
+ else if (i % 8 == 0)
+ row += border_char[BORDER_TOPSPLIT];
+ row += border_char[BORDER_HBAR];
+ if (i == bits.size() - 1)
+ row += border_char[BORDER_TOPLEFT];
+ }
+ printf(" %s\n", row.c_str());
+
+ row = "";
+ for (uint64_t i = 0; i < bits.size(); i++) {
+ if (i == 0)
+ row += border_char[BORDER_VBAR];
+ else if (i % 8 == 0)
+ row += border_char[BORDER_VBAR];
+ row += bits[i];
+ if (i == bits.size() - 1)
+ row += border_char[BORDER_VBAR];
+ }
+ printf(" %s\n", row.c_str());
+
+ row = "";
+ for (uint64_t i = 0; i < bits.size(); i++) {
+ if (i == 0)
+ row += border_char[BORDER_BOTTOMLEFT];
+ else if (i % 8 == 0)
+ row += border_char[BORDER_BOTTOMSPLIT];
+ row += border_char[BORDER_HBAR];
+ if (i == bits.size() - 1)
+ row += border_char[BORDER_BOTTOMRIGHT];
+ }
+ printf(" %s\n", row.c_str());
+}
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Sep 7, 2:22 PM (2 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36963770
Default Alt Text
D58927.id.diff (12 KB)
Attached To
Mode
D58927: pmc: Bargraphs and Bitfields and Histograms, Oh My!
Attached
Detach File
Event Timeline
Log In to Comment