#include <u.h>#include <tos.h>#include <libc.h>#include <thread.h>#include <ip.h>#include <bio.h>#include <draw.h>#include <mouse.h>#include <cursor.h>#include <keyboard.h>#include "trace.h" #pragma varargck type "t" vlong#pragma varargck type "U" uvlong #define NS(x) ((vlong)x)#define US(x) (NS(x) * 1000ULL)#define MS(x) (US(x) * 1000ULL)#define S(x) (MS(x) * 1000ULL) #define numblocks(a, b) (((a) + (b) - 1) / (b))#define roundup(a, b) (numblocks((a), (b)) * (b)) enum { OneRound = MS(1)/2LL, MilliRound = US(1)/2LL,}; typedef struct Event Event;typedef struct Task Task;struct Event { Traceevent; vlong etime; /* length of block to draw */}; struct Task { int pid; char *name; int nevents; Event *events; vlong tstart; vlong total; vlong runtime; vlong runmax; vlong runthis; long runs; ulong tevents[Nevent];}; enum { Nevents = 1024, Ncolor = 6, K = 1024,}; vlong now, prevts; int newwin;int Width = 1000; int Height = 100; // Per taskint topmargin = 8;int bottommargin = 4;int lineht = 12;int wctlfd;int nevents;Traceevent *eventbuf;Event *event; void drawtrace(void);int schedparse(char*, char*, char*);int timeconv(Fmt*); char *schedstatename[] = { [SAdmit] = "Admit", [SSleep] = "Sleep", [SDead] = "Dead", [SDeadline] = "Deadline", [SEdf] = "Edf", [SExpel] = "Expel", [SReady] = "Ready", [SRelease] = "Release", [SRun] = "Run", [SSlice] = "Slice", [SInts] = "Ints", [SInte] = "Inte", [SUser] = "User", [SYield] = "Yield",}; struct { vlong scale; vlong bigtics; vlong littletics; int sleep;} scales[] = { { US(500), US(100), US(50), 0}, { US(1000), US(500), US(100), 0}, { US(2000), US(1000), US(200), 0}, { US(5000), US(1000), US(500), 0}, { MS(10), MS(5), MS(1), 20}, { MS(20), MS(10), MS(2), 20}, { MS(50), MS(10), MS(5), 20}, { MS(100), MS(50), MS(10), 20}, /* starting scaleno */ { MS(200), MS(100), MS(20), 20}, { MS(500), MS(100), MS(50), 50}, { MS(1000), MS(500), MS(100), 100}, { MS(2000), MS(1000), MS(200), 100}, { MS(5000), MS(1000), MS(500), 100}, { S(10), S(50), S(1), 100}, { S(20), S(10), S(2), 100}, { S(50), S(10), S(5), 100}, { S(100), S(50), S(10), 100}, { S(200), S(100), S(20), 100}, { S(500), S(100), S(50), 100}, { S(1000), S(500), S(100), 100},}; int ntasks, verbose, triggerproc, paused;Task *tasks;Image *cols[Ncolor][4];Font *mediumfont, *tinyfont;Image *grey, *red, *green, *blue, *bg, *fg;char*profdev = "/proc/trace"; static voidusage(void){ fprint(2, "Usage: %s [-d profdev] [-w] [-v] [-t triggerproc] [processes]\n", argv0); exits(nil);} voidthreadmain(int argc, char **argv){ int fd, i; char fname[80]; fmtinstall('t', timeconv); ARGBEGIN { case 'd': profdev = EARGF(usage()); break; case 'v': verbose = 1; break; case 'w': newwin++; break; case 't': triggerproc = (int)strtol(EARGF(usage()), nil, 0); break; default: usage(); } ARGEND; fname[sizeof fname - 1] = 0; for(i = 0; i < argc; i++){ snprint(fname, sizeof fname - 2, "/proc/%s/ctl", argv[i]); if((fd = open(fname, OWRITE)) < 0){ fprint(2, "%s: cannot open %s: %r\n", argv[0], fname); continue; } if(fprint(fd, "trace 1") < 0) fprint(2, "%s: cannot enable tracing on %s: %r\n", argv[0], fname); close(fd); } drawtrace();} static voidmkcol(int i, int c0, int c1, int c2){ cols[i][0] = allocimagemix(display, c0, DWhite); cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1); cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2); cols[i][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c0);} static voidcolinit(void){ mediumfont = openfont(display, "/lib/font/bit/lucidasans/unicode.10.font"); if(mediumfont == nil) mediumfont = font; tinyfont = openfont(display, "/lib/font/bit/lucidasans/unicode.7.font"); if(tinyfont == nil) tinyfont = font; topmargin = mediumfont->height+2; bottommargin = tinyfont->height+2; /* Peach */ mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF); /* Aqua */ mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue); /* Yellow */ mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen); /* Green */ mkcol(3, DPalegreen, DMedgreen, DDarkgreen); /* Blue */ mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF); /* Grey */ cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF); cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF); cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF); cols[5][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF); grey = cols[5][2]; red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFF0000FF); green = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00FF00FF); blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF); bg = display->white; fg = display->black;} static voidredraw(int scaleno){ int n, i, j, x; char buf[256]; Point p, q; Rectangle r, rtime; Task *t; vlong ts, oldestts, newestts, period, ppp, scale, s, ss; # define time2x(t) ((int)(((t) - oldestts) / ppp)) scale = scales[scaleno].scale; period = scale + scales[scaleno].littletics; ppp = period / Width; // period per pixel. /* Round `now' to a nice number */ newestts = now - (now % scales[scaleno].bigtics) + (scales[scaleno].littletics>>1); oldestts = newestts - period; //print("newestts %t, period %t, %d-%d\n", newestts, period, time2x(oldestts), time2x(newestts)); if (prevts < oldestts){ oldestts = newestts - period; prevts = oldestts; draw(screen, screen->r, bg, nil, ZP); }else{ /* just white out time */ rtime = screen->r; rtime.min.x = rtime.max.x - stringwidth(mediumfont, "00000000000.000s"); rtime.max.y = rtime.min.y + mediumfont->height; draw(screen, rtime, bg, nil, ZP); } p = screen->r.min; for (n = 0; n != ntasks; n++) { t = &tasks[n]; /* p is upper left corner for this task */ rtime = Rpt(p, addpt(p, Pt(500, mediumfont->height))); draw(screen, rtime, bg, nil, ZP); snprint(buf, sizeof(buf), "%d %s", t->pid, t->name); q = string(screen, p, fg, ZP, mediumfont, buf); s = now - t->tstart; if(t->tevents[SRelease]) snprint(buf, sizeof(buf), " per %t — avg: %t max: %t", (vlong)(s/t->tevents[SRelease]), (vlong)(t->runtime/t->tevents[SRelease]), t->runmax); else if((s /=1000000000LL) != 0) snprint(buf, sizeof(buf), " per 1s — avg: %t total: %t", t->total/s, t->total); else snprint(buf, sizeof(buf), " total: %t", t->total); string(screen, q, fg, ZP, tinyfont, buf); p.y += Height; } x = time2x(prevts); p = screen->r.min; for (n = 0; n != ntasks; n++) { t = &tasks[n]; /* p is upper left corner for this task */ /* Move part already drawn */ r = Rect(p.x, p.y + topmargin, p.x + x, p.y+Height); draw(screen, r, screen, nil, Pt(p.x + Width - x, p.y + topmargin)); r.max.x = screen->r.max.x; r.min.x += x; draw(screen, r, bg, nil, ZP); line(screen, addpt(p, Pt(x, Height - lineht)), Pt(screen->r.max.x, p.y + Height - lineht), Endsquare, Endsquare, 0, cols[n % Ncolor][1], ZP); for (i = 0; i < t->nevents-1; i++) if (prevts < t->events[i + 1].time) break; if (i > 0) { memmove(t->events, t->events + i, (t->nevents - i) * sizeof(Event)); t->nevents -= i; } for (i = 0; i != t->nevents; i++) { Event *e = &t->events[i], *_e; int sx, ex; switch (e->etype & 0xffff) { case SAdmit: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endarrow, Endsquare, 1, green, ZP); } break; case SExpel: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 1, red, ZP); } break; case SRelease: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endarrow, Endsquare, 1, fg, ZP); } break; case SDeadline: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 1, fg, ZP); } break; case SYield: case SUser: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 0, (e->etype == SYield)? green: blue, ZP); } break; case SSlice: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 0, red, ZP); } break; case SRun: case SEdf: sx = time2x(e->time); ex = time2x(e->etime); if(ex == sx) ex++; r = Rect(sx, topmargin + 8, ex, Height - lineht); r = rectaddpt(r, p); draw(screen, r, cols[n % Ncolor][e->etype==SRun?1:3], nil, ZP); if(t->pid == triggerproc && ex < Width) paused ^= 1; for(j = 0; j < t->nevents; j++){ _e = &t->events[j]; switch(_e->etype & 0xffff){ case SInts: if (_e->time > prevts && _e->time <= newestts){ sx = time2x(_e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height / 2 - bottommargin)), Endsquare, Endsquare, 0, green, ZP); } break; case SInte: if (_e->time > prevts && _e->time <= newestts) { sx = time2x(_e->time); line(screen, addpt(p, Pt(sx, Height / 2 - bottommargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endsquare, 0, blue, ZP); } break; } } break; } } p.y += Height; } ts = prevts + scales[scaleno].littletics - (prevts % scales[scaleno].littletics); x = time2x(ts); while(x < Width){ p = screen->r.min; for(n = 0; n < ntasks; n++){ int height, width; /* p is upper left corner for this task */ if ((ts % scales[scaleno].scale) == 0){ height = 10 * Height; width = 1; }else if ((ts % scales[scaleno].bigtics) == 0){ height = 12 * Height; width = 0; }else{ height = 13 * Height; width = 0; } height >>= 4; line(screen, addpt(p, Pt(x, height)), addpt(p, Pt(x, Height - lineht)), Endsquare, Endsquare, width, cols[n % Ncolor][2], ZP); p.y += Height; } ts += scales[scaleno].littletics; x = time2x(ts); } rtime = screen->r; rtime.min.y = rtime.max.y - tinyfont->height + 2; draw(screen, rtime, bg, nil, ZP); ts = oldestts + scales[scaleno].bigtics - (oldestts % scales[scaleno].bigtics); x = time2x(ts); ss = 0; while(x < Width){ snprint(buf, sizeof(buf), "%t", ss); string(screen, addpt(p, Pt(x - stringwidth(tinyfont, buf)/2, - tinyfont->height - 1)), fg, ZP, tinyfont, buf); ts += scales[scaleno].bigtics; ss += scales[scaleno].bigtics; x = time2x(ts); } snprint(buf, sizeof(buf), "%t", now); string(screen, Pt(screen->r.max.x - stringwidth(mediumfont, buf), screen->r.min.y), fg, ZP, mediumfont, buf); flushimage(display, 1); prevts = newestts;} Task*newtask(ulong pid){ Task *t; char buf[64], *p; int fd,n; tasks = realloc(tasks, (ntasks + 1) * sizeof(Task)); assert(tasks); t = &tasks[ntasks++]; memset(t, 0, sizeof(Task)); t->events = nil; snprint(buf, sizeof buf, "/proc/%ld/status", pid); t->name = nil; fd = open(buf, OREAD); if (fd >= 0){ n = read(fd, buf, sizeof buf); if(n > 0){ p = buf + sizeof buf - 1; *p = 0; p = strchr(buf, ' '); if (p) *p = 0; t->name = strdup(buf); }else print("%s: %r\n", buf); close(fd); }else print("%s: %r\n", buf); t->pid = pid; prevts = 0; if (newwin){ fprint(wctlfd, "resize -dx %d -dy %d\n", Width + 20, (ntasks * Height) + 5); }else Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r); return t;} voiddoevent(Task *t, Traceevent *ep)Lines 1–500 of 759. Load more
#include <u.h> #include <tos.h> #include <libc.h> #include <thread.h> #include <ip.h> #include <bio.h> #include <draw.h> #include <mouse.h> #include <cursor.h> #include <keyboard.h> #include "trace.h" #pragma varargck type "t" vlong #pragma varargck type "U" uvlong #define NS(x) ((vlong)x) #define US(x) (NS(x) * 1000ULL) #define MS(x) (US(x) * 1000ULL) #define S(x) (MS(x) * 1000ULL) #define numblocks(a, b) (((a) + (b) - 1) / (b)) #define roundup(a, b) (numblocks((a), (b)) * (b)) enum { OneRound = MS(1)/2LL, MilliRound = US(1)/2LL, }; typedef struct Event Event; typedef struct Task Task; struct Event { Traceevent; vlong etime; /* length of block to draw */ }; struct Task { int pid; char *name; int nevents; Event *events; vlong tstart; vlong total; vlong runtime; vlong runmax; vlong runthis; long runs; ulong tevents[Nevent]; }; enum { Nevents = 1024, Ncolor = 6, K = 1024, }; vlong now, prevts; int newwin; int Width = 1000; int Height = 100; // Per task int topmargin = 8; int bottommargin = 4; int lineht = 12; int wctlfd; int nevents; Traceevent *eventbuf; Event *event; void drawtrace(void); int schedparse(char*, char*, char*); int timeconv(Fmt*); char *schedstatename[] = { [SAdmit] = "Admit", [SSleep] = "Sleep", [SDead] = "Dead", [SDeadline] = "Deadline", [SEdf] = "Edf", [SExpel] = "Expel", [SReady] = "Ready", [SRelease] = "Release", [SRun] = "Run", [SSlice] = "Slice", [SInts] = "Ints", [SInte] = "Inte", [SUser] = "User", [SYield] = "Yield", }; struct { vlong scale; vlong bigtics; vlong littletics; int sleep; } scales[] = { { US(500), US(100), US(50), 0}, { US(1000), US(500), US(100), 0}, { US(2000), US(1000), US(200), 0}, { US(5000), US(1000), US(500), 0}, { MS(10), MS(5), MS(1), 20}, { MS(20), MS(10), MS(2), 20}, { MS(50), MS(10), MS(5), 20}, { MS(100), MS(50), MS(10), 20}, /* starting scaleno */ { MS(200), MS(100), MS(20), 20}, { MS(500), MS(100), MS(50), 50}, { MS(1000), MS(500), MS(100), 100}, { MS(2000), MS(1000), MS(200), 100}, { MS(5000), MS(1000), MS(500), 100}, { S(10), S(50), S(1), 100}, { S(20), S(10), S(2), 100}, { S(50), S(10), S(5), 100}, { S(100), S(50), S(10), 100}, { S(200), S(100), S(20), 100}, { S(500), S(100), S(50), 100}, { S(1000), S(500), S(100), 100}, }; int ntasks, verbose, triggerproc, paused; Task *tasks; Image *cols[Ncolor][4]; Font *mediumfont, *tinyfont; Image *grey, *red, *green, *blue, *bg, *fg; char*profdev = "/proc/trace"; static void usage(void) { fprint(2, "Usage: %s [-d profdev] [-w] [-v] [-t triggerproc] [processes]\n", argv0); exits(nil); } void threadmain(int argc, char **argv) { int fd, i; char fname[80]; fmtinstall('t', timeconv); ARGBEGIN { case 'd': profdev = EARGF(usage()); break; case 'v': verbose = 1; break; case 'w': newwin++; break; case 't': triggerproc = (int)strtol(EARGF(usage()), nil, 0); break; default: usage(); } ARGEND; fname[sizeof fname - 1] = 0; for(i = 0; i < argc; i++){ snprint(fname, sizeof fname - 2, "/proc/%s/ctl", argv[i]); if((fd = open(fname, OWRITE)) < 0){ fprint(2, "%s: cannot open %s: %r\n", argv[0], fname); continue; } if(fprint(fd, "trace 1") < 0) fprint(2, "%s: cannot enable tracing on %s: %r\n", argv[0], fname); close(fd); } drawtrace(); } static void mkcol(int i, int c0, int c1, int c2) { cols[i][0] = allocimagemix(display, c0, DWhite); cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1); cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2); cols[i][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c0); } static void colinit(void) { mediumfont = openfont(display, "/lib/font/bit/lucidasans/unicode.10.font"); if(mediumfont == nil) mediumfont = font; tinyfont = openfont(display, "/lib/font/bit/lucidasans/unicode.7.font"); if(tinyfont == nil) tinyfont = font; topmargin = mediumfont->height+2; bottommargin = tinyfont->height+2; /* Peach */ mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF); /* Aqua */ mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue); /* Yellow */ mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen); /* Green */ mkcol(3, DPalegreen, DMedgreen, DDarkgreen); /* Blue */ mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF); /* Grey */ cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF); cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF); cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF); cols[5][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF); grey = cols[5][2]; red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFF0000FF); green = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00FF00FF); blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF); bg = display->white; fg = display->black; } static void redraw(int scaleno) { int n, i, j, x; char buf[256]; Point p, q; Rectangle r, rtime; Task *t; vlong ts, oldestts, newestts, period, ppp, scale, s, ss; # define time2x(t) ((int)(((t) - oldestts) / ppp)) scale = scales[scaleno].scale; period = scale + scales[scaleno].littletics; ppp = period / Width; // period per pixel. /* Round `now' to a nice number */ newestts = now - (now % scales[scaleno].bigtics) + (scales[scaleno].littletics>>1); oldestts = newestts - period; //print("newestts %t, period %t, %d-%d\n", newestts, period, time2x(oldestts), time2x(newestts)); if (prevts < oldestts){ oldestts = newestts - period; prevts = oldestts; draw(screen, screen->r, bg, nil, ZP); }else{ /* just white out time */ rtime = screen->r; rtime.min.x = rtime.max.x - stringwidth(mediumfont, "00000000000.000s"); rtime.max.y = rtime.min.y + mediumfont->height; draw(screen, rtime, bg, nil, ZP); } p = screen->r.min; for (n = 0; n != ntasks; n++) { t = &tasks[n]; /* p is upper left corner for this task */ rtime = Rpt(p, addpt(p, Pt(500, mediumfont->height))); draw(screen, rtime, bg, nil, ZP); snprint(buf, sizeof(buf), "%d %s", t->pid, t->name); q = string(screen, p, fg, ZP, mediumfont, buf); s = now - t->tstart; if(t->tevents[SRelease]) snprint(buf, sizeof(buf), " per %t — avg: %t max: %t", (vlong)(s/t->tevents[SRelease]), (vlong)(t->runtime/t->tevents[SRelease]), t->runmax); else if((s /=1000000000LL) != 0) snprint(buf, sizeof(buf), " per 1s — avg: %t total: %t", t->total/s, t->total); else snprint(buf, sizeof(buf), " total: %t", t->total); string(screen, q, fg, ZP, tinyfont, buf); p.y += Height; } x = time2x(prevts); p = screen->r.min; for (n = 0; n != ntasks; n++) { t = &tasks[n]; /* p is upper left corner for this task */ /* Move part already drawn */ r = Rect(p.x, p.y + topmargin, p.x + x, p.y+Height); draw(screen, r, screen, nil, Pt(p.x + Width - x, p.y + topmargin)); r.max.x = screen->r.max.x; r.min.x += x; draw(screen, r, bg, nil, ZP); line(screen, addpt(p, Pt(x, Height - lineht)), Pt(screen->r.max.x, p.y + Height - lineht), Endsquare, Endsquare, 0, cols[n % Ncolor][1], ZP); for (i = 0; i < t->nevents-1; i++) if (prevts < t->events[i + 1].time) break; if (i > 0) { memmove(t->events, t->events + i, (t->nevents - i) * sizeof(Event)); t->nevents -= i; } for (i = 0; i != t->nevents; i++) { Event *e = &t->events[i], *_e; int sx, ex; switch (e->etype & 0xffff) { case SAdmit: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endarrow, Endsquare, 1, green, ZP); } break; case SExpel: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 1, red, ZP); } break; case SRelease: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endarrow, Endsquare, 1, fg, ZP); } break; case SDeadline: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 1, fg, ZP); } break; case SYield: case SUser: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 0, (e->etype == SYield)? green: blue, ZP); } break; case SSlice: if (e->time > prevts && e->time <= newestts) { sx = time2x(e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endarrow, 0, red, ZP); } break; case SRun: case SEdf: sx = time2x(e->time); ex = time2x(e->etime); if(ex == sx) ex++; r = Rect(sx, topmargin + 8, ex, Height - lineht); r = rectaddpt(r, p); draw(screen, r, cols[n % Ncolor][e->etype==SRun?1:3], nil, ZP); if(t->pid == triggerproc && ex < Width) paused ^= 1; for(j = 0; j < t->nevents; j++){ _e = &t->events[j]; switch(_e->etype & 0xffff){ case SInts: if (_e->time > prevts && _e->time <= newestts){ sx = time2x(_e->time); line(screen, addpt(p, Pt(sx, topmargin)), addpt(p, Pt(sx, Height / 2 - bottommargin)), Endsquare, Endsquare, 0, green, ZP); } break; case SInte: if (_e->time > prevts && _e->time <= newestts) { sx = time2x(_e->time); line(screen, addpt(p, Pt(sx, Height / 2 - bottommargin)), addpt(p, Pt(sx, Height - bottommargin)), Endsquare, Endsquare, 0, blue, ZP); } break; } } break; } } p.y += Height; } ts = prevts + scales[scaleno].littletics - (prevts % scales[scaleno].littletics); x = time2x(ts); while(x < Width){ p = screen->r.min; for(n = 0; n < ntasks; n++){ int height, width; /* p is upper left corner for this task */ if ((ts % scales[scaleno].scale) == 0){ height = 10 * Height; width = 1; }else if ((ts % scales[scaleno].bigtics) == 0){ height = 12 * Height; width = 0; }else{ height = 13 * Height; width = 0; } height >>= 4; line(screen, addpt(p, Pt(x, height)), addpt(p, Pt(x, Height - lineht)), Endsquare, Endsquare, width, cols[n % Ncolor][2], ZP); p.y += Height; } ts += scales[scaleno].littletics; x = time2x(ts); } rtime = screen->r; rtime.min.y = rtime.max.y - tinyfont->height + 2; draw(screen, rtime, bg, nil, ZP); ts = oldestts + scales[scaleno].bigtics - (oldestts % scales[scaleno].bigtics); x = time2x(ts); ss = 0; while(x < Width){ snprint(buf, sizeof(buf), "%t", ss); string(screen, addpt(p, Pt(x - stringwidth(tinyfont, buf)/2, - tinyfont->height - 1)), fg, ZP, tinyfont, buf); ts += scales[scaleno].bigtics; ss += scales[scaleno].bigtics; x = time2x(ts); } snprint(buf, sizeof(buf), "%t", now); string(screen, Pt(screen->r.max.x - stringwidth(mediumfont, buf), screen->r.min.y), fg, ZP, mediumfont, buf); flushimage(display, 1); prevts = newestts; } Task* newtask(ulong pid) { Task *t; char buf[64], *p; int fd,n; tasks = realloc(tasks, (ntasks + 1) * sizeof(Task)); assert(tasks); t = &tasks[ntasks++]; memset(t, 0, sizeof(Task)); t->events = nil; snprint(buf, sizeof buf, "/proc/%ld/status", pid); t->name = nil; fd = open(buf, OREAD); if (fd >= 0){ n = read(fd, buf, sizeof buf); if(n > 0){ p = buf + sizeof buf - 1; *p = 0; p = strchr(buf, ' '); if (p) *p = 0; t->name = strdup(buf); }else print("%s: %r\n", buf); close(fd); }else print("%s: %r\n", buf); t->pid = pid; prevts = 0; if (newwin){ fprint(wctlfd, "resize -dx %d -dy %d\n", Width + 20, (ntasks * Height) + 5); }else Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r); return t; } void doevent(Task *t, Traceevent *ep)