Page MenuHomeFreeBSD

D58927.id.diff
No OneTemporary

D58927.id.diff

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

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)

Event Timeline