On Fri, Apr 08, 2022 at 02:39:34AM +0000, Visa Hankala wrote: > On Thu, Apr 07, 2022 at 07:55:11PM +0200, Alexander Bluhm wrote: > > On Wed, Mar 23, 2022 at 06:13:27PM +0100, Alexander Bluhm wrote: > > > In my opinion tracepoints give insight at minimal cost. It is worth > > > it to have it in GENERIC to make it easy to use. > > > > After release I want to revive the btrace of refcounts discussion. > > > > As mpi@ mentioned the idea of dt(4) is to have these trace points > > in GENERIC kernel. If you want to hunt a bug, just turn it on. > > Refounting is a common place for bugs, leaks can be detected easily. > > > > The alternative are some defines that you can compile in and access > > from ddb. This is more work and you would have to implement it for > > every recount. > > https://marc.info/?l=openbsd-tech&m=163786435916039&w=2 > > > > There is no measuarable performance difference. dt(4) is written > > in a way that is is only one additional branch. At least my goal > > is to add trace points to useful places when we identify them. > > DT_INDEX_ENTER() still checks the index first, so it has two branches > in practice. > > I think dt_tracing should be checked first so that it serves as > a gateway to the trace code. Under normal operation, the check's > outcome is always the same, which is easy even for simple branch > predictors.
Reordering the check is easy. Now dt_tracing is first. > I have a slight suspicion that dt(4) is now becoming a way to add code > that would be otherwise unacceptable. Also, how "durable" are trace > points perceived? Is an added trace point an achieved advantage that > is difficult to remove even when its utility has diminished? There is > a similarity to (ad hoc) debug printfs too. As I understand dt(4) it is a replacement for debug printfs. But it has advantages. I can be turnd on selectively from userland. It does not spam the console, but can be processed in userland. It is always there, you don't have to recompile. Of course you always have the printf or tracepoint at the worng place. I think people debugging the code should move them to the useful places. Then we may end with generally useful tool. A least that is my hope. There are obvious places to debug. We have syscall entry and return. And I think reference counting is also generally interesting. bluhm Index: dev/dt/dt_prov_static.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/dev/dt/dt_prov_static.c,v retrieving revision 1.13 diff -u -p -r1.13 dt_prov_static.c --- dev/dt/dt_prov_static.c 17 Mar 2022 14:53:59 -0000 1.13 +++ dev/dt/dt_prov_static.c 8 Apr 2022 09:40:29 -0000 @@ -87,6 +87,12 @@ DT_STATIC_PROBE1(smr, barrier_exit, "int DT_STATIC_PROBE0(smr, wakeup); DT_STATIC_PROBE2(smr, thread, "uint64_t", "uint64_t"); +/* + * reference counting + */ +DT_STATIC_PROBE0(refcnt, none); +DT_STATIC_PROBE3(refcnt, inpcb, "void *", "int", "int"); +DT_STATIC_PROBE3(refcnt, tdb, "void *", "int", "int"); /* * List of all static probes @@ -127,15 +133,24 @@ struct dt_probe *const dtps_static[] = { &_DT_STATIC_P(smr, barrier_exit), &_DT_STATIC_P(smr, wakeup), &_DT_STATIC_P(smr, thread), + /* refcnt */ + &_DT_STATIC_P(refcnt, none), + &_DT_STATIC_P(refcnt, inpcb), + &_DT_STATIC_P(refcnt, tdb), }; +struct dt_probe *const *dtps_index_refcnt; + int dt_prov_static_init(void) { int i; - for (i = 0; i < nitems(dtps_static); i++) + for (i = 0; i < nitems(dtps_static); i++) { + if (dtps_static[i] == &_DT_STATIC_P(refcnt, none)) + dtps_index_refcnt = &dtps_static[i]; dt_dev_register_probe(dtps_static[i]); + } return i; } Index: dev/dt/dtvar.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/dev/dt/dtvar.h,v retrieving revision 1.13 diff -u -p -r1.13 dtvar.h --- dev/dt/dtvar.h 27 Feb 2022 10:14:01 -0000 1.13 +++ dev/dt/dtvar.h 8 Apr 2022 09:42:19 -0000 @@ -313,11 +313,30 @@ extern volatile uint32_t dt_tracing; /* #define DT_STATIC_ENTER(func, name, args...) do { \ extern struct dt_probe _DT_STATIC_P(func, name); \ struct dt_probe *dtp = &_DT_STATIC_P(func, name); \ - struct dt_provider *dtpv = dtp->dtp_prov; \ \ if (__predict_false(dt_tracing) && \ __predict_false(dtp->dtp_recording)) { \ + struct dt_provider *dtpv = dtp->dtp_prov; \ + \ dtpv->dtpv_enter(dtpv, dtp, args); \ + } \ +} while (0) + +#define _DT_INDEX_P(func) (dtps_index_##func) + +#define DT_INDEX_ENTER(func, index, args...) do { \ + extern struct dt_probe **_DT_INDEX_P(func); \ + \ + if (__predict_false(dt_tracing) && \ + __predict_false(index > 0) && \ + __predict_true(_DT_INDEX_P(func) != NULL)) { \ + struct dt_probe *dtp = _DT_INDEX_P(func)[index]; \ + \ + if(__predict_false(dtp->dtp_recording)) { \ + struct dt_provider *dtpv = dtp->dtp_prov; \ + \ + dtpv->dtpv_enter(dtpv, dtp, args); \ + } \ } \ } while (0) Index: kern/kern_synch.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_synch.c,v retrieving revision 1.185 diff -u -p -r1.185 kern_synch.c --- kern/kern_synch.c 18 Mar 2022 15:32:06 -0000 1.185 +++ kern/kern_synch.c 8 Apr 2022 09:40:29 -0000 @@ -804,7 +804,15 @@ sys___thrwakeup(struct proc *p, void *v, void refcnt_init(struct refcnt *r) { + refcnt_init_trace(r, 0); +} + +void +refcnt_init_trace(struct refcnt *r, int idx) +{ + r->r_traceidx = idx; atomic_store_int(&r->r_refs, 1); + TRACEINDEX(refcnt, r->r_traceidx, r, 0, +1); } void @@ -814,6 +822,7 @@ refcnt_take(struct refcnt *r) refs = atomic_inc_int_nv(&r->r_refs); KASSERT(refs != 0); + TRACEINDEX(refcnt, r->r_traceidx, r, refs - 1, +1); (void)refs; } @@ -824,6 +833,7 @@ refcnt_rele(struct refcnt *r) refs = atomic_dec_int_nv(&r->r_refs); KASSERT(refs != ~0); + TRACEINDEX(refcnt, r->r_traceidx, r, refs + 1, -1); return (refs == 0); } @@ -842,11 +852,13 @@ refcnt_finalize(struct refcnt *r, const refs = atomic_dec_int_nv(&r->r_refs); KASSERT(refs != ~0); + TRACEINDEX(refcnt, r->r_traceidx, r, refs + 1, -1); while (refs) { sleep_setup(&sls, r, PWAIT, wmesg, 0); refs = atomic_load_int(&r->r_refs); sleep_finish(&sls, refs); } + TRACEINDEX(refcnt, r->r_traceidx, r, refs, 0); } int @@ -855,6 +867,7 @@ refcnt_shared(struct refcnt *r) u_int refs; refs = atomic_load_int(&r->r_refs); + TRACEINDEX(refcnt, r->r_traceidx, r, refs, 0); return (refs > 1); } @@ -864,6 +877,7 @@ refcnt_read(struct refcnt *r) u_int refs; refs = atomic_load_int(&r->r_refs); + TRACEINDEX(refcnt, r->r_traceidx, r, refs, 0); return (refs); } Index: netinet/in_pcb.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.264 diff -u -p -r1.264 in_pcb.c --- netinet/in_pcb.c 22 Mar 2022 18:02:54 -0000 1.264 +++ netinet/in_pcb.c 8 Apr 2022 09:40:29 -0000 @@ -235,7 +235,7 @@ in_pcballoc(struct socket *so, struct in return (ENOBUFS); inp->inp_table = table; inp->inp_socket = so; - refcnt_init(&inp->inp_refcnt); + refcnt_init_trace(&inp->inp_refcnt, DT_REFCNT_IDX_INPCB); inp->inp_seclevel[SL_AUTH] = IPSEC_AUTH_LEVEL_DEFAULT; inp->inp_seclevel[SL_ESP_TRANS] = IPSEC_ESP_TRANS_LEVEL_DEFAULT; inp->inp_seclevel[SL_ESP_NETWORK] = IPSEC_ESP_NETWORK_LEVEL_DEFAULT; Index: netinet/ip_ipsp.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.c,v retrieving revision 1.269 diff -u -p -r1.269 ip_ipsp.c --- netinet/ip_ipsp.c 10 Mar 2022 15:21:08 -0000 1.269 +++ netinet/ip_ipsp.c 8 Apr 2022 09:40:29 -0000 @@ -1048,7 +1048,7 @@ tdb_alloc(u_int rdomain) tdbp = pool_get(&tdb_pool, PR_WAITOK | PR_ZERO); - refcnt_init(&tdbp->tdb_refcnt); + refcnt_init_trace(&tdbp->tdb_refcnt, DT_REFCNT_IDX_TDB); mtx_init(&tdbp->tdb_mtx, IPL_SOFTNET); TAILQ_INIT(&tdbp->tdb_policy_head); Index: sys/refcnt.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/sys/refcnt.h,v retrieving revision 1.6 diff -u -p -r1.6 refcnt.h --- sys/refcnt.h 16 Mar 2022 14:13:01 -0000 1.6 +++ sys/refcnt.h 8 Apr 2022 09:40:29 -0000 @@ -21,24 +21,30 @@ /* * Locks used to protect struct members in this file: + * I immutable after creation * a atomic operations */ struct refcnt { unsigned int r_refs; /* [a] reference counter */ + int r_traceidx; /* [I] index for dt(4) tracing */ }; -#define REFCNT_INITIALIZER() { .r_refs = 1 } +#define REFCNT_INITIALIZER() { .r_refs = 1, .r_traceidx = 0 } #ifdef _KERNEL void refcnt_init(struct refcnt *); +void refcnt_init_trace(struct refcnt *, int id); void refcnt_take(struct refcnt *); int refcnt_rele(struct refcnt *); void refcnt_rele_wake(struct refcnt *); void refcnt_finalize(struct refcnt *, const char *); int refcnt_shared(struct refcnt *); unsigned int refcnt_read(struct refcnt *); + +#define DT_REFCNT_IDX_INPCB 1 +#define DT_REFCNT_IDX_TDB 2 #endif /* _KERNEL */ Index: sys/tracepoint.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/sys/tracepoint.h,v retrieving revision 1.1 diff -u -p -r1.1 tracepoint.h --- sys/tracepoint.h 21 Jan 2020 16:16:23 -0000 1.1 +++ sys/tracepoint.h 8 Apr 2022 09:40:29 -0000 @@ -25,11 +25,13 @@ #if NDT > 0 #include <dev/dt/dtvar.h> -#define TRACEPOINT(func, name, args...) DT_STATIC_ENTER(func, name, args) +#define TRACEPOINT(func, name, args...) DT_STATIC_ENTER(func, name, args) +#define TRACEINDEX(func, index, args...) DT_INDEX_ENTER(func, index, args) #else /* NDT > 0 */ -#define TRACEPOINT(func, name, args...) +#define TRACEPOINT(func, name, args...) +#define TRACEINDEX(func, index, args...) #endif /* NDT > 0 */ #endif /* _KERNEL */