137aecfafSDavid du Colombier #include <u.h>
237aecfafSDavid du Colombier #include <tos.h>
337aecfafSDavid du Colombier #include <libc.h>
437aecfafSDavid du Colombier #include <thread.h>
537aecfafSDavid du Colombier #include <ip.h>
637aecfafSDavid du Colombier #include <bio.h>
737aecfafSDavid du Colombier #include <draw.h>
837aecfafSDavid du Colombier #include <mouse.h>
937aecfafSDavid du Colombier #include <cursor.h>
1037aecfafSDavid du Colombier #include <keyboard.h>
1137aecfafSDavid du Colombier #include "trace.h"
1237aecfafSDavid du Colombier
1337aecfafSDavid du Colombier #pragma varargck type "t" vlong
1437aecfafSDavid du Colombier #pragma varargck type "U" uvlong
1537aecfafSDavid du Colombier
1637aecfafSDavid du Colombier #define NS(x) ((vlong)x)
1737aecfafSDavid du Colombier #define US(x) (NS(x) * 1000ULL)
1837aecfafSDavid du Colombier #define MS(x) (US(x) * 1000ULL)
1937aecfafSDavid du Colombier #define S(x) (MS(x) * 1000ULL)
2037aecfafSDavid du Colombier
2137aecfafSDavid du Colombier #define numblocks(a, b) (((a) + (b) - 1) / (b))
2237aecfafSDavid du Colombier #define roundup(a, b) (numblocks((a), (b)) * (b))
2337aecfafSDavid du Colombier
2437aecfafSDavid du Colombier enum {
2537aecfafSDavid du Colombier OneRound = MS(1)/2LL,
2637aecfafSDavid du Colombier MilliRound = US(1)/2LL,
2737aecfafSDavid du Colombier };
2837aecfafSDavid du Colombier
2937aecfafSDavid du Colombier typedef struct Event Event;
3037aecfafSDavid du Colombier typedef struct Task Task;
3137aecfafSDavid du Colombier struct Event {
3237aecfafSDavid du Colombier Traceevent;
3337aecfafSDavid du Colombier vlong etime; /* length of block to draw */
3437aecfafSDavid du Colombier };
3537aecfafSDavid du Colombier
3637aecfafSDavid du Colombier struct Task {
3737aecfafSDavid du Colombier int pid;
3837aecfafSDavid du Colombier char *name;
3937aecfafSDavid du Colombier int nevents;
4037aecfafSDavid du Colombier Event *events;
4137aecfafSDavid du Colombier vlong tstart;
4237aecfafSDavid du Colombier vlong total;
4337aecfafSDavid du Colombier vlong runtime;
4437aecfafSDavid du Colombier vlong runmax;
4537aecfafSDavid du Colombier vlong runthis;
4637aecfafSDavid du Colombier long runs;
4737aecfafSDavid du Colombier ulong tevents[Nevent];
4837aecfafSDavid du Colombier };
4937aecfafSDavid du Colombier
5037aecfafSDavid du Colombier enum {
5137aecfafSDavid du Colombier Nevents = 1024,
5237aecfafSDavid du Colombier Ncolor = 6,
5337aecfafSDavid du Colombier K = 1024,
5437aecfafSDavid du Colombier };
5537aecfafSDavid du Colombier
5637aecfafSDavid du Colombier vlong now, prevts;
5737aecfafSDavid du Colombier
5837aecfafSDavid du Colombier int newwin;
5937aecfafSDavid du Colombier int Width = 1000;
6037aecfafSDavid du Colombier int Height = 100; // Per task
6137aecfafSDavid du Colombier int topmargin = 8;
6237aecfafSDavid du Colombier int bottommargin = 4;
6337aecfafSDavid du Colombier int lineht = 12;
6437aecfafSDavid du Colombier int wctlfd;
6537aecfafSDavid du Colombier int nevents;
6637aecfafSDavid du Colombier Traceevent *eventbuf;
6737aecfafSDavid du Colombier Event *event;
6837aecfafSDavid du Colombier
6937aecfafSDavid du Colombier void drawtrace(void);
7037aecfafSDavid du Colombier int schedparse(char*, char*, char*);
7137aecfafSDavid du Colombier int timeconv(Fmt*);
7237aecfafSDavid du Colombier
7337aecfafSDavid du Colombier char *schedstatename[] = {
7437aecfafSDavid du Colombier [SAdmit] = "Admit",
7537aecfafSDavid du Colombier [SSleep] = "Sleep",
7637aecfafSDavid du Colombier [SDead] = "Dead",
7737aecfafSDavid du Colombier [SDeadline] = "Deadline",
7837aecfafSDavid du Colombier [SEdf] = "Edf",
7937aecfafSDavid du Colombier [SExpel] = "Expel",
8037aecfafSDavid du Colombier [SReady] = "Ready",
8137aecfafSDavid du Colombier [SRelease] = "Release",
8237aecfafSDavid du Colombier [SRun] = "Run",
8337aecfafSDavid du Colombier [SSlice] = "Slice",
8437aecfafSDavid du Colombier [SInts] = "Ints",
8537aecfafSDavid du Colombier [SInte] = "Inte",
8637aecfafSDavid du Colombier [SUser] = "User",
8737aecfafSDavid du Colombier [SYield] = "Yield",
8837aecfafSDavid du Colombier };
8937aecfafSDavid du Colombier
9037aecfafSDavid du Colombier struct {
9137aecfafSDavid du Colombier vlong scale;
9237aecfafSDavid du Colombier vlong bigtics;
9337aecfafSDavid du Colombier vlong littletics;
9437aecfafSDavid du Colombier int sleep;
9537aecfafSDavid du Colombier } scales[] = {
9637aecfafSDavid du Colombier { US(500), US(100), US(50), 0},
9737aecfafSDavid du Colombier { US(1000), US(500), US(100), 0},
9837aecfafSDavid du Colombier { US(2000), US(1000), US(200), 0},
9937aecfafSDavid du Colombier { US(5000), US(1000), US(500), 0},
10037aecfafSDavid du Colombier { MS(10), MS(5), MS(1), 20},
10137aecfafSDavid du Colombier { MS(20), MS(10), MS(2), 20},
10237aecfafSDavid du Colombier { MS(50), MS(10), MS(5), 20},
10337aecfafSDavid du Colombier { MS(100), MS(50), MS(10), 20}, /* starting scaleno */
10437aecfafSDavid du Colombier { MS(200), MS(100), MS(20), 20},
10537aecfafSDavid du Colombier { MS(500), MS(100), MS(50), 50},
10637aecfafSDavid du Colombier { MS(1000), MS(500), MS(100), 100},
10737aecfafSDavid du Colombier { MS(2000), MS(1000), MS(200), 100},
10837aecfafSDavid du Colombier { MS(5000), MS(1000), MS(500), 100},
10937aecfafSDavid du Colombier { S(10), S(50), S(1), 100},
11037aecfafSDavid du Colombier { S(20), S(10), S(2), 100},
11137aecfafSDavid du Colombier { S(50), S(10), S(5), 100},
11237aecfafSDavid du Colombier { S(100), S(50), S(10), 100},
11337aecfafSDavid du Colombier { S(200), S(100), S(20), 100},
11437aecfafSDavid du Colombier { S(500), S(100), S(50), 100},
11537aecfafSDavid du Colombier { S(1000), S(500), S(100), 100},
11637aecfafSDavid du Colombier };
11737aecfafSDavid du Colombier
11815174232SDavid du Colombier int ntasks, verbose, triggerproc, paused;
11937aecfafSDavid du Colombier Task *tasks;
12037aecfafSDavid du Colombier Image *cols[Ncolor][4];
12137aecfafSDavid du Colombier Font *mediumfont, *tinyfont;
12237aecfafSDavid du Colombier Image *grey, *red, *green, *blue, *bg, *fg;
12337aecfafSDavid du Colombier char*profdev = "/proc/trace";
12437aecfafSDavid du Colombier
12537aecfafSDavid du Colombier static void
usage(void)12637aecfafSDavid du Colombier usage(void)
12737aecfafSDavid du Colombier {
12815174232SDavid du Colombier fprint(2, "Usage: %s [-d profdev] [-w] [-v] [-t triggerproc] [processes]\n", argv0);
12937aecfafSDavid du Colombier exits(nil);
13037aecfafSDavid du Colombier }
13137aecfafSDavid du Colombier
13237aecfafSDavid du Colombier void
threadmain(int argc,char ** argv)13337aecfafSDavid du Colombier threadmain(int argc, char **argv)
13437aecfafSDavid du Colombier {
13537aecfafSDavid du Colombier int fd, i;
13637aecfafSDavid du Colombier char fname[80];
13737aecfafSDavid du Colombier
13837aecfafSDavid du Colombier fmtinstall('t', timeconv);
13937aecfafSDavid du Colombier ARGBEGIN {
14037aecfafSDavid du Colombier case 'd':
14137aecfafSDavid du Colombier profdev = EARGF(usage());
14237aecfafSDavid du Colombier break;
14337aecfafSDavid du Colombier case 'v':
14437aecfafSDavid du Colombier verbose = 1;
14537aecfafSDavid du Colombier break;
14637aecfafSDavid du Colombier case 'w':
14737aecfafSDavid du Colombier newwin++;
14837aecfafSDavid du Colombier break;
14915174232SDavid du Colombier case 't':
15015174232SDavid du Colombier triggerproc = (int)strtol(EARGF(usage()), nil, 0);
15115174232SDavid du Colombier break;
15237aecfafSDavid du Colombier default:
15337aecfafSDavid du Colombier usage();
15437aecfafSDavid du Colombier }
15537aecfafSDavid du Colombier ARGEND;
15637aecfafSDavid du Colombier
15737aecfafSDavid du Colombier fname[sizeof fname - 1] = 0;
15837aecfafSDavid du Colombier for(i = 0; i < argc; i++){
15937aecfafSDavid du Colombier snprint(fname, sizeof fname - 2, "/proc/%s/ctl",
16037aecfafSDavid du Colombier argv[i]);
16137aecfafSDavid du Colombier if((fd = open(fname, OWRITE)) < 0){
16237aecfafSDavid du Colombier fprint(2, "%s: cannot open %s: %r\n",
16337aecfafSDavid du Colombier argv[0], fname);
16437aecfafSDavid du Colombier continue;
16537aecfafSDavid du Colombier }
16637aecfafSDavid du Colombier
167375daca8SDavid du Colombier if(fprint(fd, "trace 1") < 0)
16837aecfafSDavid du Colombier fprint(2, "%s: cannot enable tracing on %s: %r\n",
16937aecfafSDavid du Colombier argv[0], fname);
17037aecfafSDavid du Colombier close(fd);
17137aecfafSDavid du Colombier }
17237aecfafSDavid du Colombier
17337aecfafSDavid du Colombier drawtrace();
17437aecfafSDavid du Colombier }
17537aecfafSDavid du Colombier
17637aecfafSDavid du Colombier static void
mkcol(int i,int c0,int c1,int c2)17737aecfafSDavid du Colombier mkcol(int i, int c0, int c1, int c2)
17837aecfafSDavid du Colombier {
17937aecfafSDavid du Colombier cols[i][0] = allocimagemix(display, c0, DWhite);
18037aecfafSDavid du Colombier cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1);
18137aecfafSDavid du Colombier cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2);
18237aecfafSDavid du Colombier cols[i][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c0);
18337aecfafSDavid du Colombier }
18437aecfafSDavid du Colombier
18537aecfafSDavid du Colombier static void
colinit(void)18637aecfafSDavid du Colombier colinit(void)
18737aecfafSDavid du Colombier {
18837aecfafSDavid du Colombier mediumfont = openfont(display, "/lib/font/bit/lucidasans/unicode.10.font");
18937aecfafSDavid du Colombier if(mediumfont == nil)
19037aecfafSDavid du Colombier mediumfont = font;
19137aecfafSDavid du Colombier tinyfont = openfont(display, "/lib/font/bit/lucidasans/unicode.7.font");
19237aecfafSDavid du Colombier if(tinyfont == nil)
19337aecfafSDavid du Colombier tinyfont = font;
19437aecfafSDavid du Colombier topmargin = mediumfont->height+2;
19537aecfafSDavid du Colombier bottommargin = tinyfont->height+2;
19637aecfafSDavid du Colombier
19737aecfafSDavid du Colombier /* Peach */
19837aecfafSDavid du Colombier mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
19937aecfafSDavid du Colombier /* Aqua */
20037aecfafSDavid du Colombier mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
20137aecfafSDavid du Colombier /* Yellow */
20237aecfafSDavid du Colombier mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
20337aecfafSDavid du Colombier /* Green */
20437aecfafSDavid du Colombier mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
20537aecfafSDavid du Colombier /* Blue */
20637aecfafSDavid du Colombier mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
20737aecfafSDavid du Colombier /* Grey */
20837aecfafSDavid du Colombier cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF);
20937aecfafSDavid du Colombier cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);
21037aecfafSDavid du Colombier cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF);
21137aecfafSDavid du Colombier cols[5][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);
21237aecfafSDavid du Colombier grey = cols[5][2];
21337aecfafSDavid du Colombier red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFF0000FF);
21437aecfafSDavid du Colombier green = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00FF00FF);
21537aecfafSDavid du Colombier blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF);
21637aecfafSDavid du Colombier bg = display->white;
21737aecfafSDavid du Colombier fg = display->black;
21837aecfafSDavid du Colombier }
21937aecfafSDavid du Colombier
22037aecfafSDavid du Colombier static void
redraw(int scaleno)22137aecfafSDavid du Colombier redraw(int scaleno)
22237aecfafSDavid du Colombier {
22337aecfafSDavid du Colombier int n, i, j, x;
22437aecfafSDavid du Colombier char buf[256];
22537aecfafSDavid du Colombier Point p, q;
22637aecfafSDavid du Colombier Rectangle r, rtime;
22737aecfafSDavid du Colombier Task *t;
228375daca8SDavid du Colombier vlong ts, oldestts, newestts, period, ppp, scale, s, ss;
22937aecfafSDavid du Colombier
23037aecfafSDavid du Colombier # define time2x(t) ((int)(((t) - oldestts) / ppp))
23137aecfafSDavid du Colombier
23237aecfafSDavid du Colombier scale = scales[scaleno].scale;
23337aecfafSDavid du Colombier period = scale + scales[scaleno].littletics;
23437aecfafSDavid du Colombier ppp = period / Width; // period per pixel.
23537aecfafSDavid du Colombier
23637aecfafSDavid du Colombier /* Round `now' to a nice number */
23737aecfafSDavid du Colombier newestts = now - (now % scales[scaleno].bigtics) +
23837aecfafSDavid du Colombier (scales[scaleno].littletics>>1);
23937aecfafSDavid du Colombier
24037aecfafSDavid du Colombier oldestts = newestts - period;
24137aecfafSDavid du Colombier
24237aecfafSDavid du Colombier //print("newestts %t, period %t, %d-%d\n", newestts, period, time2x(oldestts), time2x(newestts));
24337aecfafSDavid du Colombier if (prevts < oldestts){
24437aecfafSDavid du Colombier oldestts = newestts - period;
24537aecfafSDavid du Colombier
24637aecfafSDavid du Colombier prevts = oldestts;
24737aecfafSDavid du Colombier draw(screen, screen->r, bg, nil, ZP);
24837aecfafSDavid du Colombier }else{
24937aecfafSDavid du Colombier /* just white out time */
25037aecfafSDavid du Colombier rtime = screen->r;
25137aecfafSDavid du Colombier rtime.min.x = rtime.max.x - stringwidth(mediumfont, "00000000000.000s");
25237aecfafSDavid du Colombier rtime.max.y = rtime.min.y + mediumfont->height;
25337aecfafSDavid du Colombier draw(screen, rtime, bg, nil, ZP);
25437aecfafSDavid du Colombier }
25537aecfafSDavid du Colombier p = screen->r.min;
25637aecfafSDavid du Colombier for (n = 0; n != ntasks; n++) {
25737aecfafSDavid du Colombier t = &tasks[n];
25837aecfafSDavid du Colombier /* p is upper left corner for this task */
25937aecfafSDavid du Colombier rtime = Rpt(p, addpt(p, Pt(500, mediumfont->height)));
26037aecfafSDavid du Colombier draw(screen, rtime, bg, nil, ZP);
26137aecfafSDavid du Colombier snprint(buf, sizeof(buf), "%d %s", t->pid, t->name);
26237aecfafSDavid du Colombier q = string(screen, p, fg, ZP, mediumfont, buf);
26337aecfafSDavid du Colombier s = now - t->tstart;
26437aecfafSDavid du Colombier if(t->tevents[SRelease])
26537aecfafSDavid du Colombier snprint(buf, sizeof(buf), " per %t — avg: %t max: %t",
26637aecfafSDavid du Colombier (vlong)(s/t->tevents[SRelease]),
26737aecfafSDavid du Colombier (vlong)(t->runtime/t->tevents[SRelease]),
26837aecfafSDavid du Colombier t->runmax);
26937aecfafSDavid du Colombier else if((s /=1000000000LL) != 0)
27037aecfafSDavid du Colombier snprint(buf, sizeof(buf), " per 1s — avg: %t total: %t",
27137aecfafSDavid du Colombier t->total/s,
27237aecfafSDavid du Colombier t->total);
27337aecfafSDavid du Colombier else
27437aecfafSDavid du Colombier snprint(buf, sizeof(buf), " total: %t", t->total);
27537aecfafSDavid du Colombier string(screen, q, fg, ZP, tinyfont, buf);
27637aecfafSDavid du Colombier p.y += Height;
27737aecfafSDavid du Colombier }
27837aecfafSDavid du Colombier x = time2x(prevts);
27937aecfafSDavid du Colombier
28037aecfafSDavid du Colombier p = screen->r.min;
28137aecfafSDavid du Colombier for (n = 0; n != ntasks; n++) {
28237aecfafSDavid du Colombier t = &tasks[n];
28337aecfafSDavid du Colombier
28437aecfafSDavid du Colombier /* p is upper left corner for this task */
28537aecfafSDavid du Colombier
28637aecfafSDavid du Colombier /* Move part already drawn */
28737aecfafSDavid du Colombier r = Rect(p.x, p.y + topmargin, p.x + x, p.y+Height);
288375daca8SDavid du Colombier draw(screen, r, screen, nil, Pt(p.x + Width - x, p.y + topmargin));
28937aecfafSDavid du Colombier
29037aecfafSDavid du Colombier r.max.x = screen->r.max.x;
29137aecfafSDavid du Colombier r.min.x += x;
29237aecfafSDavid du Colombier draw(screen, r, bg, nil, ZP);
29337aecfafSDavid du Colombier
294375daca8SDavid du Colombier line(screen, addpt(p, Pt(x, Height - lineht)), Pt(screen->r.max.x, p.y + Height - lineht),
295375daca8SDavid du Colombier Endsquare, Endsquare, 0, cols[n % Ncolor][1], ZP);
29637aecfafSDavid du Colombier
29737aecfafSDavid du Colombier for (i = 0; i < t->nevents-1; i++)
29837aecfafSDavid du Colombier if (prevts < t->events[i + 1].time)
29937aecfafSDavid du Colombier break;
30037aecfafSDavid du Colombier
30137aecfafSDavid du Colombier if (i > 0) {
302375daca8SDavid du Colombier memmove(t->events, t->events + i, (t->nevents - i) * sizeof(Event));
30337aecfafSDavid du Colombier t->nevents -= i;
30437aecfafSDavid du Colombier }
30537aecfafSDavid du Colombier
30637aecfafSDavid du Colombier for (i = 0; i != t->nevents; i++) {
30737aecfafSDavid du Colombier Event *e = &t->events[i], *_e;
30837aecfafSDavid du Colombier int sx, ex;
30937aecfafSDavid du Colombier
31037aecfafSDavid du Colombier switch (e->etype & 0xffff) {
31137aecfafSDavid du Colombier case SAdmit:
31237aecfafSDavid du Colombier if (e->time > prevts && e->time <= newestts) {
31337aecfafSDavid du Colombier sx = time2x(e->time);
31437aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
31537aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
31637aecfafSDavid du Colombier Endarrow, Endsquare, 1, green, ZP);
31737aecfafSDavid du Colombier }
31837aecfafSDavid du Colombier break;
31937aecfafSDavid du Colombier case SExpel:
32037aecfafSDavid du Colombier if (e->time > prevts && e->time <= newestts) {
32137aecfafSDavid du Colombier sx = time2x(e->time);
32237aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
32337aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
32437aecfafSDavid du Colombier Endsquare, Endarrow, 1, red, ZP);
32537aecfafSDavid du Colombier }
32637aecfafSDavid du Colombier break;
32737aecfafSDavid du Colombier case SRelease:
32837aecfafSDavid du Colombier if (e->time > prevts && e->time <= newestts) {
32937aecfafSDavid du Colombier sx = time2x(e->time);
33037aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
33137aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
33237aecfafSDavid du Colombier Endarrow, Endsquare, 1, fg, ZP);
33337aecfafSDavid du Colombier }
33437aecfafSDavid du Colombier break;
33537aecfafSDavid du Colombier case SDeadline:
33637aecfafSDavid du Colombier if (e->time > prevts && e->time <= newestts) {
33737aecfafSDavid du Colombier sx = time2x(e->time);
33837aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
33937aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
34037aecfafSDavid du Colombier Endsquare, Endarrow, 1, fg, ZP);
34137aecfafSDavid du Colombier }
34237aecfafSDavid du Colombier break;
34337aecfafSDavid du Colombier
34437aecfafSDavid du Colombier case SYield:
34537aecfafSDavid du Colombier case SUser:
34637aecfafSDavid du Colombier if (e->time > prevts && e->time <= newestts) {
34737aecfafSDavid du Colombier sx = time2x(e->time);
34837aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
34937aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
35037aecfafSDavid du Colombier Endsquare, Endarrow, 0,
35137aecfafSDavid du Colombier (e->etype == SYield)? green: blue, ZP);
35237aecfafSDavid du Colombier }
35337aecfafSDavid du Colombier break;
35437aecfafSDavid du Colombier case SSlice:
35537aecfafSDavid du Colombier if (e->time > prevts && e->time <= newestts) {
35637aecfafSDavid du Colombier sx = time2x(e->time);
35737aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
35837aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
35937aecfafSDavid du Colombier Endsquare, Endarrow, 0, red, ZP);
36037aecfafSDavid du Colombier }
36137aecfafSDavid du Colombier break;
36237aecfafSDavid du Colombier
36337aecfafSDavid du Colombier case SRun:
36437aecfafSDavid du Colombier case SEdf:
36537aecfafSDavid du Colombier sx = time2x(e->time);
36637aecfafSDavid du Colombier ex = time2x(e->etime);
36715174232SDavid du Colombier if(ex == sx)
36815174232SDavid du Colombier ex++;
36937aecfafSDavid du Colombier
37037aecfafSDavid du Colombier r = Rect(sx, topmargin + 8, ex, Height - lineht);
37137aecfafSDavid du Colombier r = rectaddpt(r, p);
37237aecfafSDavid du Colombier
37337aecfafSDavid du Colombier draw(screen, r, cols[n % Ncolor][e->etype==SRun?1:3], nil, ZP);
37437aecfafSDavid du Colombier
37515174232SDavid du Colombier if(t->pid == triggerproc && ex < Width)
37615174232SDavid du Colombier paused ^= 1;
37715174232SDavid du Colombier
37837aecfafSDavid du Colombier for(j = 0; j < t->nevents; j++){
37937aecfafSDavid du Colombier _e = &t->events[j];
38037aecfafSDavid du Colombier switch(_e->etype & 0xffff){
38137aecfafSDavid du Colombier case SInts:
38237aecfafSDavid du Colombier if (_e->time > prevts && _e->time <= newestts){
38337aecfafSDavid du Colombier sx = time2x(_e->time);
38437aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, topmargin)),
38537aecfafSDavid du Colombier addpt(p, Pt(sx, Height / 2 - bottommargin)),
38637aecfafSDavid du Colombier Endsquare, Endsquare, 0,
38737aecfafSDavid du Colombier green, ZP);
38837aecfafSDavid du Colombier }
38937aecfafSDavid du Colombier break;
39037aecfafSDavid du Colombier case SInte:
39137aecfafSDavid du Colombier if (_e->time > prevts && _e->time <= newestts) {
39237aecfafSDavid du Colombier sx = time2x(_e->time);
39337aecfafSDavid du Colombier line(screen, addpt(p, Pt(sx, Height / 2 - bottommargin)),
39437aecfafSDavid du Colombier addpt(p, Pt(sx, Height - bottommargin)),
39537aecfafSDavid du Colombier Endsquare, Endsquare, 0,
39637aecfafSDavid du Colombier blue, ZP);
39737aecfafSDavid du Colombier }
39837aecfafSDavid du Colombier break;
39937aecfafSDavid du Colombier }
40037aecfafSDavid du Colombier }
40137aecfafSDavid du Colombier break;
40237aecfafSDavid du Colombier }
40337aecfafSDavid du Colombier }
40437aecfafSDavid du Colombier p.y += Height;
40537aecfafSDavid du Colombier }
40637aecfafSDavid du Colombier
40737aecfafSDavid du Colombier ts = prevts + scales[scaleno].littletics - (prevts % scales[scaleno].littletics);
40837aecfafSDavid du Colombier x = time2x(ts);
40937aecfafSDavid du Colombier
41037aecfafSDavid du Colombier while(x < Width){
41137aecfafSDavid du Colombier p = screen->r.min;
41237aecfafSDavid du Colombier for(n = 0; n < ntasks; n++){
41337aecfafSDavid du Colombier int height, width;
41437aecfafSDavid du Colombier
41537aecfafSDavid du Colombier /* p is upper left corner for this task */
41637aecfafSDavid du Colombier if ((ts % scales[scaleno].scale) == 0){
41737aecfafSDavid du Colombier height = 10 * Height;
41837aecfafSDavid du Colombier width = 1;
41937aecfafSDavid du Colombier }else if ((ts % scales[scaleno].bigtics) == 0){
42037aecfafSDavid du Colombier height = 12 * Height;
42137aecfafSDavid du Colombier width = 0;
42237aecfafSDavid du Colombier }else{
42337aecfafSDavid du Colombier height = 13 * Height;
42437aecfafSDavid du Colombier width = 0;
42537aecfafSDavid du Colombier }
42637aecfafSDavid du Colombier height >>= 4;
42737aecfafSDavid du Colombier
42837aecfafSDavid du Colombier line(screen, addpt(p, Pt(x, height)), addpt(p, Pt(x, Height - lineht)),
42937aecfafSDavid du Colombier Endsquare, Endsquare, width, cols[n % Ncolor][2], ZP);
43037aecfafSDavid du Colombier
43137aecfafSDavid du Colombier p.y += Height;
43237aecfafSDavid du Colombier }
43337aecfafSDavid du Colombier ts += scales[scaleno].littletics;
43437aecfafSDavid du Colombier x = time2x(ts);
43537aecfafSDavid du Colombier }
43637aecfafSDavid du Colombier
43737aecfafSDavid du Colombier rtime = screen->r;
43837aecfafSDavid du Colombier rtime.min.y = rtime.max.y - tinyfont->height + 2;
43937aecfafSDavid du Colombier draw(screen, rtime, bg, nil, ZP);
44037aecfafSDavid du Colombier ts = oldestts + scales[scaleno].bigtics - (oldestts % scales[scaleno].bigtics);
44137aecfafSDavid du Colombier x = time2x(ts);
442375daca8SDavid du Colombier ss = 0;
44337aecfafSDavid du Colombier while(x < Width){
444375daca8SDavid du Colombier snprint(buf, sizeof(buf), "%t", ss);
44537aecfafSDavid du Colombier string(screen, addpt(p, Pt(x - stringwidth(tinyfont, buf)/2, - tinyfont->height - 1)),
44637aecfafSDavid du Colombier fg, ZP, tinyfont, buf);
44737aecfafSDavid du Colombier ts += scales[scaleno].bigtics;
448375daca8SDavid du Colombier ss += scales[scaleno].bigtics;
44937aecfafSDavid du Colombier x = time2x(ts);
45037aecfafSDavid du Colombier }
45137aecfafSDavid du Colombier
45237aecfafSDavid du Colombier snprint(buf, sizeof(buf), "%t", now);
45337aecfafSDavid du Colombier string(screen, Pt(screen->r.max.x - stringwidth(mediumfont, buf), screen->r.min.y),
45437aecfafSDavid du Colombier fg, ZP, mediumfont, buf);
45537aecfafSDavid du Colombier
45637aecfafSDavid du Colombier flushimage(display, 1);
45737aecfafSDavid du Colombier prevts = newestts;
45837aecfafSDavid du Colombier }
45937aecfafSDavid du Colombier
46037aecfafSDavid du Colombier Task*
newtask(ulong pid)46137aecfafSDavid du Colombier newtask(ulong pid)
46237aecfafSDavid du Colombier {
46337aecfafSDavid du Colombier Task *t;
46437aecfafSDavid du Colombier char buf[64], *p;
46537aecfafSDavid du Colombier int fd,n;
46637aecfafSDavid du Colombier
46737aecfafSDavid du Colombier tasks = realloc(tasks, (ntasks + 1) * sizeof(Task));
46837aecfafSDavid du Colombier assert(tasks);
46937aecfafSDavid du Colombier
47037aecfafSDavid du Colombier t = &tasks[ntasks++];
47137aecfafSDavid du Colombier memset(t, 0, sizeof(Task));
47237aecfafSDavid du Colombier t->events = nil;
47337aecfafSDavid du Colombier snprint(buf, sizeof buf, "/proc/%ld/status", pid);
47437aecfafSDavid du Colombier t->name = nil;
47537aecfafSDavid du Colombier fd = open(buf, OREAD);
47637aecfafSDavid du Colombier if (fd >= 0){
47737aecfafSDavid du Colombier n = read(fd, buf, sizeof buf);
47837aecfafSDavid du Colombier if(n > 0){
47937aecfafSDavid du Colombier p = buf + sizeof buf - 1;
48037aecfafSDavid du Colombier *p = 0;
48137aecfafSDavid du Colombier p = strchr(buf, ' ');
48237aecfafSDavid du Colombier if (p) *p = 0;
48337aecfafSDavid du Colombier t->name = strdup(buf);
48437aecfafSDavid du Colombier }else
48537aecfafSDavid du Colombier print("%s: %r\n", buf);
48637aecfafSDavid du Colombier close(fd);
48737aecfafSDavid du Colombier }else
48837aecfafSDavid du Colombier print("%s: %r\n", buf);
48937aecfafSDavid du Colombier t->pid = pid;
49037aecfafSDavid du Colombier prevts = 0;
49137aecfafSDavid du Colombier if (newwin){
49237aecfafSDavid du Colombier fprint(wctlfd, "resize -dx %d -dy %d\n",
49337aecfafSDavid du Colombier Width + 20, (ntasks * Height) + 5);
49437aecfafSDavid du Colombier }else
49537aecfafSDavid du Colombier Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);
49637aecfafSDavid du Colombier return t;
49737aecfafSDavid du Colombier }
49837aecfafSDavid du Colombier
49937aecfafSDavid du Colombier void
doevent(Task * t,Traceevent * ep)50037aecfafSDavid du Colombier doevent(Task *t, Traceevent *ep)
50137aecfafSDavid du Colombier {
50237aecfafSDavid du Colombier int i, n;
50337aecfafSDavid du Colombier Event *event;
50437aecfafSDavid du Colombier vlong runt;
50537aecfafSDavid du Colombier
50637aecfafSDavid du Colombier t->tevents[ep->etype & 0xffff]++;
50737aecfafSDavid du Colombier n = t->nevents++;
50837aecfafSDavid du Colombier t->events = realloc(t->events, t->nevents*sizeof(Event));
50937aecfafSDavid du Colombier assert(t->events);
51037aecfafSDavid du Colombier event = &t->events[n];
51137aecfafSDavid du Colombier memmove(event, ep, sizeof(Traceevent));
51237aecfafSDavid du Colombier event->etime = 0;
51337aecfafSDavid du Colombier
51437aecfafSDavid du Colombier switch(event->etype & 0xffff){
51537aecfafSDavid du Colombier case SRelease:
51637aecfafSDavid du Colombier if (t->runthis > t->runmax)
51737aecfafSDavid du Colombier t->runmax = t->runthis;
51837aecfafSDavid du Colombier t->runthis = 0;
51937aecfafSDavid du Colombier break;
52037aecfafSDavid du Colombier
52137aecfafSDavid du Colombier case SSleep:
52237aecfafSDavid du Colombier case SYield:
52337aecfafSDavid du Colombier case SReady:
52437aecfafSDavid du Colombier case SSlice:
52537aecfafSDavid du Colombier for(i = n-1; i >= 0; i--)
52637aecfafSDavid du Colombier if (t->events[i].etype == SRun ||
52737aecfafSDavid du Colombier t->events[i].etype == SEdf)
52837aecfafSDavid du Colombier break;
52937aecfafSDavid du Colombier if(i < 0 || t->events[i].etime != 0)
53037aecfafSDavid du Colombier break;
53137aecfafSDavid du Colombier runt = event->time - t->events[i].time;
53237aecfafSDavid du Colombier if(runt > 0){
53337aecfafSDavid du Colombier t->events[i].etime = event->time;
53437aecfafSDavid du Colombier t->runtime += runt;
53537aecfafSDavid du Colombier t->total += runt;
53637aecfafSDavid du Colombier t->runthis += runt;
53737aecfafSDavid du Colombier t->runs++;
53837aecfafSDavid du Colombier }
53937aecfafSDavid du Colombier break;
54037aecfafSDavid du Colombier case SDead:
54137aecfafSDavid du Colombier print("task died %ld %t %s\n", event->pid, event->time, schedstatename[event->etype & 0xffff]);
54237aecfafSDavid du Colombier free(t->events);
54337aecfafSDavid du Colombier free(t->name);
54437aecfafSDavid du Colombier ntasks--;
54537aecfafSDavid du Colombier memmove(t, t+1, sizeof(Task)*(&tasks[ntasks]-t));
54637aecfafSDavid du Colombier if (newwin)
54737aecfafSDavid du Colombier fprint(wctlfd, "resize -dx %d -dy %d\n",
54837aecfafSDavid du Colombier Width + 20, (ntasks * Height) + 5);
54937aecfafSDavid du Colombier else
55037aecfafSDavid du Colombier Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);
55137aecfafSDavid du Colombier prevts = 0;
55237aecfafSDavid du Colombier }
55337aecfafSDavid du Colombier }
55437aecfafSDavid du Colombier
55537aecfafSDavid du Colombier void
drawtrace(void)55637aecfafSDavid du Colombier drawtrace(void)
55737aecfafSDavid du Colombier {
55837aecfafSDavid du Colombier char *wsys, line[256];
55937aecfafSDavid du Colombier int wfd, logfd;
56037aecfafSDavid du Colombier Mousectl *mousectl;
56137aecfafSDavid du Colombier Keyboardctl *keyboardctl;
56237aecfafSDavid du Colombier int scaleno;
56337aecfafSDavid du Colombier Rune r;
56437aecfafSDavid du Colombier int i, n;
56537aecfafSDavid du Colombier Task *t;
56637aecfafSDavid du Colombier Traceevent *ep;
56737aecfafSDavid du Colombier
56837aecfafSDavid du Colombier eventbuf = malloc(Nevents*sizeof(Traceevent));
56937aecfafSDavid du Colombier assert(eventbuf);
57037aecfafSDavid du Colombier
57137aecfafSDavid du Colombier if((logfd = open(profdev, OREAD)) < 0)
572*14cc0f53SDavid du Colombier sysfatal("%s: Cannot open %s: %r", argv0, profdev);
57337aecfafSDavid du Colombier
57437aecfafSDavid du Colombier if(newwin){
57537aecfafSDavid du Colombier if((wsys = getenv("wsys")) == nil)
576*14cc0f53SDavid du Colombier sysfatal("%s: Cannot find windowing system: %r",
57737aecfafSDavid du Colombier argv0);
57837aecfafSDavid du Colombier
57937aecfafSDavid du Colombier if((wfd = open(wsys, ORDWR)) < 0)
580*14cc0f53SDavid du Colombier sysfatal("%s: Cannot open windowing system: %r",
58137aecfafSDavid du Colombier argv0);
58237aecfafSDavid du Colombier
58337aecfafSDavid du Colombier snprint(line, sizeof(line), "new -pid %d -dx %d -dy %d",
58437aecfafSDavid du Colombier getpid(), Width + 20, Height + 5);
58537aecfafSDavid du Colombier line[sizeof(line) - 1] = '\0';
58637aecfafSDavid du Colombier rfork(RFNAMEG);
58737aecfafSDavid du Colombier
58837aecfafSDavid du Colombier if(mount(wfd, -1, "/mnt/wsys", MREPL, line) < 0)
589*14cc0f53SDavid du Colombier sysfatal("%s: Cannot mount %s under /mnt/wsys: %r",
59037aecfafSDavid du Colombier argv0, line);
59137aecfafSDavid du Colombier
59237aecfafSDavid du Colombier if(bind("/mnt/wsys", "/dev", MBEFORE) < 0)
593*14cc0f53SDavid du Colombier sysfatal("%s: Cannot bind /mnt/wsys in /dev: %r",
59437aecfafSDavid du Colombier argv0);
59537aecfafSDavid du Colombier
59637aecfafSDavid du Colombier }
59737aecfafSDavid du Colombier if((wctlfd = open("/dev/wctl", OWRITE)) < 0)
598*14cc0f53SDavid du Colombier sysfatal("%s: Cannot open /dev/wctl: %r", argv0);
59937aecfafSDavid du Colombier if(initdraw(nil, nil, "trace") < 0)
600*14cc0f53SDavid du Colombier sysfatal("%s: initdraw failure: %r", argv0);
60137aecfafSDavid du Colombier
60237aecfafSDavid du Colombier Width = Dx(screen->r);
60337aecfafSDavid du Colombier Height = Dy(screen->r);
60437aecfafSDavid du Colombier
60537aecfafSDavid du Colombier if((mousectl = initmouse(nil, screen)) == nil)
606*14cc0f53SDavid du Colombier sysfatal("%s: cannot initialize mouse: %r", argv0);
60737aecfafSDavid du Colombier
60837aecfafSDavid du Colombier if((keyboardctl = initkeyboard(nil)) == nil)
609*14cc0f53SDavid du Colombier sysfatal("%s: cannot initialize keyboard: %r", argv0);
61037aecfafSDavid du Colombier
61137aecfafSDavid du Colombier colinit();
61237aecfafSDavid du Colombier
61337aecfafSDavid du Colombier paused = 0;
61437aecfafSDavid du Colombier scaleno = 7; /* 100 milliseconds */
61537aecfafSDavid du Colombier now = nsec();
616ec46fab0SDavid du Colombier for(;;) {
61737aecfafSDavid du Colombier Alt a[] = {
61837aecfafSDavid du Colombier { mousectl->c, nil, CHANRCV },
61937aecfafSDavid du Colombier { mousectl->resizec, nil, CHANRCV },
62037aecfafSDavid du Colombier { keyboardctl->c, &r, CHANRCV },
62137aecfafSDavid du Colombier { nil, nil, CHANNOBLK },
62237aecfafSDavid du Colombier };
62337aecfafSDavid du Colombier
62437aecfafSDavid du Colombier switch (alt(a)) {
62537aecfafSDavid du Colombier case 0:
62637aecfafSDavid du Colombier continue;
62737aecfafSDavid du Colombier
62837aecfafSDavid du Colombier case 1:
62937aecfafSDavid du Colombier if(getwindow(display, Refnone) < 0)
630*14cc0f53SDavid du Colombier sysfatal("drawrt: Cannot re-attach window");
63137aecfafSDavid du Colombier if(newwin){
63237aecfafSDavid du Colombier if(Dx(screen->r) != Width ||
63337aecfafSDavid du Colombier Dy(screen->r) != (ntasks * Height)){
63437aecfafSDavid du Colombier fprint(2, "resize: x: have %d, need %d; y: have %d, need %d\n",
63537aecfafSDavid du Colombier Dx(screen->r), Width + 8, Dy(screen->r), (ntasks * Height) + 8);
63637aecfafSDavid du Colombier fprint(wctlfd, "resize -dx %d -dy %d\n",
63737aecfafSDavid du Colombier Width + 8, (ntasks * Height) + 8);
63837aecfafSDavid du Colombier }
63937aecfafSDavid du Colombier }
64037aecfafSDavid du Colombier else{
64137aecfafSDavid du Colombier Width = Dx(screen->r);
64237aecfafSDavid du Colombier Height = ntasks? Dy(screen->r)/ntasks:
64337aecfafSDavid du Colombier Dy(screen->r);
64437aecfafSDavid du Colombier }
64537aecfafSDavid du Colombier break;
64637aecfafSDavid du Colombier
64737aecfafSDavid du Colombier case 2:
64837aecfafSDavid du Colombier
64937aecfafSDavid du Colombier switch(r){
65037aecfafSDavid du Colombier case 'r':
65137aecfafSDavid du Colombier for(i = 0; i < ntasks; i++){
65237aecfafSDavid du Colombier tasks[i].tstart = now;
65337aecfafSDavid du Colombier tasks[i].total = 0;
65437aecfafSDavid du Colombier tasks[i].runtime = 0;
65537aecfafSDavid du Colombier tasks[i].runmax = 0;
65637aecfafSDavid du Colombier tasks[i].runthis = 0;
65737aecfafSDavid du Colombier tasks[i].runs = 0;
65837aecfafSDavid du Colombier memset(tasks[i].tevents, 0, Nevent*sizeof(ulong));
65937aecfafSDavid du Colombier
66037aecfafSDavid du Colombier }
66137aecfafSDavid du Colombier break;
66237aecfafSDavid du Colombier
66337aecfafSDavid du Colombier case 'p':
66415174232SDavid du Colombier paused ^= 1;
66537aecfafSDavid du Colombier prevts = 0;
66637aecfafSDavid du Colombier break;
66737aecfafSDavid du Colombier
66837aecfafSDavid du Colombier case '-':
66937aecfafSDavid du Colombier if (scaleno < nelem(scales) - 1)
67037aecfafSDavid du Colombier scaleno++;
67137aecfafSDavid du Colombier prevts = 0;
67237aecfafSDavid du Colombier break;
67337aecfafSDavid du Colombier
67437aecfafSDavid du Colombier case '+':
67537aecfafSDavid du Colombier if (scaleno > 0)
67637aecfafSDavid du Colombier scaleno--;
67737aecfafSDavid du Colombier prevts = 0;
67837aecfafSDavid du Colombier break;
67937aecfafSDavid du Colombier
68037aecfafSDavid du Colombier case 'q':
68137aecfafSDavid du Colombier threadexitsall(nil);
68237aecfafSDavid du Colombier
68337aecfafSDavid du Colombier case 'v':
68437aecfafSDavid du Colombier verbose ^= 1;
68537aecfafSDavid du Colombier
68637aecfafSDavid du Colombier default:
68737aecfafSDavid du Colombier break;
68837aecfafSDavid du Colombier }
68937aecfafSDavid du Colombier break;
69037aecfafSDavid du Colombier
69137aecfafSDavid du Colombier case 3:
69237aecfafSDavid du Colombier now = nsec();
69337aecfafSDavid du Colombier while((n = read(logfd, eventbuf, Nevents*sizeof(Traceevent))) > 0){
69437aecfafSDavid du Colombier assert((n % sizeof(Traceevent)) == 0);
69537aecfafSDavid du Colombier nevents = n / sizeof(Traceevent);
69637aecfafSDavid du Colombier for (ep = eventbuf; ep < eventbuf + nevents; ep++){
69737aecfafSDavid du Colombier if ((ep->etype & 0xffff) >= Nevent){
69837aecfafSDavid du Colombier print("%ld %t Illegal event %ld\n",
69937aecfafSDavid du Colombier ep->pid, ep->time, ep->etype & 0xffff);
70037aecfafSDavid du Colombier continue;
70137aecfafSDavid du Colombier }
70237aecfafSDavid du Colombier if (verbose)
70337aecfafSDavid du Colombier print("%ld %t %s\n",
70437aecfafSDavid du Colombier ep->pid, ep->time, schedstatename[ep->etype & 0xffff]);
70537aecfafSDavid du Colombier
70637aecfafSDavid du Colombier for(i = 0; i < ntasks; i++)
70737aecfafSDavid du Colombier if(tasks[i].pid == ep->pid)
70837aecfafSDavid du Colombier break;
70937aecfafSDavid du Colombier
71037aecfafSDavid du Colombier if(i == ntasks){
71137aecfafSDavid du Colombier t = newtask(ep->pid);
71237aecfafSDavid du Colombier t->tstart = ep->time;
71337aecfafSDavid du Colombier }else
71437aecfafSDavid du Colombier t = &tasks[i];
71537aecfafSDavid du Colombier
71637aecfafSDavid du Colombier doevent(t, ep);
71737aecfafSDavid du Colombier }
71837aecfafSDavid du Colombier }
71937aecfafSDavid du Colombier if(!paused)
72037aecfafSDavid du Colombier redraw(scaleno);
72137aecfafSDavid du Colombier }
72237aecfafSDavid du Colombier sleep(scales[scaleno].sleep);
72337aecfafSDavid du Colombier }
72437aecfafSDavid du Colombier }
72537aecfafSDavid du Colombier
72637aecfafSDavid du Colombier int
timeconv(Fmt * f)72737aecfafSDavid du Colombier timeconv(Fmt *f)
72837aecfafSDavid du Colombier {
72937aecfafSDavid du Colombier char buf[128], *sign;
73037aecfafSDavid du Colombier vlong t;
73137aecfafSDavid du Colombier
73237aecfafSDavid du Colombier buf[0] = 0;
73337aecfafSDavid du Colombier switch(f->r) {
73437aecfafSDavid du Colombier case 'U':
73537aecfafSDavid du Colombier t = va_arg(f->args, vlong);
73637aecfafSDavid du Colombier break;
73737aecfafSDavid du Colombier case 't': // vlong in nanoseconds
73837aecfafSDavid du Colombier t = va_arg(f->args, vlong);
73937aecfafSDavid du Colombier break;
74037aecfafSDavid du Colombier default:
74137aecfafSDavid du Colombier return fmtstrcpy(f, "(timeconv)");
74237aecfafSDavid du Colombier }
74337aecfafSDavid du Colombier if (t < 0) {
74437aecfafSDavid du Colombier sign = "-";
74537aecfafSDavid du Colombier t = -t;
74637aecfafSDavid du Colombier }else
74737aecfafSDavid du Colombier sign = "";
74837aecfafSDavid du Colombier if (t > S(1)){
74937aecfafSDavid du Colombier t += OneRound;
75037aecfafSDavid du Colombier sprint(buf, "%s%d.%.3ds", sign, (int)(t / S(1)), (int)(t % S(1))/1000000);
75137aecfafSDavid du Colombier }else if (t > MS(1)){
75237aecfafSDavid du Colombier t += MilliRound;
75337aecfafSDavid du Colombier sprint(buf, "%s%d.%.3dms", sign, (int)(t / MS(1)), (int)(t % MS(1))/1000);
75437aecfafSDavid du Colombier }else if (t > US(1))
75537aecfafSDavid du Colombier sprint(buf, "%s%d.%.3dµs", sign, (int)(t / US(1)), (int)(t % US(1)));
75637aecfafSDavid du Colombier else
75737aecfafSDavid du Colombier sprint(buf, "%s%dns", sign, (int)t);
75837aecfafSDavid du Colombier return fmtstrcpy(f, buf);
75937aecfafSDavid du Colombier }
760