trace.c 17 KB

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