trace.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #include <u.h>
  2. #include <tos.h>
  3. #include <libc.h>
  4. #include <thread.h>
  5. #include <ip.h>
  6. #include <bio.h>
  7. #include <stdio.h>
  8. #include <draw.h>
  9. #include <mouse.h>
  10. #include <cursor.h>
  11. #include <keyboard.h>
  12. #include "trace.h"
  13. #pragma varargck type "t" vlong
  14. #pragma varargck type "U" uvlong
  15. #define NS(x) ((vlong)x)
  16. #define US(x) (NS(x) * 1000ULL)
  17. #define MS(x) (US(x) * 1000ULL)
  18. #define S(x) (MS(x) * 1000ULL)
  19. #define numblocks(a, b) (((a) + (b) - 1) / (b))
  20. #define roundup(a, b) (numblocks((a), (b)) * (b))
  21. enum {
  22. OneRound = MS(1)/2LL,
  23. MilliRound = US(1)/2LL,
  24. };
  25. typedef struct Event Event;
  26. typedef struct Task Task;
  27. struct Event {
  28. Traceevent;
  29. vlong etime; /* length of block to draw */
  30. };
  31. struct Task {
  32. int pid;
  33. char *name;
  34. int nevents;
  35. Event *events;
  36. vlong tstart;
  37. vlong total;
  38. vlong runtime;
  39. vlong runmax;
  40. vlong runthis;
  41. long runs;
  42. ulong tevents[Nevent];
  43. };
  44. enum {
  45. Nevents = 1024,
  46. Ncolor = 6,
  47. K = 1024,
  48. };
  49. vlong now, prevts;
  50. int newwin;
  51. int Width = 1000;
  52. int Height = 100; // Per task
  53. int topmargin = 8;
  54. int bottommargin = 4;
  55. int lineht = 12;
  56. int wctlfd;
  57. int nevents;
  58. Traceevent *eventbuf;
  59. Event *event;
  60. void drawtrace(void);
  61. int schedparse(char*, char*, char*);
  62. int timeconv(Fmt*);
  63. char *schedstatename[] = {
  64. [SAdmit] = "Admit",
  65. [SSleep] = "Sleep",
  66. [SDead] = "Dead",
  67. [SDeadline] = "Deadline",
  68. [SEdf] = "Edf",
  69. [SExpel] = "Expel",
  70. [SReady] = "Ready",
  71. [SRelease] = "Release",
  72. [SRun] = "Run",
  73. [SSlice] = "Slice",
  74. [SInts] = "Ints",
  75. [SInte] = "Inte",
  76. [SUser] = "User",
  77. [SYield] = "Yield",
  78. };
  79. struct {
  80. vlong scale;
  81. vlong bigtics;
  82. vlong littletics;
  83. int sleep;
  84. } scales[] = {
  85. { US(500), US(100), US(50), 0},
  86. { US(1000), US(500), US(100), 0},
  87. { US(2000), US(1000), US(200), 0},
  88. { US(5000), US(1000), US(500), 0},
  89. { MS(10), MS(5), MS(1), 20},
  90. { MS(20), MS(10), MS(2), 20},
  91. { MS(50), MS(10), MS(5), 20},
  92. { MS(100), MS(50), MS(10), 20}, /* starting scaleno */
  93. { MS(200), MS(100), MS(20), 20},
  94. { MS(500), MS(100), MS(50), 50},
  95. { MS(1000), MS(500), MS(100), 100},
  96. { MS(2000), MS(1000), MS(200), 100},
  97. { MS(5000), MS(1000), MS(500), 100},
  98. { S(10), S(50), S(1), 100},
  99. { S(20), S(10), S(2), 100},
  100. { S(50), S(10), S(5), 100},
  101. { S(100), S(50), S(10), 100},
  102. { S(200), S(100), S(20), 100},
  103. { S(500), S(100), S(50), 100},
  104. { S(1000), S(500), S(100), 100},
  105. };
  106. int ntasks, verbose, triggerproc, paused;
  107. Task *tasks;
  108. Image *cols[Ncolor][4];
  109. Font *mediumfont, *tinyfont;
  110. Image *grey, *red, *green, *blue, *bg, *fg;
  111. char*profdev = "/proc/trace";
  112. static void
  113. usage(void)
  114. {
  115. fprint(2, "Usage: %s [-d profdev] [-w] [-v] [-t triggerproc] [processes]\n", argv0);
  116. exits(nil);
  117. }
  118. void
  119. threadmain(int argc, char **argv)
  120. {
  121. int fd, i;
  122. char fname[80];
  123. fmtinstall('t', timeconv);
  124. ARGBEGIN {
  125. case 'd':
  126. profdev = EARGF(usage());
  127. break;
  128. case 'v':
  129. verbose = 1;
  130. break;
  131. case 'w':
  132. newwin++;
  133. break;
  134. case 't':
  135. triggerproc = (int)strtol(EARGF(usage()), nil, 0);
  136. break;
  137. default:
  138. usage();
  139. }
  140. ARGEND;
  141. fname[sizeof fname - 1] = 0;
  142. for(i = 0; i < argc; i++){
  143. snprint(fname, sizeof fname - 2, "/proc/%s/ctl",
  144. argv[i]);
  145. if((fd = open(fname, OWRITE)) < 0){
  146. fprint(2, "%s: cannot open %s: %r\n",
  147. argv[0], fname);
  148. continue;
  149. }
  150. if(fprint(fd, "trace 1") < 0)
  151. fprint(2, "%s: cannot enable tracing on %s: %r\n",
  152. argv[0], fname);
  153. close(fd);
  154. }
  155. drawtrace();
  156. }
  157. static void
  158. mkcol(int i, int c0, int c1, int c2)
  159. {
  160. cols[i][0] = allocimagemix(display, c0, DWhite);
  161. cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1);
  162. cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2);
  163. cols[i][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c0);
  164. }
  165. static void
  166. colinit(void)
  167. {
  168. mediumfont = openfont(display, "/lib/font/bit/lucidasans/unicode.10.font");
  169. if(mediumfont == nil)
  170. mediumfont = font;
  171. tinyfont = openfont(display, "/lib/font/bit/lucidasans/unicode.7.font");
  172. if(tinyfont == nil)
  173. tinyfont = font;
  174. topmargin = mediumfont->height+2;
  175. bottommargin = tinyfont->height+2;
  176. /* Peach */
  177. mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
  178. /* Aqua */
  179. mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
  180. /* Yellow */
  181. mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
  182. /* Green */
  183. mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
  184. /* Blue */
  185. mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
  186. /* Grey */
  187. cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF);
  188. cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);
  189. cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF);
  190. cols[5][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);
  191. grey = cols[5][2];
  192. red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFF0000FF);
  193. green = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00FF00FF);
  194. blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF);
  195. bg = display->white;
  196. fg = display->black;
  197. }
  198. static void
  199. redraw(int scaleno)
  200. {
  201. int n, i, j, x;
  202. char buf[256];
  203. Point p, q;
  204. Rectangle r, rtime;
  205. Task *t;
  206. vlong ts, oldestts, newestts, period, ppp, scale, s, ss;
  207. # define time2x(t) ((int)(((t) - oldestts) / ppp))
  208. scale = scales[scaleno].scale;
  209. period = scale + scales[scaleno].littletics;
  210. ppp = period / Width; // period per pixel.
  211. /* Round `now' to a nice number */
  212. newestts = now - (now % scales[scaleno].bigtics) +
  213. (scales[scaleno].littletics>>1);
  214. oldestts = newestts - period;
  215. //print("newestts %t, period %t, %d-%d\n", newestts, period, time2x(oldestts), time2x(newestts));
  216. if (prevts < oldestts){
  217. oldestts = newestts - period;
  218. prevts = oldestts;
  219. draw(screen, screen->r, bg, nil, ZP);
  220. }else{
  221. /* just white out time */
  222. rtime = screen->r;
  223. rtime.min.x = rtime.max.x - stringwidth(mediumfont, "00000000000.000s");
  224. rtime.max.y = rtime.min.y + mediumfont->height;
  225. draw(screen, rtime, bg, nil, ZP);
  226. }
  227. p = screen->r.min;
  228. for (n = 0; n != ntasks; n++) {
  229. t = &tasks[n];
  230. /* p is upper left corner for this task */
  231. rtime = Rpt(p, addpt(p, Pt(500, mediumfont->height)));
  232. draw(screen, rtime, bg, nil, ZP);
  233. snprint(buf, sizeof(buf), "%d %s", t->pid, t->name);
  234. q = string(screen, p, fg, ZP, mediumfont, buf);
  235. s = now - t->tstart;
  236. if(t->tevents[SRelease])
  237. snprint(buf, sizeof(buf), " per %t — avg: %t max: %t",
  238. (vlong)(s/t->tevents[SRelease]),
  239. (vlong)(t->runtime/t->tevents[SRelease]),
  240. t->runmax);
  241. else if((s /=1000000000LL) != 0)
  242. snprint(buf, sizeof(buf), " per 1s — avg: %t total: %t",
  243. t->total/s,
  244. t->total);
  245. else
  246. snprint(buf, sizeof(buf), " total: %t", t->total);
  247. string(screen, q, fg, ZP, tinyfont, buf);
  248. p.y += Height;
  249. }
  250. x = time2x(prevts);
  251. p = screen->r.min;
  252. for (n = 0; n != ntasks; n++) {
  253. t = &tasks[n];
  254. /* p is upper left corner for this task */
  255. /* Move part already drawn */
  256. r = Rect(p.x, p.y + topmargin, p.x + x, p.y+Height);
  257. draw(screen, r, screen, nil, Pt(p.x + Width - x, p.y + topmargin));
  258. r.max.x = screen->r.max.x;
  259. r.min.x += x;
  260. draw(screen, r, bg, nil, ZP);
  261. line(screen, addpt(p, Pt(x, Height - lineht)), Pt(screen->r.max.x, p.y + Height - lineht),
  262. Endsquare, Endsquare, 0, cols[n % Ncolor][1], ZP);
  263. for (i = 0; i < t->nevents-1; i++)
  264. if (prevts < t->events[i + 1].time)
  265. break;
  266. if (i > 0) {
  267. memmove(t->events, t->events + i, (t->nevents - i) * sizeof(Event));
  268. t->nevents -= i;
  269. }
  270. for (i = 0; i != t->nevents; i++) {
  271. Event *e = &t->events[i], *_e;
  272. int sx, ex;
  273. switch (e->etype & 0xffff) {
  274. case SAdmit:
  275. if (e->time > prevts && e->time <= newestts) {
  276. sx = time2x(e->time);
  277. line(screen, addpt(p, Pt(sx, topmargin)),
  278. addpt(p, Pt(sx, Height - bottommargin)),
  279. Endarrow, Endsquare, 1, green, ZP);
  280. }
  281. break;
  282. case SExpel:
  283. if (e->time > prevts && e->time <= newestts) {
  284. sx = time2x(e->time);
  285. line(screen, addpt(p, Pt(sx, topmargin)),
  286. addpt(p, Pt(sx, Height - bottommargin)),
  287. Endsquare, Endarrow, 1, red, ZP);
  288. }
  289. break;
  290. case SRelease:
  291. if (e->time > prevts && e->time <= newestts) {
  292. sx = time2x(e->time);
  293. line(screen, addpt(p, Pt(sx, topmargin)),
  294. addpt(p, Pt(sx, Height - bottommargin)),
  295. Endarrow, Endsquare, 1, fg, ZP);
  296. }
  297. break;
  298. case SDeadline:
  299. if (e->time > prevts && e->time <= newestts) {
  300. sx = time2x(e->time);
  301. line(screen, addpt(p, Pt(sx, topmargin)),
  302. addpt(p, Pt(sx, Height - bottommargin)),
  303. Endsquare, Endarrow, 1, fg, ZP);
  304. }
  305. break;
  306. case SYield:
  307. case SUser:
  308. if (e->time > prevts && e->time <= newestts) {
  309. sx = time2x(e->time);
  310. line(screen, addpt(p, Pt(sx, topmargin)),
  311. addpt(p, Pt(sx, Height - bottommargin)),
  312. Endsquare, Endarrow, 0,
  313. (e->etype == SYield)? green: blue, ZP);
  314. }
  315. break;
  316. case SSlice:
  317. if (e->time > prevts && e->time <= newestts) {
  318. sx = time2x(e->time);
  319. line(screen, addpt(p, Pt(sx, topmargin)),
  320. addpt(p, Pt(sx, Height - bottommargin)),
  321. Endsquare, Endarrow, 0, red, ZP);
  322. }
  323. break;
  324. case SRun:
  325. case SEdf:
  326. sx = time2x(e->time);
  327. ex = time2x(e->etime);
  328. if(ex == sx)
  329. ex++;
  330. r = Rect(sx, topmargin + 8, ex, Height - lineht);
  331. r = rectaddpt(r, p);
  332. draw(screen, r, cols[n % Ncolor][e->etype==SRun?1:3], nil, ZP);
  333. if(t->pid == triggerproc && ex < Width)
  334. paused ^= 1;
  335. for(j = 0; j < t->nevents; j++){
  336. _e = &t->events[j];
  337. switch(_e->etype & 0xffff){
  338. case SInts:
  339. if (_e->time > prevts && _e->time <= newestts){
  340. sx = time2x(_e->time);
  341. line(screen, addpt(p, Pt(sx, topmargin)),
  342. addpt(p, Pt(sx, Height / 2 - bottommargin)),
  343. Endsquare, Endsquare, 0,
  344. green, ZP);
  345. }
  346. break;
  347. case SInte:
  348. if (_e->time > prevts && _e->time <= newestts) {
  349. sx = time2x(_e->time);
  350. line(screen, addpt(p, Pt(sx, Height / 2 - bottommargin)),
  351. addpt(p, Pt(sx, Height - bottommargin)),
  352. Endsquare, Endsquare, 0,
  353. blue, ZP);
  354. }
  355. break;
  356. }
  357. }
  358. break;
  359. }
  360. }
  361. p.y += Height;
  362. }
  363. ts = prevts + scales[scaleno].littletics - (prevts % scales[scaleno].littletics);
  364. x = time2x(ts);
  365. while(x < Width){
  366. p = screen->r.min;
  367. for(n = 0; n < ntasks; n++){
  368. int height, width;
  369. /* p is upper left corner for this task */
  370. if ((ts % scales[scaleno].scale) == 0){
  371. height = 10 * Height;
  372. width = 1;
  373. }else if ((ts % scales[scaleno].bigtics) == 0){
  374. height = 12 * Height;
  375. width = 0;
  376. }else{
  377. height = 13 * Height;
  378. width = 0;
  379. }
  380. height >>= 4;
  381. line(screen, addpt(p, Pt(x, height)), addpt(p, Pt(x, Height - lineht)),
  382. Endsquare, Endsquare, width, cols[n % Ncolor][2], ZP);
  383. p.y += Height;
  384. }
  385. ts += scales[scaleno].littletics;
  386. x = time2x(ts);
  387. }
  388. rtime = screen->r;
  389. rtime.min.y = rtime.max.y - tinyfont->height + 2;
  390. draw(screen, rtime, bg, nil, ZP);
  391. ts = oldestts + scales[scaleno].bigtics - (oldestts % scales[scaleno].bigtics);
  392. x = time2x(ts);
  393. ss = 0;
  394. while(x < Width){
  395. snprint(buf, sizeof(buf), "%t", ss);
  396. string(screen, addpt(p, Pt(x - stringwidth(tinyfont, buf)/2, - tinyfont->height - 1)),
  397. fg, ZP, tinyfont, buf);
  398. ts += scales[scaleno].bigtics;
  399. ss += scales[scaleno].bigtics;
  400. x = time2x(ts);
  401. }
  402. snprint(buf, sizeof(buf), "%t", now);
  403. string(screen, Pt(screen->r.max.x - stringwidth(mediumfont, buf), screen->r.min.y),
  404. fg, ZP, mediumfont, buf);
  405. flushimage(display, 1);
  406. prevts = newestts;
  407. }
  408. Task*
  409. newtask(ulong pid)
  410. {
  411. Task *t;
  412. char buf[64], *p;
  413. int fd,n;
  414. tasks = realloc(tasks, (ntasks + 1) * sizeof(Task));
  415. assert(tasks);
  416. t = &tasks[ntasks++];
  417. memset(t, 0, sizeof(Task));
  418. t->events = nil;
  419. snprint(buf, sizeof buf, "/proc/%ld/status", pid);
  420. t->name = nil;
  421. fd = open(buf, OREAD);
  422. if (fd >= 0){
  423. n = read(fd, buf, sizeof buf);
  424. if(n > 0){
  425. p = buf + sizeof buf - 1;
  426. *p = 0;
  427. p = strchr(buf, ' ');
  428. if (p) *p = 0;
  429. t->name = strdup(buf);
  430. }else
  431. print("%s: %r\n", buf);
  432. close(fd);
  433. }else
  434. print("%s: %r\n", buf);
  435. t->pid = pid;
  436. prevts = 0;
  437. if (newwin){
  438. fprint(wctlfd, "resize -dx %d -dy %d\n",
  439. Width + 20, (ntasks * Height) + 5);
  440. }else
  441. Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);
  442. return t;
  443. }
  444. void
  445. doevent(Task *t, Traceevent *ep)
  446. {
  447. int i, n;
  448. Event *event;
  449. vlong runt;
  450. t->tevents[ep->etype & 0xffff]++;
  451. n = t->nevents++;
  452. t->events = realloc(t->events, t->nevents*sizeof(Event));
  453. assert(t->events);
  454. event = &t->events[n];
  455. memmove(event, ep, sizeof(Traceevent));
  456. event->etime = 0;
  457. switch(event->etype & 0xffff){
  458. case SRelease:
  459. if (t->runthis > t->runmax)
  460. t->runmax = t->runthis;
  461. t->runthis = 0;
  462. break;
  463. case SSleep:
  464. case SYield:
  465. case SReady:
  466. case SSlice:
  467. for(i = n-1; i >= 0; i--)
  468. if (t->events[i].etype == SRun ||
  469. t->events[i].etype == SEdf)
  470. break;
  471. if(i < 0 || t->events[i].etime != 0)
  472. break;
  473. runt = event->time - t->events[i].time;
  474. if(runt > 0){
  475. t->events[i].etime = event->time;
  476. t->runtime += runt;
  477. t->total += runt;
  478. t->runthis += runt;
  479. t->runs++;
  480. }
  481. break;
  482. case SDead:
  483. print("task died %ld %t %s\n", event->pid, event->time, schedstatename[event->etype & 0xffff]);
  484. free(t->events);
  485. free(t->name);
  486. ntasks--;
  487. memmove(t, t+1, sizeof(Task)*(&tasks[ntasks]-t));
  488. if (newwin)
  489. fprint(wctlfd, "resize -dx %d -dy %d\n",
  490. Width + 20, (ntasks * Height) + 5);
  491. else
  492. Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);
  493. prevts = 0;
  494. }
  495. }
  496. void
  497. drawtrace(void)
  498. {
  499. char *wsys, line[256];
  500. int wfd, logfd;
  501. Mousectl *mousectl;
  502. Keyboardctl *keyboardctl;
  503. int scaleno;
  504. Rune r;
  505. int i, n;
  506. Task *t;
  507. Traceevent *ep;
  508. eventbuf = malloc(Nevents*sizeof(Traceevent));
  509. assert(eventbuf);
  510. if((logfd = open(profdev, OREAD)) < 0)
  511. sysfatal("%s: Cannot open %s: %r\n", argv0, profdev);
  512. if(newwin){
  513. if((wsys = getenv("wsys")) == nil)
  514. sysfatal("%s: Cannot find windowing system: %r\n",
  515. argv0);
  516. if((wfd = open(wsys, ORDWR)) < 0)
  517. sysfatal("%s: Cannot open windowing system: %r\n",
  518. argv0);
  519. snprint(line, sizeof(line), "new -pid %d -dx %d -dy %d",
  520. getpid(), Width + 20, Height + 5);
  521. line[sizeof(line) - 1] = '\0';
  522. rfork(RFNAMEG);
  523. if(mount(wfd, -1, "/mnt/wsys", MREPL, line) < 0)
  524. sysfatal("%s: Cannot mount %s under /mnt/wsys: %r\n",
  525. argv0, line);
  526. if(bind("/mnt/wsys", "/dev", MBEFORE) < 0)
  527. sysfatal("%s: Cannot bind /mnt/wsys in /dev: %r\n",
  528. argv0);
  529. }
  530. if((wctlfd = open("/dev/wctl", OWRITE)) < 0)
  531. sysfatal("%s: Cannot open /dev/wctl: %r\n", argv0);
  532. if(initdraw(nil, nil, "trace") < 0)
  533. sysfatal("%s: initdraw failure: %r\n", argv0);
  534. Width = Dx(screen->r);
  535. Height = Dy(screen->r);
  536. if((mousectl = initmouse(nil, screen)) == nil)
  537. sysfatal("%s: cannot initialize mouse: %r\n", argv0);
  538. if((keyboardctl = initkeyboard(nil)) == nil)
  539. sysfatal("%s: cannot initialize keyboard: %r\n", argv0);
  540. colinit();
  541. paused = 0;
  542. scaleno = 7; /* 100 milliseconds */
  543. now = nsec();
  544. while(1) {
  545. Alt a[] = {
  546. { mousectl->c, nil, CHANRCV },
  547. { mousectl->resizec, nil, CHANRCV },
  548. { keyboardctl->c, &r, CHANRCV },
  549. { nil, nil, CHANNOBLK },
  550. };
  551. switch (alt(a)) {
  552. case 0:
  553. continue;
  554. case 1:
  555. if(getwindow(display, Refnone) < 0)
  556. sysfatal("drawrt: Cannot re-attach window\n");
  557. if(newwin){
  558. if(Dx(screen->r) != Width ||
  559. Dy(screen->r) != (ntasks * Height)){
  560. fprint(2, "resize: x: have %d, need %d; y: have %d, need %d\n",
  561. Dx(screen->r), Width + 8, Dy(screen->r), (ntasks * Height) + 8);
  562. fprint(wctlfd, "resize -dx %d -dy %d\n",
  563. Width + 8, (ntasks * Height) + 8);
  564. }
  565. }
  566. else{
  567. Width = Dx(screen->r);
  568. Height = ntasks? Dy(screen->r)/ntasks:
  569. Dy(screen->r);
  570. }
  571. break;
  572. case 2:
  573. switch(r){
  574. case 'r':
  575. for(i = 0; i < ntasks; i++){
  576. tasks[i].tstart = now;
  577. tasks[i].total = 0;
  578. tasks[i].runtime = 0;
  579. tasks[i].runmax = 0;
  580. tasks[i].runthis = 0;
  581. tasks[i].runs = 0;
  582. memset(tasks[i].tevents, 0, Nevent*sizeof(ulong));
  583. }
  584. break;
  585. case 'p':
  586. paused ^= 1;
  587. prevts = 0;
  588. break;
  589. case '-':
  590. if (scaleno < nelem(scales) - 1)
  591. scaleno++;
  592. prevts = 0;
  593. break;
  594. case '+':
  595. if (scaleno > 0)
  596. scaleno--;
  597. prevts = 0;
  598. break;
  599. case 'q':
  600. threadexitsall(nil);
  601. case 'v':
  602. verbose ^= 1;
  603. default:
  604. break;
  605. }
  606. break;
  607. case 3:
  608. now = nsec();
  609. while((n = read(logfd, eventbuf, Nevents*sizeof(Traceevent))) > 0){
  610. assert((n % sizeof(Traceevent)) == 0);
  611. nevents = n / sizeof(Traceevent);
  612. for (ep = eventbuf; ep < eventbuf + nevents; ep++){
  613. if ((ep->etype & 0xffff) >= Nevent){
  614. print("%ld %t Illegal event %ld\n",
  615. ep->pid, ep->time, ep->etype & 0xffff);
  616. continue;
  617. }
  618. if (verbose)
  619. print("%ld %t %s\n",
  620. ep->pid, ep->time, schedstatename[ep->etype & 0xffff]);
  621. for(i = 0; i < ntasks; i++)
  622. if(tasks[i].pid == ep->pid)
  623. break;
  624. if(i == ntasks){
  625. t = newtask(ep->pid);
  626. t->tstart = ep->time;
  627. }else
  628. t = &tasks[i];
  629. doevent(t, ep);
  630. }
  631. }
  632. if(!paused)
  633. redraw(scaleno);
  634. }
  635. sleep(scales[scaleno].sleep);
  636. }
  637. }
  638. int
  639. timeconv(Fmt *f)
  640. {
  641. char buf[128], *sign;
  642. vlong t;
  643. buf[0] = 0;
  644. switch(f->r) {
  645. case 'U':
  646. t = va_arg(f->args, vlong);
  647. break;
  648. case 't': // vlong in nanoseconds
  649. t = va_arg(f->args, vlong);
  650. break;
  651. default:
  652. return fmtstrcpy(f, "(timeconv)");
  653. }
  654. if (t < 0) {
  655. sign = "-";
  656. t = -t;
  657. }else
  658. sign = "";
  659. if (t > S(1)){
  660. t += OneRound;
  661. sprint(buf, "%s%d.%.3ds", sign, (int)(t / S(1)), (int)(t % S(1))/1000000);
  662. }else if (t > MS(1)){
  663. t += MilliRound;
  664. sprint(buf, "%s%d.%.3dms", sign, (int)(t / MS(1)), (int)(t % MS(1))/1000);
  665. }else if (t > US(1))
  666. sprint(buf, "%s%d.%.3dµs", sign, (int)(t / US(1)), (int)(t % US(1)));
  667. else
  668. sprint(buf, "%s%dns", sign, (int)t);
  669. return fmtstrcpy(f, buf);
  670. }