On 08/04/22(Fri) 12:16, Alexander Bluhm wrote:
> 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.

I'm happy if this can help debugging real reference counting issues.  Do
you have a script that could be committed to /usr/share/btrace to show
how to track reference counting using these probes?

> 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 */

Reply via email to