move these here
This commit is contained in:
parent
f0f4401f0c
commit
e21fee604e
2 changed files with 2942 additions and 0 deletions
884
src/cmd/draw/stats.c
Normal file
884
src/cmd/draw/stats.c
Normal file
|
|
@ -0,0 +1,884 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include <draw.h>
|
||||
#include <thread.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
|
||||
typedef struct Graph Graph;
|
||||
typedef struct Machine Machine;
|
||||
|
||||
enum
|
||||
{
|
||||
Ncolor = 6,
|
||||
Ysqueeze = 2, /* vertical squeezing of label text */
|
||||
Labspace = 2, /* room around label */
|
||||
Dot = 2, /* height of dot */
|
||||
Opwid = 5, /* strlen("add ") or strlen("drop ") */
|
||||
Nlab = 3, /* max number of labels on y axis */
|
||||
Lablen = 16, /* max length of label */
|
||||
Lx = 4, /* label tick length */
|
||||
|
||||
STACK = 8192,
|
||||
XSTACK = 32768,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Vbattery,
|
||||
Vcontext,
|
||||
Vcpu,
|
||||
Vether,
|
||||
Vethererr,
|
||||
Vetherin,
|
||||
Vetherout,
|
||||
Vfault,
|
||||
Vfork,
|
||||
Vidle,
|
||||
Vintr,
|
||||
Vload,
|
||||
Vmem,
|
||||
Vswap,
|
||||
Vsys,
|
||||
Vsyscall,
|
||||
Vuser,
|
||||
Nvalue,
|
||||
};
|
||||
|
||||
char*
|
||||
labels[Nvalue] =
|
||||
{
|
||||
"battery",
|
||||
"context",
|
||||
"cpu",
|
||||
"ether",
|
||||
"ethererr",
|
||||
"etherin",
|
||||
"etherout",
|
||||
"fault",
|
||||
"fork",
|
||||
"idle",
|
||||
"intr",
|
||||
"load",
|
||||
"mem",
|
||||
"swap",
|
||||
"sys",
|
||||
"syscall",
|
||||
"user",
|
||||
};
|
||||
|
||||
struct Graph
|
||||
{
|
||||
int colindex;
|
||||
Rectangle r;
|
||||
int *data;
|
||||
int ndata;
|
||||
char *label;
|
||||
int value;
|
||||
void (*update)(Graph*, ulong, ulong);
|
||||
Machine *mach;
|
||||
int overflow;
|
||||
Image *overtmp;
|
||||
ulong vmax;
|
||||
};
|
||||
|
||||
struct Machine
|
||||
{
|
||||
char *name;
|
||||
int fd;
|
||||
int pid;
|
||||
int dead;
|
||||
int absolute[Nvalue];
|
||||
ulong last[Nvalue];
|
||||
ulong val[Nvalue][2];
|
||||
};
|
||||
|
||||
char *menu2str[Nvalue+1];
|
||||
char xmenu2str[Nvalue+1][40];
|
||||
|
||||
Menu menu2 = {menu2str, nil};
|
||||
int present[Nvalue];
|
||||
Image *cols[Ncolor][3];
|
||||
Graph *graph;
|
||||
Machine *mach;
|
||||
Font *mediumfont;
|
||||
char *mysysname;
|
||||
char argchars[] = "bceEfiIlmnsw";
|
||||
int pids[1024];
|
||||
int parity; /* toggled to avoid patterns in textured background */
|
||||
int nmach;
|
||||
int ngraph; /* totaly number is ngraph*nmach */
|
||||
double scale = 1.0;
|
||||
int logscale = 0;
|
||||
int ylabels = 0;
|
||||
int oldsystem = 0;
|
||||
int sleeptime = 1000;
|
||||
int changedvmax;
|
||||
|
||||
Mousectl *mc;
|
||||
Keyboardctl *kc;
|
||||
|
||||
void
|
||||
killall(char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<nmach; i++)
|
||||
if(mach[i].pid)
|
||||
postnote(PNPROC, mach[i].pid, "kill");
|
||||
exits(s);
|
||||
}
|
||||
|
||||
void*
|
||||
emalloc(ulong sz)
|
||||
{
|
||||
void *v;
|
||||
v = malloc(sz);
|
||||
if(v == nil) {
|
||||
fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
|
||||
killall("mem");
|
||||
}
|
||||
memset(v, 0, sz);
|
||||
return v;
|
||||
}
|
||||
|
||||
void*
|
||||
erealloc(void *v, ulong sz)
|
||||
{
|
||||
v = realloc(v, sz);
|
||||
if(v == nil) {
|
||||
fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
|
||||
killall("mem");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
char*
|
||||
estrdup(char *s)
|
||||
{
|
||||
char *t;
|
||||
if((t = strdup(s)) == nil) {
|
||||
fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
|
||||
killall("mem");
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
mkcol(int i, int c0, int c1, int c2)
|
||||
{
|
||||
cols[i][0] = allocimagemix(display, c0, DWhite);
|
||||
cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
|
||||
cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
|
||||
}
|
||||
|
||||
void
|
||||
colinit(void)
|
||||
{
|
||||
mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
|
||||
if(mediumfont == nil)
|
||||
mediumfont = font;
|
||||
|
||||
/* Peach */
|
||||
mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
|
||||
/* Aqua */
|
||||
mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
|
||||
/* Yellow */
|
||||
mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
|
||||
/* Green */
|
||||
mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
|
||||
/* Blue */
|
||||
mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
|
||||
/* Grey */
|
||||
cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
|
||||
cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
|
||||
cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
|
||||
}
|
||||
|
||||
void
|
||||
label(Point p, int dy, char *text)
|
||||
{
|
||||
char *s;
|
||||
Rune r[2];
|
||||
int w, maxw, maxy;
|
||||
|
||||
p.x += Labspace;
|
||||
maxy = p.y+dy;
|
||||
maxw = 0;
|
||||
r[1] = '\0';
|
||||
for(s=text; *s; ){
|
||||
if(p.y+mediumfont->height-Ysqueeze > maxy)
|
||||
break;
|
||||
w = chartorune(r, s);
|
||||
s += w;
|
||||
w = runestringwidth(mediumfont, r);
|
||||
if(w > maxw)
|
||||
maxw = w;
|
||||
runestring(screen, p, display->black, ZP, mediumfont, r);
|
||||
p.y += mediumfont->height-Ysqueeze;
|
||||
}
|
||||
}
|
||||
|
||||
Point
|
||||
paritypt(int x)
|
||||
{
|
||||
return Pt(x+parity, 0);
|
||||
}
|
||||
|
||||
Point
|
||||
datapoint(Graph *g, int x, ulong v, ulong vmax)
|
||||
{
|
||||
Point p;
|
||||
double y;
|
||||
|
||||
p.x = x;
|
||||
y = ((double)v)/(vmax*scale);
|
||||
if(logscale){
|
||||
/*
|
||||
* Arrange scale to cover a factor of 1000.
|
||||
* vmax corresponds to the 100 mark.
|
||||
* 10*vmax is the top of the scale.
|
||||
*/
|
||||
if(y <= 0.)
|
||||
y = 0;
|
||||
else{
|
||||
y = log10(y);
|
||||
/* 1 now corresponds to the top; -2 to the bottom; rescale */
|
||||
y = (y+2.)/3.;
|
||||
}
|
||||
}
|
||||
p.y = g->r.max.y - Dy(g->r)*y - Dot;
|
||||
if(p.y < g->r.min.y)
|
||||
p.y = g->r.min.y;
|
||||
if(p.y > g->r.max.y-Dot)
|
||||
p.y = g->r.max.y-Dot;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
drawdatum(Graph *g, int x, ulong prev, ulong v, ulong vmax)
|
||||
{
|
||||
int c;
|
||||
Point p, q;
|
||||
|
||||
c = g->colindex;
|
||||
p = datapoint(g, x, v, vmax);
|
||||
q = datapoint(g, x, prev, vmax);
|
||||
if(p.y < q.y){
|
||||
draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
|
||||
draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
|
||||
draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
|
||||
}else{
|
||||
draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
|
||||
draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
|
||||
draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
redraw(Graph *g, int vmax)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
if(vmax != g->vmax){
|
||||
g->vmax = vmax;
|
||||
changedvmax = 1;
|
||||
}
|
||||
c = g->colindex;
|
||||
draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
|
||||
for(i=1; i<Dx(g->r); i++)
|
||||
drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
|
||||
drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
|
||||
g->overflow = 0;
|
||||
}
|
||||
|
||||
void
|
||||
update1(Graph *g, ulong v, ulong vmax)
|
||||
{
|
||||
char buf[32];
|
||||
int overflow;
|
||||
|
||||
if(vmax != g->vmax){
|
||||
g->vmax = vmax;
|
||||
changedvmax = 1;
|
||||
}
|
||||
if(g->overflow && g->overtmp!=nil)
|
||||
draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
|
||||
draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
|
||||
drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
|
||||
memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
|
||||
g->data[0] = v;
|
||||
g->overflow = 0;
|
||||
if(logscale)
|
||||
overflow = (v>10*vmax*scale);
|
||||
else
|
||||
overflow = (v>vmax*scale);
|
||||
if(overflow && g->overtmp!=nil){
|
||||
g->overflow = 1;
|
||||
draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
|
||||
sprint(buf, "%ld", v);
|
||||
string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: stats [-O] [-S scale] [-LY] [-%s] [machine...]\n", argchars);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
addgraph(int n)
|
||||
{
|
||||
Graph *g, *ograph;
|
||||
int i, j;
|
||||
static int nadd;
|
||||
|
||||
if(n > Nvalue)
|
||||
abort();
|
||||
/* avoid two adjacent graphs of same color */
|
||||
if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
|
||||
nadd++;
|
||||
ograph = graph;
|
||||
graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
|
||||
for(i=0; i<nmach; i++)
|
||||
for(j=0; j<ngraph; j++)
|
||||
graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
|
||||
free(ograph);
|
||||
ngraph++;
|
||||
for(i=0; i<nmach; i++){
|
||||
g = &graph[i*ngraph+(ngraph-1)];
|
||||
memset(g, 0, sizeof(Graph));
|
||||
g->value = n;
|
||||
g->label = menu2str[n]+Opwid;
|
||||
g->update = update1; /* no other update functions yet */
|
||||
g->mach = &mach[i];
|
||||
g->colindex = nadd%Ncolor;
|
||||
}
|
||||
present[n] = 1;
|
||||
nadd++;
|
||||
}
|
||||
|
||||
void
|
||||
dropgraph(int which)
|
||||
{
|
||||
Graph *ograph;
|
||||
int i, j, n;
|
||||
|
||||
if(which > nelem(menu2str))
|
||||
abort();
|
||||
/* convert n to index in graph table */
|
||||
n = -1;
|
||||
for(i=0; i<ngraph; i++)
|
||||
if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
|
||||
n = i;
|
||||
break;
|
||||
}
|
||||
if(n < 0){
|
||||
fprint(2, "stats: internal error can't drop graph\n");
|
||||
killall("error");
|
||||
}
|
||||
ograph = graph;
|
||||
graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
|
||||
for(i=0; i<nmach; i++){
|
||||
for(j=0; j<n; j++)
|
||||
graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
|
||||
free(ograph[i*ngraph+j].data);
|
||||
freeimage(ograph[i*ngraph+j].overtmp);
|
||||
for(j++; j<ngraph; j++)
|
||||
graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
|
||||
}
|
||||
free(ograph);
|
||||
ngraph--;
|
||||
present[which] = 0;
|
||||
}
|
||||
|
||||
int initmach(Machine*, char*);
|
||||
|
||||
int
|
||||
addmachine(char *name)
|
||||
{
|
||||
if(ngraph > 0){
|
||||
fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
|
||||
usage();
|
||||
}
|
||||
if(mach == nil)
|
||||
nmach = 0; /* a little dance to get us started with local machine by default */
|
||||
mach = erealloc(mach, (nmach+1)*sizeof(Machine));
|
||||
memset(mach+nmach, 0, sizeof(Machine));
|
||||
if (initmach(mach+nmach, name)){
|
||||
nmach++;
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
newvalue(Machine *m, int i, ulong *v, ulong *vmax)
|
||||
{
|
||||
ulong now;
|
||||
|
||||
if(m->absolute[i]){
|
||||
*v = m->val[i][0];
|
||||
*vmax = m->val[i][1];
|
||||
}else{
|
||||
now = m->val[i][0];
|
||||
*v = (vlong)((now - m->last[i])*sleeptime)/1000;
|
||||
m->last[i] = now;
|
||||
*vmax = m->val[i][1];
|
||||
}
|
||||
if(*vmax == 0)
|
||||
*vmax = 1;
|
||||
}
|
||||
|
||||
void
|
||||
labelstrs(Graph *g, char strs[Nlab][Lablen], int *np)
|
||||
{
|
||||
int j;
|
||||
ulong vmax;
|
||||
|
||||
vmax = g->vmax;
|
||||
if(logscale){
|
||||
for(j=1; j<=2; j++)
|
||||
sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);
|
||||
*np = 2;
|
||||
}else{
|
||||
for(j=1; j<=3; j++)
|
||||
sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);
|
||||
*np = 3;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
labelwidth(void)
|
||||
{
|
||||
int i, j, n, w, maxw;
|
||||
char strs[Nlab][Lablen];
|
||||
|
||||
maxw = 0;
|
||||
for(i=0; i<ngraph; i++){
|
||||
/* choose value for rightmost graph */
|
||||
labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);
|
||||
for(j=0; j<n; j++){
|
||||
w = stringwidth(mediumfont, strs[j]);
|
||||
if(w > maxw)
|
||||
maxw = w;
|
||||
}
|
||||
}
|
||||
return maxw;
|
||||
}
|
||||
|
||||
void
|
||||
resize(void)
|
||||
{
|
||||
int i, j, k, n, startx, starty, x, y, dx, dy, ly, ondata, maxx, wid, nlab;
|
||||
Graph *g;
|
||||
Rectangle machr, r;
|
||||
ulong v, vmax;
|
||||
char buf[128], labs[Nlab][Lablen];
|
||||
|
||||
draw(screen, screen->r, display->white, nil, ZP);
|
||||
|
||||
/* label left edge */
|
||||
x = screen->r.min.x;
|
||||
y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
|
||||
dy = (screen->r.max.y - y)/ngraph;
|
||||
dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
|
||||
startx = x+dx+1;
|
||||
starty = y;
|
||||
for(i=0; i<ngraph; i++,y+=dy){
|
||||
draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
|
||||
draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
|
||||
label(Pt(x, y), dy, graph[i].label);
|
||||
draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
|
||||
}
|
||||
|
||||
/* label top edge */
|
||||
dx = (screen->r.max.x - startx)/nmach;
|
||||
for(x=startx, i=0; i<nmach; i++,x+=dx){
|
||||
draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
|
||||
j = dx/stringwidth(mediumfont, "0");
|
||||
// n = mach[i].nproc;
|
||||
n = 1;
|
||||
if(n>1 && j>=1+3+(n>10)+(n>100)){ /* first char of name + (n) */
|
||||
j -= 3+(n>10)+(n>100);
|
||||
if(j <= 0)
|
||||
j = 1;
|
||||
snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
|
||||
}else
|
||||
snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
|
||||
string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf);
|
||||
}
|
||||
|
||||
maxx = screen->r.max.x;
|
||||
|
||||
/* label right, if requested */
|
||||
if(ylabels && dy>Nlab*(mediumfont->height+1)){
|
||||
wid = labelwidth();
|
||||
if(wid < (maxx-startx)-30){
|
||||
/* else there's not enough room */
|
||||
maxx -= 1+Lx+wid;
|
||||
draw(screen, Rect(maxx, starty, maxx+1, screen->r.max.y), display->black, nil, ZP);
|
||||
y = starty;
|
||||
for(j=0; j<ngraph; j++, y+=dy){
|
||||
/* choose value for rightmost graph */
|
||||
g = &graph[ngraph*(nmach-1)+j];
|
||||
labelstrs(g, labs, &nlab);
|
||||
r = Rect(maxx+1, y, screen->r.max.x, y+dy-1);
|
||||
if(j == ngraph-1)
|
||||
r.max.y = screen->r.max.y;
|
||||
draw(screen, r, cols[g->colindex][0], nil, paritypt(r.min.x));
|
||||
for(k=0; k<nlab; k++){
|
||||
ly = y + (dy*(nlab-k)/(nlab+1));
|
||||
draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
|
||||
ly -= mediumfont->height/2;
|
||||
string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, mediumfont, labs[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create graphs */
|
||||
for(i=0; i<nmach; i++){
|
||||
machr = Rect(startx+i*dx, starty, maxx, screen->r.max.y);
|
||||
if(i < nmach-1)
|
||||
machr.max.x = startx+(i+1)*dx - 1;
|
||||
y = starty;
|
||||
for(j=0; j<ngraph; j++, y+=dy){
|
||||
g = &graph[i*ngraph+j];
|
||||
/* allocate data */
|
||||
ondata = g->ndata;
|
||||
g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */
|
||||
g->data = erealloc(g->data, g->ndata*sizeof(ulong));
|
||||
if(g->ndata > ondata)
|
||||
memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(ulong));
|
||||
/* set geometry */
|
||||
g->r = machr;
|
||||
g->r.min.y = y;
|
||||
g->r.max.y = y+dy - 1;
|
||||
if(j == ngraph-1)
|
||||
g->r.max.y = screen->r.max.y;
|
||||
draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
|
||||
g->overflow = 0;
|
||||
r = g->r;
|
||||
r.max.y = r.min.y+mediumfont->height;
|
||||
r.max.x = r.min.x+stringwidth(mediumfont, "9999999");
|
||||
freeimage(g->overtmp);
|
||||
g->overtmp = nil;
|
||||
if(r.max.x <= g->r.max.x)
|
||||
g->overtmp = allocimage(display, r, screen->chan, 0, -1);
|
||||
newvalue(g->mach, g->value, &v, &vmax);
|
||||
redraw(g, vmax);
|
||||
}
|
||||
}
|
||||
|
||||
flushimage(display, 1);
|
||||
}
|
||||
|
||||
void
|
||||
eresized(int new)
|
||||
{
|
||||
lockdisplay(display);
|
||||
if(new && getwindow(display, Refnone) < 0) {
|
||||
fprint(2, "stats: can't reattach to window\n");
|
||||
killall("reattach");
|
||||
}
|
||||
resize();
|
||||
unlockdisplay(display);
|
||||
}
|
||||
|
||||
void
|
||||
mousethread(void *v)
|
||||
{
|
||||
Mouse m;
|
||||
int i;
|
||||
|
||||
USED(v);
|
||||
|
||||
while(readmouse(mc) == 0){
|
||||
m = mc->m;
|
||||
if(m.buttons == 4){
|
||||
for(i=0; i<Nvalue; i++)
|
||||
if(present[i])
|
||||
memmove(menu2str[i], "drop ", Opwid);
|
||||
else
|
||||
memmove(menu2str[i], "add ", Opwid);
|
||||
lockdisplay(display);
|
||||
i = menuhit(3, mc, &menu2, nil);
|
||||
if(i >= 0){
|
||||
if(!present[i])
|
||||
addgraph(i);
|
||||
else if(ngraph > 1)
|
||||
dropgraph(i);
|
||||
resize();
|
||||
}
|
||||
unlockdisplay(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
resizethread(void *v)
|
||||
{
|
||||
USED(v);
|
||||
|
||||
while(recv(mc->resizec, 0) == 1){
|
||||
lockdisplay(display);
|
||||
if(getwindow(display, Refnone) < 0)
|
||||
sysfatal("attach to window: %r");
|
||||
resize();
|
||||
unlockdisplay(display);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
keyboardthread(void *v)
|
||||
{
|
||||
Rune r;
|
||||
|
||||
while(recv(kc->c, &r) == 1)
|
||||
if(r == 0x7F || r == 'q')
|
||||
killall("quit");
|
||||
}
|
||||
|
||||
void machthread(void*);
|
||||
|
||||
void
|
||||
threadmain(int argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
char *s;
|
||||
ulong v, vmax, nargs;
|
||||
char args[100];
|
||||
|
||||
nmach = 1;
|
||||
mysysname = sysname();
|
||||
if(mysysname == nil){
|
||||
fprint(2, "stats: can't find sysname: %r\n");
|
||||
exits("sysname");
|
||||
}
|
||||
|
||||
nargs = 0;
|
||||
ARGBEGIN{
|
||||
case 'T':
|
||||
s = ARGF();
|
||||
if(s == nil)
|
||||
usage();
|
||||
i = atoi(s);
|
||||
if(i > 0)
|
||||
sleeptime = 1000*i;
|
||||
break;
|
||||
case 'S':
|
||||
s = ARGF();
|
||||
if(s == nil)
|
||||
usage();
|
||||
scale = atof(s);
|
||||
if(scale <= 0.)
|
||||
usage();
|
||||
break;
|
||||
case 'L':
|
||||
logscale++;
|
||||
break;
|
||||
case 'Y':
|
||||
ylabels++;
|
||||
break;
|
||||
case 'O':
|
||||
oldsystem = 1;
|
||||
break;
|
||||
default:
|
||||
if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
|
||||
usage();
|
||||
args[nargs++] = ARGC();
|
||||
}ARGEND
|
||||
|
||||
for(i=0; i<Nvalue; i++){
|
||||
menu2str[i] = xmenu2str[i];
|
||||
snprint(xmenu2str[i], sizeof xmenu2str[i], "add %s", labels[i]);
|
||||
}
|
||||
|
||||
if(argc == 0){
|
||||
mach = emalloc(nmach*sizeof(Machine));
|
||||
initmach(&mach[0], mysysname);
|
||||
}else{
|
||||
for(i=j=0; i<argc; i++)
|
||||
addmachine(argv[i]);
|
||||
}
|
||||
|
||||
for(i=0; i<nmach; i++)
|
||||
threadcreate(machthread, &mach[i], STACK);
|
||||
|
||||
for(i=0; i<nargs; i++)
|
||||
switch(args[i]){
|
||||
default:
|
||||
fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
|
||||
usage();
|
||||
case 'b':
|
||||
addgraph(Vbattery);
|
||||
break;
|
||||
case 'c':
|
||||
addgraph(Vcontext);
|
||||
break;
|
||||
case 'e':
|
||||
addgraph(Vether);
|
||||
break;
|
||||
case 'E':
|
||||
addgraph(Vetherin);
|
||||
addgraph(Vetherout);
|
||||
break;
|
||||
case 'f':
|
||||
addgraph(Vfault);
|
||||
break;
|
||||
case 'i':
|
||||
addgraph(Vintr);
|
||||
break;
|
||||
case 'I':
|
||||
addgraph(Vload);
|
||||
addgraph(Vidle);
|
||||
break;
|
||||
case 'l':
|
||||
addgraph(Vload);
|
||||
break;
|
||||
case 'm':
|
||||
addgraph(Vmem);
|
||||
break;
|
||||
case 'n':
|
||||
addgraph(Vetherin);
|
||||
addgraph(Vetherout);
|
||||
addgraph(Vethererr);
|
||||
break;
|
||||
case 's':
|
||||
addgraph(Vsyscall);
|
||||
break;
|
||||
case 'w':
|
||||
addgraph(Vswap);
|
||||
break;
|
||||
}
|
||||
|
||||
if(ngraph == 0)
|
||||
addgraph(Vload);
|
||||
|
||||
for(i=0; i<nmach; i++)
|
||||
for(j=0; j<ngraph; j++)
|
||||
graph[i*ngraph+j].mach = &mach[i];
|
||||
|
||||
if(initdraw(nil, nil, "stats") < 0)
|
||||
sysfatal("initdraw: %r");
|
||||
colinit();
|
||||
if((mc = initmouse(nil, nil)) == nil)
|
||||
sysfatal("initmouse: %r");
|
||||
if((kc = initkeyboard(nil)) == nil)
|
||||
sysfatal("initkeyboard: %r");
|
||||
|
||||
display->locking = 1;
|
||||
threadcreate(keyboardthread, nil, XSTACK);
|
||||
threadcreate(mousethread, nil, XSTACK);
|
||||
threadcreate(resizethread, nil, XSTACK);
|
||||
|
||||
resize();
|
||||
unlockdisplay(display);
|
||||
|
||||
for(;;){
|
||||
parity = 1-parity;
|
||||
lockdisplay(display);
|
||||
for(i=0; i<nmach*ngraph; i++){
|
||||
newvalue(graph[i].mach, graph[i].value, &v, &vmax);
|
||||
graph[i].update(&graph[i], v, vmax);
|
||||
}
|
||||
if(changedvmax){
|
||||
changedvmax = 0;
|
||||
resize();
|
||||
}
|
||||
flushimage(display, 1);
|
||||
unlockdisplay(display);
|
||||
threadsleep(sleeptime);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
machthread(void *v)
|
||||
{
|
||||
char buf[256], *f[4], *p;
|
||||
int i, n, t;
|
||||
Machine *m;
|
||||
|
||||
m = v;
|
||||
t = 0;
|
||||
for(;;){
|
||||
n = threadread(m->fd, buf+t, sizeof buf-t);
|
||||
m->dead = 0;
|
||||
if(n <= 0)
|
||||
break;
|
||||
t += n;
|
||||
while((p = memchr(buf, '\n', t)) != nil){
|
||||
*p++ = 0;
|
||||
n = tokenize(buf, f, nelem(f));
|
||||
if(n >= 3){
|
||||
for(i=0; i<Nvalue; i++){
|
||||
if(strcmp(labels[i], f[0]) == 0){
|
||||
if(*f[1] == '='){
|
||||
m->absolute[i] = 1;
|
||||
f[1]++;
|
||||
}
|
||||
m->val[i][0] = strtoul(f[1], 0, 0);
|
||||
m->val[i][1] = strtoul(f[2], 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
t -= (p-buf);
|
||||
memmove(buf, p, t);
|
||||
}
|
||||
}
|
||||
if(m->fd){
|
||||
close(m->fd);
|
||||
m->fd = -1;
|
||||
}
|
||||
if(m->pid){
|
||||
postnote(PNPROC, m->pid, "kill");
|
||||
m->pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
initmach(Machine *m, char *name)
|
||||
{
|
||||
char *args[5], *q;
|
||||
int p[2], kfd[3], pid;
|
||||
|
||||
m->name = name;
|
||||
if(strcmp(name, mysysname) == 0)
|
||||
name = nil;
|
||||
|
||||
if(pipe(p) < 0)
|
||||
sysfatal("pipe: %r");
|
||||
|
||||
memset(args, 0, sizeof args);
|
||||
args[0] = "sysstat";
|
||||
if(name){
|
||||
args[1] = name;
|
||||
if((q = strchr(name, ':')) != nil){
|
||||
*q++ = 0;
|
||||
args[2] = q;
|
||||
}
|
||||
}
|
||||
kfd[0] = open("/dev/null", OREAD);
|
||||
kfd[1] = p[1];
|
||||
kfd[2] = dup(2, -1);
|
||||
if((pid = threadspawn(kfd, "sysstat", args)) < 0){
|
||||
fprint(2, "spawn: %r\n");
|
||||
close(kfd[0]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
return 0;
|
||||
}
|
||||
m->fd = p[0];
|
||||
m->pid = pid;
|
||||
if((q = strchr(m->name, '.')) != nil)
|
||||
*q = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
2058
src/cmd/draw/tweak.c
Normal file
2058
src/cmd/draw/tweak.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue