Quoth Russ Cox <r...@swtch.com>: > As far as the top-of-stack info, it gets complicated. You have to hard-code > an algorithm that must be implemented in every user binary, and then it's a > pain to change. This is why in Go we've backed away from reading that info > on Mac and why we call into the VDSO on Linux instead of recreating that > code ourselves. Personally, I'm not too worried about the cost of fetching > the time. A system call is fine. > > Based on this discussion, I've abandoned the idea of changing the system > calls, and I've updated Go to open /dev/bintime at startup and abandon > nsec. It also opens /dev/random at startup now too. If we're opening one, > two is not a big deal. That change is pending at https://go.dev/cl/656755. > > However, a change to Plan 9 is still needed to provide monotonic time. At > first I was going to try to recreate it from the ticks and fasthz values in > /dev/bintime, but the value of fasthz can change over time as aux/timesync > deems it necessary, and if fasthz goes up, then 1e9*ticks/fasthz will go > down, making the derived time non-monotonic. It is also annoying to do that > calculation efficiently: more parameters are needed from the kernel. > Instead of exposing all those parameters, it is far easier and cleaner to > have the kernel maintain a monotonic time and simply expose that. I suggest > we add the monotonic time in nanoseconds as an extra field you can read > from /dev/time and /dev/bintime. If you ask for a big enough buffer, you > get it. If not, you don't. The diff is here: > https://github.com/rsc/plan9/commit/baf076425c. > > Best, > Russ
Alright, here's a draft of a parallel change for 9front. This also makes a related semantic change -- While we're touching all of the todget calls, it seems like it'd be sensible to trace our syscalls and edf deadlines using monotonic timestamps too. diff 6c59f4960d2641786557499443e6cdb5e250d064 uncommitted --- a/sys/src/9/arm64/trap.c +++ b/sys/src/9/arm64/trap.c @@ -221,7 +221,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ @@ -244,7 +244,7 @@ } ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/cycv/trap.c +++ b/sys/src/9/cycv/trap.c @@ -233,7 +233,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ @@ -257,7 +257,7 @@ ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/kw/syscall.c +++ b/sys/src/9/kw/syscall.c @@ -186,7 +186,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ postnote(up, 1, "sys: bad sys call", NDebug); @@ -218,7 +218,7 @@ ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/mt7688/syscall.c +++ b/sys/src/9/mt7688/syscall.c @@ -53,7 +53,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ @@ -89,7 +89,7 @@ ureg->r1 = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/pc/devlml.c +++ b/sys/src/9/pc/devlml.c @@ -396,7 +396,7 @@ statcom = lml->codedata->statCom[fno]; jpgheader = (FrameHeader *)(lml->codedata->frag[fno].hdr + 2); jpgheader->frameNo = lml->jpgframeno; - jpgheader->ftime = todget(nil); + jpgheader->ftime = todget(nil, nil); jpgheader->frameSize = (statcom & 0x00ffffff) >> 1; jpgheader->frameSeqNo = statcom >> 24; wakeup(&lml->sleepjpg); --- a/sys/src/9/pc/trap.c +++ b/sys/src/9/pc/trap.c @@ -493,7 +493,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ @@ -528,7 +528,7 @@ ureg->ax = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/pc64/trap.c +++ b/sys/src/9/pc64/trap.c @@ -472,7 +472,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ postnote(up, 1, "sys: bad sys call", NDebug); @@ -504,7 +504,7 @@ } if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/port/devcons.c +++ b/sys/src/9/port/devcons.c @@ -817,7 +817,7 @@ static uvlong uvorder = 0x0001020304050607ULL; static uchar* -le2vlong(vlong *to, uchar *f) +be2vlong(vlong *to, uchar *f) { uchar *t, *o; int i; @@ -830,7 +830,7 @@ } static uchar* -vlong2le(uchar *t, vlong from) +vlong2be(uchar *t, vlong from) { uchar *f, *o; int i; @@ -845,7 +845,7 @@ static long order = 0x00010203; static uchar* -le2long(long *to, uchar *f) +be2long(long *to, uchar *f) { uchar *t, *o; int i; @@ -857,19 +857,6 @@ return f+sizeof(long); } -static uchar* -long2le(uchar *t, long from) -{ - uchar *f, *o; - int i; - - f = (uchar*)&from; - o = (uchar*)ℴ - for(i = 0; i < sizeof(long); i++) - t[i] = f[o[i]]; - return t+sizeof(long); -} - char *Ebadtimectl = "bad time control"; /* @@ -880,19 +867,20 @@ static int readtime(ulong off, char *buf, int n) { - vlong nsec, ticks; + vlong nsec, ticks, mono; long sec; - char str[7*NUMSIZE]; + char str[9*NUMSIZE]; - nsec = todget(&ticks); + nsec = todget(&ticks, &mono); if(fasthz == 0LL) fastticks((uvlong*)&fasthz); sec = nsec/1000000000ULL; - snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ", + snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud %*llud ", NUMSIZE-1, sec, VLNUMSIZE-1, nsec, VLNUMSIZE-1, ticks, - VLNUMSIZE-1, fasthz); + VLNUMSIZE-1, fasthz, + VLNUMSIZE-1, mono); return readstr(off, buf, n, str); } @@ -926,23 +914,27 @@ readbintime(char *buf, int n) { int i; - vlong nsec, ticks; + vlong nsec, ticks, mono; uchar *b = (uchar*)buf; i = 0; if(fasthz == 0LL) fastticks((uvlong*)&fasthz); - nsec = todget(&ticks); + nsec = todget(&ticks, &mono); + if(n >= 4*sizeof(uvlong)){ + vlong2be(b+3*sizeof(uvlong), mono); + i += sizeof(uvlong); + } if(n >= 3*sizeof(uvlong)){ - vlong2le(b+2*sizeof(uvlong), fasthz); + vlong2be(b+2*sizeof(uvlong), fasthz); i += sizeof(uvlong); } if(n >= 2*sizeof(uvlong)){ - vlong2le(b+sizeof(uvlong), ticks); + vlong2be(b+sizeof(uvlong), ticks); i += sizeof(uvlong); } if(n >= 8){ - vlong2le(b, nsec); + vlong2be(b, nsec); i += sizeof(vlong); } return i; @@ -968,20 +960,20 @@ case 'n': if(n < sizeof(vlong)) error(Ebadtimectl); - le2vlong(&delta, p); + be2vlong(&delta, p); todset(delta, 0, 0); break; case 'd': if(n < sizeof(vlong)+sizeof(long)) error(Ebadtimectl); - p = le2vlong(&delta, p); - le2long(&period, p); + p = be2vlong(&delta, p); + be2long(&period, p); todset(-1, delta, period); break; case 'f': if(n < sizeof(uvlong)) error(Ebadtimectl); - le2vlong(&fasthz, p); + be2vlong(&fasthz, p); if(fasthz <= 0) error(Ebadtimectl); todsetfreq(fasthz); --- a/sys/src/9/port/devloopback.c +++ b/sys/src/9/port/devloopback.c @@ -553,7 +553,7 @@ bp = padblock(bp, Tmsize); if(BLEN(bp) < lb->minmtu) bp = adjustblock(bp, lb->minmtu); - ptime(bp->rp, todget(nil)); + ptime(bp->rp, todget(nil, nil)); link->packets++; link->bytes += n; --- a/sys/src/9/port/devproc.c +++ b/sys/src/9/port/devproc.c @@ -281,7 +281,7 @@ te->pid = p->pid; te->etype = etype; if (ts == 0) - te->time = todget(nil); + todget(nil, &te->time); else te->time = ts; tproduced++; --- a/sys/src/9/port/edf.c +++ b/sys/src/9/port/edf.c @@ -195,7 +195,7 @@ DPRINT("%lud release %lud[%s], r=%lud, d=%lud, t=%lud, S=%lud\n", now, p->pid, statename[p->state], e->r, e->d, e->t, e->S); if(pt = proctrace){ - nowns = todget(nil); + todget(nil, &nowns); pt(p, SRelease, nowns); pt(p, SDeadline, nowns + 1000LL*e->D); } @@ -291,6 +291,7 @@ Edf *e; void (*pt)(Proc*, int, vlong); long tns; + vlong tnow; e = p->edf; /* Called with edflock held */ @@ -315,8 +316,10 @@ }else{ DPRINT("v"); } - if(p->trace && (pt = proctrace)) - pt(p, SInte, todget(nil) + e->tns); + if(p->trace && (pt = proctrace)){ + todget(nil, &tnow); + pt(p, SInte, tnow + e->tns); + } e->tmode = Trelative; e->tf = deadlineintr; e->ta = p; --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -366,7 +366,7 @@ ulong tk2ms(ulong); #define TK2MS(x) ((x)*(1000/HZ)) uvlong tod2fastticks(vlong); -vlong todget(vlong*); +vlong todget(vlong*, vlong*); void todsetfreq(vlong); void todinit(void); void todset(vlong, vlong, int); --- a/sys/src/9/port/sysproc.c +++ b/sys/src/9/port/sysproc.c @@ -1257,12 +1257,12 @@ /* return in register on 64bit machine */ if(sizeof(uintptr) == sizeof(vlong)){ USED(list); - return (uintptr)todget(nil); + return (uintptr)todget(nil, nil); } v = va_arg(list, vlong*); evenaddr((uintptr)v); validaddr((uintptr)v, sizeof(vlong), 1); - *v = todget(nil); + *v = todget(nil, nil); return 0; } --- a/sys/src/9/port/taslock.c +++ b/sys/src/9/port/taslock.c @@ -36,6 +36,7 @@ lock(Lock *l) { int i; + vlong mono; uintptr pc; pc = getcallerpc(&l); @@ -67,7 +68,8 @@ */ print("inversion %#p pc %#p proc %lud held by pc %#p proc %lud\n", l, pc, up ? up->pid : 0, l->pc, l->p ? l->p->pid : 0); - up->edf->d = todget(nil); /* yield to process with lock */ + todget(nil, &mono); /* yield to process with lock */ + up->edf->d = mono; } if(i++ > 100000000){ i = 0; --- a/sys/src/9/port/tod.c +++ b/sys/src/9/port/tod.c @@ -44,7 +44,9 @@ uvlong udivider; /* ticks = (µdivider*µs)>>31 */ vlong hz; /* frequency of fast clock */ vlong last; /* last reading of fast clock */ - vlong off; /* offset from epoch to last */ + vlong off; /* offset from epoch to last (ns) */ + vlong monolast; /* last reading of fast clocks for monotonic time */ + vlong monooff; /* offset from 0 to monolast (ns) */ vlong lasttime; /* last return value from todget */ vlong delta; /* add 'delta' each slow clock tick from sstart to send */ ulong sstart; /* ... */ @@ -61,6 +63,7 @@ ilock(&tod); tod.init = 1; /* prevent reentry via fastticks */ tod.last = fastticks((uvlong *)&tod.hz); + tod.monolast = tod.last; iunlock(&tod); todsetfreq(tod.hz); addclock0link(todfix, 100); @@ -67,14 +70,36 @@ } /* + * return monotonic ns; tod must be locked + */ +static vlong +todmono(vlong ticks) +{ + uvlong x; + vlong diff; + + if(tod.hz == 0) /* called from first todsetfreq */ + return 0; + diff = ticks - tod.monolast; + mul64fract(&x, diff, tod.multiplier); + x += tod.monooff; + return x; +} + +/* * calculate multiplier */ void todsetfreq(vlong f) { + vlong ticks; + if (f <= 0) panic("todsetfreq: freq %lld <= 0", f); ilock(&tod); + ticks = fastticks(nil); + tod.monooff = todmono(ticks); + tod.monolast = ticks; tod.hz = f; /* calculate multiplier for time conversion */ @@ -125,10 +150,10 @@ * get time of day */ vlong -todget(vlong *ticksp) +todget(vlong *ticksp, vlong *monop) { uvlong x; - vlong ticks, diff; + vlong ticks, diff, mono; ulong t; if(!tod.init) @@ -159,16 +184,21 @@ mul64fract(&x, diff, tod.multiplier); x += tod.off; - /* time can't go backwards */ + /* time can't go backwards (except when /dev/[bin]time is written) */ if(x < tod.lasttime) x = tod.lasttime; else tod.lasttime = x; + mono = 0; + if(monop != nil) + mono = todmono(ticks); iunlock(&tod); if(ticksp != nil) *ticksp = ticks; + if(monop != nil) + *monop = mono; return x; } @@ -219,7 +249,7 @@ long seconds(void) { - return (vlong)todget(nil) / TODFREQ; + return (vlong)todget(nil, nil) / TODFREQ; } uvlong --- a/sys/src/9/sgi/trap.c +++ b/sys/src/9/sgi/trap.c @@ -595,7 +595,7 @@ if(up->syscalltrace) free(up->syscalltrace); up->syscalltrace = nil; - *startnsp = todget(nil); + todget(nil, startnsp); } } @@ -602,12 +602,14 @@ static void sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns) { + vlong stopns; int s; if(up->procctl == Proc_tracesyscall){ + todget(nil, &stopns); up->procctl = Proc_stopme; sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, - startns, todget(nil)); + startns, stopns); s = splhi(); procctl(); splx(s); --- a/sys/src/9/teg2/syscall.c +++ b/sys/src/9/teg2/syscall.c @@ -202,7 +202,7 @@ up->nerrlab = 0; ret = -1; - startns = todget(nil); + todget(nil, &startns); l1cache->wb(); /* system is more stable with this */ if(!waserror()){ @@ -240,7 +240,7 @@ ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; --- a/sys/src/9/zynq/trap.c +++ b/sys/src/9/zynq/trap.c @@ -233,7 +233,7 @@ up->procctl = Proc_stopme; procctl(); splx(s); - startns = todget(nil); + todget(nil, &startns); } if(scallnr >= nsyscall || systab[scallnr] == nil){ postnote(up, 1, "sys: bad sys call", NDebug); @@ -256,7 +256,7 @@ ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ - stopns = todget(nil); + todget(nil, &stopns); sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns); s = splhi(); up->procctl = Proc_stopme; ------------------------------------------ 9fans: 9fans Permalink: https://9fans.topicbox.com/groups/9fans/T59810df4fe34a033-M2c451362e4dff236d4dea432 Delivery options: https://9fans.topicbox.com/groups/9fans/subscription