stats.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. #include <u.h>
  2. #include <lib9.h>
  3. #include <envvars.h>
  4. #include <ctype.h>
  5. #include <draw.h>
  6. #include <event.h>
  7. #include <keyboard.h>
  8. #define MAXNUM 10 /* maximum number of numbers on data line */
  9. typedef struct Graph Graph;
  10. typedef struct Machine Machine;
  11. struct Graph
  12. {
  13. int colindex;
  14. Rectangle r;
  15. int *data;
  16. int ndata;
  17. char *label;
  18. void (*newvalue)(Machine*, uint64_t*, uint64_t*, int);
  19. void (*update)(Graph*, uint64_t, uint64_t);
  20. Machine *mach;
  21. int overflow;
  22. Image *overtmp;
  23. };
  24. enum
  25. {
  26. /* old /dev/swap */
  27. Mem = 0,
  28. Maxmem,
  29. Swap,
  30. Maxswap,
  31. Kern,
  32. Maxkern,
  33. Draw,
  34. Maxdraw,
  35. /* /dev/sysstats */
  36. Procno = 0,
  37. Context,
  38. Interrupt,
  39. Syscall,
  40. Fault,
  41. TLBfault,
  42. TLBpurge,
  43. Load,
  44. Idle,
  45. InIntr,
  46. /* /net/ether0/stats */
  47. In = 0,
  48. Link,
  49. Out,
  50. Err0,
  51. };
  52. struct Machine
  53. {
  54. char *name;
  55. char *shortname;
  56. int remote;
  57. int statsfd;
  58. int swapfd;
  59. int etherfd;
  60. int ifstatsfd;
  61. int batteryfd;
  62. int bitsybatfd;
  63. int tempfd;
  64. int disable;
  65. uint64_t devswap[8];
  66. uint64_t devsysstat[10];
  67. uint64_t prevsysstat[10];
  68. int nproc;
  69. int lgproc;
  70. uint64_t netetherstats[8];
  71. uint64_t prevetherstats[8];
  72. uint64_t batterystats[2];
  73. uint64_t netetherifstats[2];
  74. uint64_t temp[10];
  75. /* big enough to hold /dev/sysstat even with many processors */
  76. char buf[8*1024];
  77. char *bufp;
  78. char *ebufp;
  79. };
  80. enum
  81. {
  82. Mainproc,
  83. Inputproc,
  84. NPROC,
  85. };
  86. enum
  87. {
  88. Ncolor = 6,
  89. Ysqueeze = 2, /* vertical squeezing of label text */
  90. Labspace = 2, /* room around label */
  91. Dot = 2, /* height of dot */
  92. Opwid = 5, /* strlen("add ") or strlen("drop ") */
  93. Nlab = 3, /* max number of labels on y axis */
  94. Lablen = 16, /* max length of label */
  95. Lx = 4, /* label tick length */
  96. };
  97. enum Menu2
  98. {
  99. Mbattery,
  100. Mcontext,
  101. Mether,
  102. Methererr,
  103. Metherin,
  104. Metherout,
  105. Mfault,
  106. Midle,
  107. Minintr,
  108. Mintr,
  109. Mload,
  110. Mmem,
  111. Mswap,
  112. Mkern,
  113. Mdraw,
  114. Msyscall,
  115. Mtlbmiss,
  116. Mtlbpurge,
  117. Msignal,
  118. Mtemp,
  119. Nmenu2,
  120. };
  121. char *menu2strtpl[Nmenu2+1] = {
  122. "add battery ",
  123. "add context ",
  124. "add ether ",
  125. "add ethererr",
  126. "add etherin ",
  127. "add etherout",
  128. "add fault ",
  129. "add idle ",
  130. "add inintr ",
  131. "add intr ",
  132. "add load ",
  133. "add mem ",
  134. "add swap ",
  135. "add kern ",
  136. "add draw ",
  137. "add syscall ",
  138. "add tlbmiss ",
  139. "add tlbpurge",
  140. "add 802.11b ",
  141. "add temp ",
  142. nil,
  143. };
  144. char *menu2str[Nmenu2+1];
  145. void contextval(Machine*, uint64_t*, uint64_t*, int),
  146. etherval(Machine*, uint64_t*, uint64_t*, int),
  147. ethererrval(Machine*, uint64_t*, uint64_t*, int),
  148. etherinval(Machine*, uint64_t*, uint64_t*, int),
  149. etheroutval(Machine*, uint64_t*, uint64_t*, int),
  150. faultval(Machine*, uint64_t*, uint64_t*, int),
  151. intrval(Machine*, uint64_t*, uint64_t*, int),
  152. inintrval(Machine*, uint64_t*, uint64_t*, int),
  153. loadval(Machine*, uint64_t*, uint64_t*, int),
  154. idleval(Machine*, uint64_t*, uint64_t*, int),
  155. memval(Machine*, uint64_t*, uint64_t*, int),
  156. swapval(Machine*, uint64_t*, uint64_t*, int),
  157. kernval(Machine*, uint64_t*, uint64_t*, int),
  158. drawval(Machine*, uint64_t*, uint64_t*, int),
  159. syscallval(Machine*, uint64_t*, uint64_t*, int),
  160. tlbmissval(Machine*, uint64_t*, uint64_t*, int),
  161. tlbpurgeval(Machine*, uint64_t*, uint64_t*, int),
  162. batteryval(Machine*, uint64_t*, uint64_t*, int),
  163. signalval(Machine*, uint64_t*, uint64_t*, int),
  164. tempval(Machine*, uint64_t*, uint64_t*, int);
  165. Menu menu2 = {menu2str, nil};
  166. int present[Nmenu2];
  167. void (*newvaluefn[Nmenu2])(Machine*, uint64_t*, uint64_t*, int init) = {
  168. batteryval,
  169. contextval,
  170. etherval,
  171. ethererrval,
  172. etherinval,
  173. etheroutval,
  174. faultval,
  175. idleval,
  176. inintrval,
  177. intrval,
  178. loadval,
  179. memval,
  180. swapval,
  181. kernval,
  182. drawval,
  183. syscallval,
  184. tlbmissval,
  185. tlbpurgeval,
  186. signalval,
  187. tempval,
  188. };
  189. Image *cols[Ncolor][3];
  190. Graph *graph;
  191. Machine *mach;
  192. char *mysysname;
  193. char argchars[] = "8bcdeEfiIkmlnpstwz";
  194. int pids[NPROC];
  195. int parity; /* toggled to avoid patterns in textured background */
  196. int nmach;
  197. int ngraph; /* totaly number is ngraph*nmach */
  198. double scale = 1.0;
  199. int logscale = 0;
  200. int ylabels = 0;
  201. int sleeptime = 1000;
  202. char *procnames[NPROC] = {"main", "input"};
  203. void
  204. killall(char *s)
  205. {
  206. int i, pid;
  207. pid = getpid();
  208. for(i=0; i<NPROC; i++)
  209. if(pids[i] && pids[i]!=pid)
  210. postnote(PNPROC, pids[i], "kill");
  211. exits(s);
  212. }
  213. void*
  214. emalloc(uint32_t sz)
  215. {
  216. void *v;
  217. v = malloc(sz);
  218. if(v == nil) {
  219. fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
  220. killall("mem");
  221. }
  222. memset(v, 0, sz);
  223. return v;
  224. }
  225. void*
  226. erealloc(void *v, uint32_t sz)
  227. {
  228. v = realloc(v, sz);
  229. if(v == nil) {
  230. fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
  231. killall("mem");
  232. }
  233. return v;
  234. }
  235. char*
  236. estrdup(char *s)
  237. {
  238. char *t;
  239. if((t = strdup(s)) == nil) {
  240. fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
  241. killall("mem");
  242. }
  243. return t;
  244. }
  245. void
  246. mkcol(int i, int c0, int c1, int c2)
  247. {
  248. cols[i][0] = allocimagemix(display, c0, DWhite);
  249. cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
  250. cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
  251. }
  252. void
  253. colinit(void)
  254. {
  255. /* Peach */
  256. mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
  257. /* Aqua */
  258. mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
  259. /* Yellow */
  260. mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
  261. /* Green */
  262. mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
  263. /* Blue */
  264. mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
  265. /* Grey */
  266. cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
  267. cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
  268. cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
  269. }
  270. int
  271. loadbuf(Machine *m, int *fd)
  272. {
  273. int n;
  274. if(*fd < 0)
  275. return 0;
  276. seek(*fd, 0, 0);
  277. n = read(*fd, m->buf, sizeof m->buf-1);
  278. if(n <= 0){
  279. close(*fd);
  280. *fd = -1;
  281. return 0;
  282. }
  283. m->bufp = m->buf;
  284. m->ebufp = m->buf+n;
  285. m->buf[n] = 0;
  286. return 1;
  287. }
  288. void
  289. label(Point p, int dy, char *text)
  290. {
  291. char *s;
  292. Rune r[2];
  293. int w, maxw, maxy;
  294. p.x += Labspace;
  295. maxy = p.y+dy;
  296. maxw = 0;
  297. r[1] = '\0';
  298. for(s=text; *s; ){
  299. if(p.y+font->height-Ysqueeze > maxy)
  300. break;
  301. w = chartorune(r, s);
  302. s += w;
  303. w = runestringwidth(font, r);
  304. if(w > maxw)
  305. maxw = w;
  306. runestring(screen, p, display->black, ZP, font, r);
  307. p.y += font->height-Ysqueeze;
  308. }
  309. }
  310. Point
  311. paritypt(int x)
  312. {
  313. return Pt(x+parity, 0);
  314. }
  315. Point
  316. datapoint(Graph *g, int x, uint64_t v, uint64_t vmax)
  317. {
  318. Point p;
  319. double y;
  320. p.x = x;
  321. y = ((double)v)/(vmax*scale);
  322. if(logscale){
  323. /*
  324. * Arrange scale to cover a factor of 1000.
  325. * vmax corresponds to the 100 mark.
  326. * 10*vmax is the top of the scale.
  327. */
  328. if(y <= 0.)
  329. y = 0;
  330. else{
  331. y = log10(y);
  332. /* 1 now corresponds to the top; -2 to the bottom; rescale */
  333. y = (y+2.)/3.;
  334. }
  335. }
  336. if(y >= 1.)
  337. y = 1;
  338. if(y <= 0.)
  339. y = 0;
  340. p.y = g->r.max.y - Dy(g->r)*y - Dot;
  341. if(p.y < g->r.min.y)
  342. p.y = g->r.min.y;
  343. if(p.y > g->r.max.y-Dot)
  344. p.y = g->r.max.y-Dot;
  345. return p;
  346. }
  347. void
  348. drawdatum(Graph *g, int x, uint64_t prev, uint64_t v, uint64_t vmax)
  349. {
  350. int c;
  351. Point p, q;
  352. c = g->colindex;
  353. p = datapoint(g, x, v, vmax);
  354. q = datapoint(g, x, prev, vmax);
  355. if(p.y < q.y){
  356. draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
  357. draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
  358. draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
  359. }else{
  360. draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
  361. draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
  362. draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
  363. }
  364. }
  365. void
  366. redraw(Graph *g, uint64_t vmax)
  367. {
  368. int i, c;
  369. c = g->colindex;
  370. draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
  371. for(i=1; i<Dx(g->r); i++)
  372. drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
  373. drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
  374. g->overflow = 0;
  375. }
  376. void
  377. update1(Graph *g, uint64_t v, uint64_t vmax)
  378. {
  379. char buf[48];
  380. int overflow;
  381. if(g->overflow && g->overtmp!=nil)
  382. draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
  383. draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
  384. drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
  385. memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
  386. g->data[0] = v;
  387. g->overflow = 0;
  388. if(logscale)
  389. overflow = (v>10*vmax*scale);
  390. else
  391. overflow = (v>vmax*scale);
  392. if(overflow && g->overtmp!=nil){
  393. g->overflow = 1;
  394. draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
  395. sprint(buf, "%llud", v);
  396. string(screen, g->overtmp->r.min, display->black, ZP, font, buf);
  397. }
  398. }
  399. /* read one line of text from buffer and process integers */
  400. int
  401. readnums(Machine *m, int n, uint64_t *a, int spanlines)
  402. {
  403. int i;
  404. char *p, *ep;
  405. if(spanlines)
  406. ep = m->ebufp;
  407. else
  408. for(ep=m->bufp; ep<m->ebufp; ep++)
  409. if(*ep == '\n')
  410. break;
  411. p = m->bufp;
  412. for(i=0; i<n && p<ep; i++){
  413. while(p<ep && (!isascii(*p) || !isdigit(*p)) && *p!='-')
  414. p++;
  415. if(p == ep)
  416. break;
  417. a[i] = strtoull(p, &p, 10);
  418. }
  419. if(ep < m->ebufp)
  420. ep++;
  421. m->bufp = ep;
  422. return i == n;
  423. }
  424. int
  425. readswap(Machine *m, uint64_t *a)
  426. {
  427. if(strstr(m->buf, "memory\n")){
  428. /* new /dev/swap - skip first 3 numbers */
  429. if(!readnums(m, 5, a, 1))
  430. return 0;
  431. a[0] = a[3];
  432. a[1] = a[4];
  433. a[2] = a[5];
  434. a[3] = a[6];
  435. a[4] = 0;
  436. a[5] = 0;
  437. if(m->bufp = strstr(m->buf, "kernel malloc")){
  438. while(m->bufp > m->buf && m->bufp[-1] != '\n')
  439. m->bufp--;
  440. a[4] = strtoull(m->bufp, &m->bufp, 10);
  441. while(*m->bufp++ == '/')
  442. a[5] = strtoull(m->bufp, &m->bufp, 10);
  443. }
  444. a[6] = 0;
  445. a[7] = 0;
  446. if(m->bufp = strstr(m->buf, "kernel draw")){
  447. while(m->bufp > m->buf && m->bufp[-1] != '\n')
  448. m->bufp--;
  449. a[6] = strtoull(m->bufp, &m->bufp, 10);
  450. while(*m->bufp++ == '/')
  451. a[7] = strtoull(m->bufp, &m->bufp, 10);
  452. }
  453. return 1;
  454. }
  455. a[4] = 0;
  456. a[5] = 0;
  457. a[6] = 0;
  458. a[7] = 0;
  459. return readnums(m, 4, a, 0);
  460. }
  461. char*
  462. shortname(char *s)
  463. {
  464. char *p, *e;
  465. p = estrdup(s);
  466. e = strchr(p, '.');
  467. if(e)
  468. *e = 0;
  469. return p;
  470. }
  471. int
  472. ilog10(uint64_t j)
  473. {
  474. int i;
  475. for(i = 0; j >= 10; i++)
  476. j /= 10;
  477. return i;
  478. }
  479. int
  480. initmach(Machine *m, char *name)
  481. {
  482. int n;
  483. uint64_t a[MAXNUM];
  484. char *p, mpt[256], buf[256];
  485. p = strchr(name, '!');
  486. if(p)
  487. p++;
  488. else
  489. p = name;
  490. m->name = estrdup(p);
  491. m->shortname = shortname(p);
  492. m->remote = (strcmp(p, mysysname) != 0);
  493. if(m->remote == 0)
  494. strcpy(mpt, "");
  495. else{
  496. Waitmsg *w;
  497. int pid;
  498. snprint(mpt, sizeof mpt, "/n/%s", p);
  499. snprint(buf, sizeof buf, "rimport %q / %q || import %q / %q", name, mpt, name, mpt);
  500. pid = fork();
  501. switch(pid){
  502. case -1:
  503. fprint(2, "can't fork: %r\n");
  504. return 0;
  505. case 0:
  506. execl("/cmd/rc", "rc", "-c", buf, nil);
  507. fprint(2, "can't exec: %r\n");
  508. exits("exec");
  509. }
  510. w = wait();
  511. if(w == nil || w->pid != pid || w->msg[0] != '\0'){
  512. free(w);
  513. return 0;
  514. }
  515. free(w);
  516. }
  517. snprint(buf, sizeof buf, "%s/dev/swap", mpt);
  518. m->swapfd = open(buf, OREAD);
  519. if(loadbuf(m, &m->swapfd) && readswap(m, a))
  520. memmove(m->devswap, a, sizeof m->devswap);
  521. snprint(buf, sizeof buf, "%s/dev/sysstat", mpt);
  522. m->statsfd = open(buf, OREAD);
  523. if(loadbuf(m, &m->statsfd)){
  524. for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++)
  525. ;
  526. m->nproc = n;
  527. }else
  528. m->nproc = 1;
  529. m->lgproc = ilog10(m->nproc);
  530. snprint(buf, sizeof buf, "%s/net/ether0/stats", mpt);
  531. m->etherfd = open(buf, OREAD);
  532. if(loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1))
  533. memmove(m->netetherstats, a, sizeof m->netetherstats);
  534. snprint(buf, sizeof buf, "%s/net/ether0/ifstats", mpt);
  535. m->ifstatsfd = open(buf, OREAD);
  536. if(loadbuf(m, &m->ifstatsfd)){
  537. /* need to check that this is a wavelan interface */
  538. if(strncmp(m->buf, "Signal: ", 8) == 0 && readnums(m, nelem(m->netetherifstats), a, 1))
  539. memmove(m->netetherifstats, a, sizeof m->netetherifstats);
  540. }
  541. snprint(buf, sizeof buf, "%s/mnt/apm/battery", mpt);
  542. m->batteryfd = open(buf, OREAD);
  543. m->bitsybatfd = -1;
  544. if(m->batteryfd >= 0){
  545. if(loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
  546. memmove(m->batterystats, a, sizeof(m->batterystats));
  547. }else{
  548. snprint(buf, sizeof buf, "%s/dev/battery", mpt);
  549. m->bitsybatfd = open(buf, OREAD);
  550. if(loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0))
  551. memmove(m->batterystats, a, sizeof(m->batterystats));
  552. }
  553. snprint(buf, sizeof buf, "%s/dev/cputemp", mpt);
  554. m->tempfd = open(buf, OREAD);
  555. if(loadbuf(m, &m->tempfd))
  556. for(n=0; n < nelem(m->temp) && readnums(m, 2, a, 0); n++)
  557. m->temp[n] = a[0];
  558. return 1;
  559. }
  560. jmp_buf catchalarm;
  561. int
  562. alarmed(void *a, char *s)
  563. {
  564. if(strcmp(s, "alarm") == 0)
  565. notejmp(a, catchalarm, 1);
  566. return 0;
  567. }
  568. int
  569. needswap(int init)
  570. {
  571. return init | present[Mmem] | present[Mswap] | present[Mkern] | present[Mdraw];
  572. }
  573. int
  574. needstat(int init)
  575. {
  576. return init | present[Mcontext] | present[Mfault] | present[Mintr] | present[Mload] | present[Midle] |
  577. present[Minintr] | present[Msyscall] | present[Mtlbmiss] | present[Mtlbpurge];
  578. }
  579. int
  580. needether(int init)
  581. {
  582. return init | present[Mether] | present[Metherin] | present[Metherout] | present[Methererr];
  583. }
  584. int
  585. needbattery(int init)
  586. {
  587. return init | present[Mbattery];
  588. }
  589. int
  590. needsignal(int init)
  591. {
  592. return init | present[Msignal];
  593. }
  594. int
  595. needtemp(int init)
  596. {
  597. return init | present[Mtemp];
  598. }
  599. void
  600. readmach(Machine *m, int init)
  601. {
  602. int n, i;
  603. uint64_t a[nelem(m->devsysstat)];
  604. char buf[32];
  605. if(m->remote && (m->disable || setjmp(catchalarm))){
  606. if (m->disable++ >= 5)
  607. m->disable = 0; /* give it another chance */
  608. memmove(m->devsysstat, m->prevsysstat, sizeof m->devsysstat);
  609. memmove(m->netetherstats, m->prevetherstats, sizeof m->netetherstats);
  610. return;
  611. }
  612. snprint(buf, sizeof buf, "%s", m->name);
  613. if (strcmp(m->name, buf) != 0){
  614. free(m->name);
  615. m->name = estrdup(buf);
  616. free(m->shortname);
  617. m->shortname = shortname(buf);
  618. if(display != nil) /* else we're still initializing */
  619. eresized(0);
  620. }
  621. if(m->remote){
  622. atnotify(alarmed, 1);
  623. alarm(5000);
  624. }
  625. if(needswap(init) && loadbuf(m, &m->swapfd) && readswap(m, a))
  626. memmove(m->devswap, a, sizeof m->devswap);
  627. if(needstat(init) && loadbuf(m, &m->statsfd)){
  628. memmove(m->prevsysstat, m->devsysstat, sizeof m->devsysstat);
  629. memset(m->devsysstat, 0, sizeof m->devsysstat);
  630. for(n=0; n<m->nproc && readnums(m, nelem(m->devsysstat), a, 0); n++)
  631. for(i=0; i<nelem(m->devsysstat); i++)
  632. m->devsysstat[i] += a[i];
  633. }
  634. if(needether(init) && loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)){
  635. memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats);
  636. memmove(m->netetherstats, a, sizeof m->netetherstats);
  637. }
  638. if(needsignal(init) && loadbuf(m, &m->ifstatsfd) && strncmp(m->buf, "Signal: ", 8)==0 && readnums(m, nelem(m->netetherifstats), a, 1)){
  639. memmove(m->netetherifstats, a, sizeof m->netetherifstats);
  640. }
  641. if(needbattery(init) && loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
  642. memmove(m->batterystats, a, sizeof(m->batterystats));
  643. if(needbattery(init) && loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0))
  644. memmove(m->batterystats, a, sizeof(m->batterystats));
  645. if(needtemp(init) && loadbuf(m, &m->tempfd))
  646. for(n=0; n < nelem(m->temp) && readnums(m, 2, a, 0); n++)
  647. m->temp[n] = a[0];
  648. if(m->remote){
  649. alarm(0);
  650. atnotify(alarmed, 0);
  651. }
  652. }
  653. void
  654. memval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  655. {
  656. *v = m->devswap[Mem];
  657. *vmax = m->devswap[Maxmem];
  658. if(*vmax == 0)
  659. *vmax = 1;
  660. }
  661. void
  662. swapval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  663. {
  664. *v = m->devswap[Swap];
  665. *vmax = m->devswap[Maxswap];
  666. if(*vmax == 0)
  667. *vmax = 1;
  668. }
  669. void
  670. kernval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  671. {
  672. *v = m->devswap[Kern];
  673. *vmax = m->devswap[Maxkern];
  674. if(*vmax == 0)
  675. *vmax = 1;
  676. }
  677. void
  678. drawval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  679. {
  680. *v = m->devswap[Draw];
  681. *vmax = m->devswap[Maxdraw];
  682. if(*vmax == 0)
  683. *vmax = 1;
  684. }
  685. void
  686. contextval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  687. {
  688. *v = (m->devsysstat[Context]-m->prevsysstat[Context])&0xffffffff;
  689. *vmax = sleeptime*m->nproc;
  690. if(init)
  691. *vmax = sleeptime;
  692. }
  693. /*
  694. * bug: need to factor in HZ
  695. */
  696. void
  697. intrval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  698. {
  699. *v = (m->devsysstat[Interrupt]-m->prevsysstat[Interrupt])&0xffffffff;
  700. *vmax = sleeptime*m->nproc*10;
  701. if(init)
  702. *vmax = sleeptime*10;
  703. }
  704. void
  705. syscallval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  706. {
  707. *v = (m->devsysstat[Syscall]-m->prevsysstat[Syscall])&0xffffffff;
  708. *vmax = sleeptime*m->nproc;
  709. if(init)
  710. *vmax = sleeptime;
  711. }
  712. void
  713. faultval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  714. {
  715. *v = (m->devsysstat[Fault]-m->prevsysstat[Fault])&0xffffffff;
  716. *vmax = sleeptime*m->nproc;
  717. if(init)
  718. *vmax = sleeptime;
  719. }
  720. void
  721. tlbmissval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  722. {
  723. *v = (m->devsysstat[TLBfault]-m->prevsysstat[TLBfault])&0xffffffff;
  724. *vmax = (sleeptime/1000)*10*m->nproc;
  725. if(init)
  726. *vmax = (sleeptime/1000)*10;
  727. }
  728. void
  729. tlbpurgeval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  730. {
  731. *v = (m->devsysstat[TLBpurge]-m->prevsysstat[TLBpurge])&0xffffffff;
  732. *vmax = (sleeptime/1000)*10*m->nproc;
  733. if(init)
  734. *vmax = (sleeptime/1000)*10;
  735. }
  736. void
  737. loadval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  738. {
  739. *v = m->devsysstat[Load];
  740. *vmax = 1000*m->nproc;
  741. if(init)
  742. *vmax = 1000;
  743. }
  744. void
  745. idleval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  746. {
  747. *v = m->devsysstat[Idle]/m->nproc;
  748. *vmax = 100;
  749. }
  750. void
  751. inintrval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  752. {
  753. *v = m->devsysstat[InIntr]/m->nproc;
  754. *vmax = 100;
  755. }
  756. void
  757. etherval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  758. {
  759. *v = m->netetherstats[In]-m->prevetherstats[In] + m->netetherstats[Out]-m->prevetherstats[Out];
  760. *vmax = sleeptime*m->nproc;
  761. if(init)
  762. *vmax = sleeptime;
  763. }
  764. void
  765. etherinval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  766. {
  767. *v = m->netetherstats[In]-m->prevetherstats[In];
  768. *vmax = sleeptime*m->nproc;
  769. if(init)
  770. *vmax = sleeptime;
  771. }
  772. void
  773. etheroutval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  774. {
  775. *v = m->netetherstats[Out]-m->prevetherstats[Out];
  776. *vmax = sleeptime*m->nproc;
  777. if(init)
  778. *vmax = sleeptime;
  779. }
  780. void
  781. ethererrval(Machine *m, uint64_t *v, uint64_t *vmax, int init)
  782. {
  783. int i;
  784. *v = 0;
  785. for(i=Err0; i<nelem(m->netetherstats); i++)
  786. *v += m->netetherstats[i];
  787. *vmax = (sleeptime/1000)*10*m->nproc;
  788. if(init)
  789. *vmax = (sleeptime/1000)*10;
  790. }
  791. void
  792. batteryval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  793. {
  794. *v = m->batterystats[0];
  795. if(m->bitsybatfd >= 0)
  796. *vmax = 184; // at least on my bitsy...
  797. else
  798. *vmax = 100;
  799. }
  800. void
  801. signalval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  802. {
  803. uint32_t l;
  804. *vmax = sleeptime;
  805. l = m->netetherifstats[0];
  806. /*
  807. * Range is seen to be from about -45 (strong) to -95 (weak); rescale
  808. */
  809. if(l == 0){ /* probably not present */
  810. *v = 0;
  811. return;
  812. }
  813. *v = 20*(l+95);
  814. }
  815. void
  816. tempval(Machine *m, uint64_t *v, uint64_t *vmax, int _)
  817. {
  818. uint32_t l;
  819. *vmax = sleeptime;
  820. l = m->temp[0];
  821. if(l == ~0 || l == 0)
  822. *v = 0;
  823. else
  824. *v = (l-20)*27;
  825. }
  826. void
  827. usage(void)
  828. {
  829. fprint(2, "usage: stats [-O] [-S scale] [-LY] [-%s] [machine...]\n", argchars);
  830. exits("usage");
  831. }
  832. void
  833. addgraph(int n)
  834. {
  835. Graph *g, *ograph;
  836. int i, j;
  837. static int nadd;
  838. if(n > nelem(menu2str))
  839. abort();
  840. /* avoid two adjacent graphs of same color */
  841. if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
  842. nadd++;
  843. ograph = graph;
  844. graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
  845. for(i=0; i<nmach; i++)
  846. for(j=0; j<ngraph; j++)
  847. graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
  848. free(ograph);
  849. ngraph++;
  850. for(i=0; i<nmach; i++){
  851. g = &graph[i*ngraph+(ngraph-1)];
  852. memset(g, 0, sizeof(Graph));
  853. g->label = menu2strtpl[n]+Opwid;
  854. g->newvalue = newvaluefn[n];
  855. g->update = update1; /* no other update functions yet */
  856. g->mach = &mach[i];
  857. g->colindex = nadd%Ncolor;
  858. }
  859. present[n] = 1;
  860. nadd++;
  861. }
  862. void
  863. dropgraph(int which)
  864. {
  865. Graph *ograph;
  866. int i, j, n;
  867. if(which > nelem(menu2str))
  868. abort();
  869. /* convert n to index in graph table */
  870. n = -1;
  871. for(i=0; i<ngraph; i++)
  872. if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
  873. n = i;
  874. break;
  875. }
  876. if(n < 0){
  877. fprint(2, "stats: internal error can't drop graph\n");
  878. killall("error");
  879. }
  880. ograph = graph;
  881. graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
  882. for(i=0; i<nmach; i++){
  883. for(j=0; j<n; j++)
  884. graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
  885. free(ograph[i*ngraph+j].data);
  886. freeimage(ograph[i*ngraph+j].overtmp);
  887. for(j++; j<ngraph; j++)
  888. graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
  889. }
  890. free(ograph);
  891. ngraph--;
  892. present[which] = 0;
  893. }
  894. int
  895. addmachine(char *name)
  896. {
  897. if(ngraph > 0){
  898. fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
  899. usage();
  900. }
  901. if(mach == nil)
  902. nmach = 0; /* a little dance to get us started with local machine by default */
  903. mach = erealloc(mach, (nmach+1)*sizeof(Machine));
  904. memset(mach+nmach, 0, sizeof(Machine));
  905. if (initmach(mach+nmach, name)){
  906. nmach++;
  907. return 1;
  908. } else
  909. return 0;
  910. }
  911. void
  912. labelstrs(Graph *g, char strs[Nlab][Lablen], int *np)
  913. {
  914. int j;
  915. uint64_t v, vmax;
  916. g->newvalue(g->mach, &v, &vmax, 1);
  917. if(vmax == 0)
  918. vmax = 1;
  919. if(logscale){
  920. for(j=1; j<=2; j++)
  921. sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);
  922. *np = 2;
  923. }else{
  924. for(j=1; j<=3; j++)
  925. sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);
  926. *np = 3;
  927. }
  928. }
  929. int
  930. labelwidth(void)
  931. {
  932. int i, j, n, w, maxw;
  933. char strs[Nlab][Lablen];
  934. maxw = 0;
  935. for(i=0; i<ngraph; i++){
  936. /* choose value for rightmost graph */
  937. labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);
  938. for(j=0; j<n; j++){
  939. w = stringwidth(font, strs[j]);
  940. if(w > maxw)
  941. maxw = w;
  942. }
  943. }
  944. return maxw;
  945. }
  946. void
  947. resize(void)
  948. {
  949. int i, j, k, n, startx, starty, x, y, dx, dy, ly, ondata, maxx, wid, nlab;
  950. Graph *g;
  951. Rectangle machr, r;
  952. uint64_t v, vmax;
  953. char buf[128], labs[Nlab][Lablen];
  954. draw(screen, screen->r, display->white, nil, ZP);
  955. /* label left edge */
  956. x = screen->r.min.x;
  957. y = screen->r.min.y + Labspace+font->height+Labspace;
  958. dy = (screen->r.max.y - y)/ngraph;
  959. dx = Labspace+stringwidth(font, "0")+Labspace;
  960. startx = x+dx+1;
  961. starty = y;
  962. for(i=0; i<ngraph; i++,y+=dy){
  963. draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
  964. draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
  965. label(Pt(x, y), dy, graph[i].label);
  966. draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
  967. }
  968. /* label top edge */
  969. dx = (screen->r.max.x - startx)/nmach;
  970. for(x=startx, i=0; i<nmach; i++,x+=dx){
  971. draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
  972. j = dx/stringwidth(font, "0");
  973. n = mach[i].nproc;
  974. if(n>1 && j>=1+3+mach[i].lgproc){ /* first char of name + (n) */
  975. j -= 3+mach[i].lgproc;
  976. if(j <= 0)
  977. j = 1;
  978. snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].shortname, n);
  979. }else
  980. snprint(buf, sizeof buf, "%.*s", j, mach[i].shortname);
  981. string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, font, buf);
  982. }
  983. maxx = screen->r.max.x;
  984. /* label right, if requested */
  985. if(ylabels && dy>Nlab*(font->height+1)){
  986. wid = labelwidth();
  987. if(wid < (maxx-startx)-30){
  988. /* else there's not enough room */
  989. maxx -= 1+Lx+wid;
  990. draw(screen, Rect(maxx, starty, maxx+1, screen->r.max.y), display->black, nil, ZP);
  991. y = starty;
  992. for(j=0; j<ngraph; j++, y+=dy){
  993. /* choose value for rightmost graph */
  994. g = &graph[ngraph*(nmach-1)+j];
  995. labelstrs(g, labs, &nlab);
  996. r = Rect(maxx+1, y, screen->r.max.x, y+dy-1);
  997. if(j == ngraph-1)
  998. r.max.y = screen->r.max.y;
  999. draw(screen, r, cols[g->colindex][0], nil, paritypt(r.min.x));
  1000. for(k=0; k<nlab; k++){
  1001. ly = y + (dy*(nlab-k)/(nlab+1));
  1002. draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
  1003. ly -= font->height/2;
  1004. string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, font, labs[k]);
  1005. }
  1006. }
  1007. }
  1008. }
  1009. /* create graphs */
  1010. for(i=0; i<nmach; i++){
  1011. machr = Rect(startx+i*dx, starty, maxx, screen->r.max.y);
  1012. if(i < nmach-1)
  1013. machr.max.x = startx+(i+1)*dx - 1;
  1014. y = starty;
  1015. for(j=0; j<ngraph; j++, y+=dy){
  1016. g = &graph[i*ngraph+j];
  1017. /* allocate data */
  1018. ondata = g->ndata;
  1019. g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */
  1020. g->data = erealloc(g->data, g->ndata*sizeof(uint32_t));
  1021. if(g->ndata > ondata)
  1022. memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(uint32_t));
  1023. /* set geometry */
  1024. g->r = machr;
  1025. g->r.min.y = y;
  1026. g->r.max.y = y+dy - 1;
  1027. if(j == ngraph-1)
  1028. g->r.max.y = screen->r.max.y;
  1029. draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
  1030. g->overflow = 0;
  1031. r = g->r;
  1032. r.max.y = r.min.y+font->height;
  1033. r.max.x = r.min.x+stringwidth(font, "999999999999");
  1034. freeimage(g->overtmp);
  1035. g->overtmp = nil;
  1036. if(r.max.x <= g->r.max.x)
  1037. g->overtmp = allocimage(display, r, screen->chan, 0, -1);
  1038. g->newvalue(g->mach, &v, &vmax, 0);
  1039. redraw(g, vmax);
  1040. }
  1041. }
  1042. flushimage(display, 1);
  1043. }
  1044. void
  1045. eresized(int new)
  1046. {
  1047. lockdisplay(display);
  1048. if(new && getwindow(display, Refnone) < 0) {
  1049. fprint(2, "stats: can't reattach to window\n");
  1050. killall("reattach");
  1051. }
  1052. resize();
  1053. unlockdisplay(display);
  1054. }
  1055. void
  1056. inputproc(void)
  1057. {
  1058. Event e;
  1059. int i;
  1060. for(;;){
  1061. switch(eread(Emouse|Ekeyboard, &e)){
  1062. case Emouse:
  1063. if(e.mouse.buttons == 4){
  1064. lockdisplay(display);
  1065. for(i=0; i<Nmenu2; i++)
  1066. if(present[i])
  1067. memmove(menu2str[i], "drop ", Opwid);
  1068. else
  1069. memmove(menu2str[i], "add ", Opwid);
  1070. i = emenuhit(3, &e.mouse, &menu2);
  1071. if(i >= 0){
  1072. if(!present[i])
  1073. addgraph(i);
  1074. else if(ngraph > 1)
  1075. dropgraph(i);
  1076. resize();
  1077. }
  1078. unlockdisplay(display);
  1079. }
  1080. break;
  1081. case Ekeyboard:
  1082. if(e.kbdc==Kdel || e.kbdc=='q')
  1083. killall(nil);
  1084. break;
  1085. }
  1086. }
  1087. }
  1088. void
  1089. startproc(void (*f)(void), int index)
  1090. {
  1091. int pid;
  1092. switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
  1093. case -1:
  1094. fprint(2, "stats: fork failed: %r\n");
  1095. killall("fork failed");
  1096. case 0:
  1097. f();
  1098. fprint(2, "stats: %s process exits\n", procnames[index]);
  1099. if(index >= 0)
  1100. killall("process died");
  1101. exits(nil);
  1102. }
  1103. if(index >= 0)
  1104. pids[index] = pid;
  1105. }
  1106. void
  1107. main(int argc, char *argv[])
  1108. {
  1109. int i, j;
  1110. double secs;
  1111. uint64_t v, vmax, nargs;
  1112. char args[100];
  1113. for(i=0; i<Nmenu2; i++){
  1114. menu2str[i] = malloc(strlen(menu2strtpl[i]) + 1);
  1115. strcpy(menu2str[i], menu2strtpl[i]);
  1116. }
  1117. quotefmtinstall();
  1118. nmach = 1;
  1119. mysysname = getenv(ENV_SYSNAME);
  1120. if(mysysname == nil){
  1121. fprint(2, "stats: can't find $" ENV_SYSNAME ": %r\n");
  1122. exits("sysname");
  1123. }
  1124. nargs = 0;
  1125. ARGBEGIN{
  1126. case 'T':
  1127. secs = atof(EARGF(usage()));
  1128. if(secs > 0)
  1129. sleeptime = 1000*secs;
  1130. break;
  1131. case 'S':
  1132. scale = atof(EARGF(usage()));
  1133. if(scale <= 0)
  1134. usage();
  1135. break;
  1136. case 'L':
  1137. logscale++;
  1138. break;
  1139. case 'Y':
  1140. ylabels++;
  1141. break;
  1142. case 'O':
  1143. break;
  1144. default:
  1145. if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
  1146. usage();
  1147. args[nargs++] = ARGC();
  1148. }ARGEND
  1149. if(argc == 0){
  1150. mach = emalloc(nmach*sizeof(Machine));
  1151. initmach(&mach[0], mysysname);
  1152. readmach(&mach[0], 1);
  1153. }else{
  1154. rfork(RFNAMEG);
  1155. for(i=j=0; i<argc; i++){
  1156. if (addmachine(argv[i]))
  1157. readmach(&mach[j++], 1);
  1158. }
  1159. if (j == 0)
  1160. exits("connect");
  1161. }
  1162. for(i=0; i<nargs; i++)
  1163. switch(args[i]){
  1164. default:
  1165. fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
  1166. usage();
  1167. case 'b':
  1168. addgraph(Mbattery);
  1169. break;
  1170. case 'c':
  1171. addgraph(Mcontext);
  1172. break;
  1173. case 'e':
  1174. addgraph(Mether);
  1175. break;
  1176. case 'E':
  1177. addgraph(Metherin);
  1178. addgraph(Metherout);
  1179. break;
  1180. case 'f':
  1181. addgraph(Mfault);
  1182. break;
  1183. case 'i':
  1184. addgraph(Mintr);
  1185. break;
  1186. case 'I':
  1187. addgraph(Mload);
  1188. addgraph(Midle);
  1189. addgraph(Minintr);
  1190. break;
  1191. case 'l':
  1192. addgraph(Mload);
  1193. break;
  1194. case 'm':
  1195. addgraph(Mmem);
  1196. break;
  1197. case 'n':
  1198. addgraph(Metherin);
  1199. addgraph(Metherout);
  1200. addgraph(Methererr);
  1201. break;
  1202. case 'p':
  1203. addgraph(Mtlbpurge);
  1204. break;
  1205. case 's':
  1206. addgraph(Msyscall);
  1207. break;
  1208. case 't':
  1209. addgraph(Mtlbmiss);
  1210. addgraph(Mtlbpurge);
  1211. break;
  1212. case '8':
  1213. addgraph(Msignal);
  1214. break;
  1215. case 'w':
  1216. addgraph(Mswap);
  1217. break;
  1218. case 'k':
  1219. addgraph(Mkern);
  1220. break;
  1221. case 'd':
  1222. addgraph(Mdraw);
  1223. break;
  1224. case 'z':
  1225. addgraph(Mtemp);
  1226. break;
  1227. }
  1228. if(ngraph == 0)
  1229. addgraph(Mload);
  1230. for(i=0; i<nmach; i++)
  1231. for(j=0; j<ngraph; j++)
  1232. graph[i*ngraph+j].mach = &mach[i];
  1233. if(initdraw(nil, nil, "stats") < 0){
  1234. fprint(2, "stats: initdraw failed: %r\n");
  1235. exits("initdraw");
  1236. }
  1237. display->locking = 1; /* tell library we're using the display lock */
  1238. colinit();
  1239. einit(Emouse|Ekeyboard);
  1240. startproc(inputproc, Inputproc);
  1241. pids[Mainproc] = getpid();
  1242. resize();
  1243. unlockdisplay(display); /* display is still locked from initdraw() */
  1244. for(;;){
  1245. for(i=0; i<nmach; i++)
  1246. readmach(&mach[i], 0);
  1247. lockdisplay(display);
  1248. parity = 1-parity;
  1249. for(i=0; i<nmach*ngraph; i++){
  1250. graph[i].newvalue(graph[i].mach, &v, &vmax, 0);
  1251. graph[i].update(&graph[i], v, vmax);
  1252. }
  1253. flushimage(display, 1);
  1254. unlockdisplay(display);
  1255. sleep(sleeptime);
  1256. }
  1257. }