stats.c 29 KB

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