Re: refcount btrace

2022-06-27 Thread Alexander Bluhm
On Fri, Apr 22, 2022 at 12:07:44AM +0200, Alexander Bluhm wrote:
> I still think it is worth to have refcount debugging in generic
> kernel dt(4).  Having tools is easier than first adding printf to
> hunt a bug.  I see no downside.

I have talked with mpi@.  We both think it is useful to have refcount
debugging tools available in GENERIC kernel.  If there are no hard
objections, I will put this in tomorrow.

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 -  1.13
> +++ dev/dt/dt_prov_static.c   21 Apr 2022 21:06:03 -
> @@ -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.h27 Feb 2022 10:14:01 -  1.13
> +++ dev/dt/dtvar.h21 Apr 2022 21:06:03 -
> @@ -313,11 +313,30 @@ extern volatile uint32_tdt_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 -  1.185
> +++ kern/kern_synch.c 21 Apr 2022 21:06:03 -
> @@ -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 @@ ref

Re: refcount btrace

2022-04-21 Thread Alexander Bluhm
I still think it is worth to have refcount debugging in generic
kernel dt(4).  Having tools is easier than first adding printf to
hunt a bug.  I see no downside.

ok?

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 -  1.13
+++ dev/dt/dt_prov_static.c 21 Apr 2022 21:06:03 -
@@ -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 -  1.13
+++ dev/dt/dtvar.h  21 Apr 2022 21:06:03 -
@@ -313,11 +313,30 @@ extern volatile uint32_t  dt_tracing; /* 
 #defineDT_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 -  1.185
+++ kern/kern_synch.c   21 Apr 2022 21:06:03 -
@@ -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, r

Re: refcount btrace

2022-04-12 Thread Alexander Bluhm
On Mon, Apr 11, 2022 at 07:19:00PM +0200, Martin Pieuchot wrote:
> On 08/04/22(Fri) 12:16, Alexander Bluhm wrote:
> > On Fri, Apr 08, 2022 at 02:39:34AM +, 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?

Script looks like this:

#!/usr/sbin/btrace
tracepoint:refcnt:inpcb{
printf("%s %x %u %+d\n", probe, arg0, arg1, arg2)
}

Note that output should be -1 instead of +4294967295, but that is
a different problem.

tracepoint:refcnt:inpcb fd80793885c0 2 +1
tracepoint:refcnt:inpcb fd80793885c0 3 +4294967295
tracepoint:refcnt:inpcb fd80793885c0 2 +1
tracepoint:refcnt:inpcb fd80793885c0 3 +4294967295
tracepoint:refcnt:inpcb fd80793885c0 2 +1
tracepoint:refcnt:inpcb fd80793885c0 3 +4294967295

Or with kernel stack:

#!/usr/sbin/btrace
tracepoint:refcnt:inpcb{
printf("%s %x %u %+d%s\n", probe, arg0, arg1, arg2, kstack)
}

tracepoint:refcnt:inpcb fd80793885c0 3 +4294967295
refcnt_rele+0x88
in_pcbunref+0x24
pf_find_state+0x2a6
pf_test_state+0x172
pf_test+0xd17
ip6_output+0xd14
tcp_output+0x164f
tcp_usrreq+0x386
sosend+0x37c
dofilewritev+0x14d
sys_write+0x51
syscall+0x314
Xsyscall+0x128
kernel

> > 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 -  1.13
> > +++ dev/dt/dt_prov_static.c 8 Apr 2022 09:40:29 -
> > @@ -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_pr

Re: refcount btrace

2022-04-11 Thread Martin Pieuchot
On 08/04/22(Fri) 12:16, Alexander Bluhm wrote:
> On Fri, Apr 08, 2022 at 02:39:34AM +, 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 -  1.13
> +++ dev/dt/dt_prov_static.c   8 Apr 2022 09:40:29 -
> @@ -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.h27 Feb 2022 10:14:01 -  1.13
> +++ dev/dt/dtvar.h8 Apr 2022 09:42:19 -
> @@ -313,11 +313,30 @@ extern volatile uint32_tdt_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 (__pr

Re: refcount btrace

2022-04-08 Thread Alexander Bluhm
On Fri, Apr 08, 2022 at 02:39:34AM +, 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 -  1.13
+++ dev/dt/dt_prov_static.c 8 Apr 2022 09:40:29 -
@@ -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 -  1.13
+++ dev/dt/dtvar.h  8 Apr 2022 09:42:19 -
@@ -313,11 +313,30 @@ extern volatile uint32_t  dt_tracing; /* 
 #defineDT_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);  \
+   }  

Re: refcount btrace

2022-04-07 Thread Visa Hankala
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.

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.



Re: refcount btrace

2022-04-07 Thread Alexander Bluhm
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.

ok?

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 -  1.13
+++ dev/dt/dt_prov_static.c 7 Apr 2022 17:32:23 -
@@ -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 -  1.13
+++ dev/dt/dtvar.h  7 Apr 2022 17:41:55 -
@@ -313,11 +313,30 @@ extern volatile uint32_t  dt_tracing; /* 
 #defineDT_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(index > 0) &&   \
+   __predict_false(dt_tracing) &&  \
+   __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 -  1.185
+++ kern/kern_synch.c   7 Apr 2022 16:25:45 -
@@ -804,7 +804,15 @

Re: refcount btrace

2022-03-23 Thread Alexander Bluhm
On Mon, Mar 21, 2022 at 01:22:22PM +0100, Martin Pieuchot wrote:
> On 20/03/22(Sun) 05:39, Visa Hankala wrote:
> > On Sat, Mar 19, 2022 at 12:10:11AM +0100, Alexander Bluhm wrote:
> > > On Thu, Mar 17, 2022 at 07:25:27AM +, Visa Hankala wrote:
> > > > On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> > > > > I would like to use btrace to debug refernce counting.  The idea
> > > > > is to a a tracepoint for every type of refcnt we have.  When it
> > > > > changes, print the actual object, the current counter and the change
> > > > > value.
> > > > 
> > > > > Do we want that feature?
> > > > 
> > > > I am against this in its current form. The code would become more
> > > > complex, and the trace points can affect timing. There is a risk that
> > > > the kernel behaves slightly differently when dt has been compiled in.
> > > 
> > > On our main architectures dt(4) is in GENERIC.  I see your timing
> > > point for uvm structures.
> > 
> > In my opinion, having dt(4) enabled by default is another reason why
> > there should be no carte blanche for adding trace points. Each trace
> > point adds a tiny amount of bloat. Few users will use the tracing
> > facility.
> > 
> > Maybe high-rate trace points could be behind a build option...
> 
> The whole point of dt(4) is to be able to debug GENERIC kernel.  I doubt
> the cost of an additional if () block matters.

The idea of dt(4) is that developer or end user with instructions
can debug a running kernel without recompiling.  So we have to put
trace points at places where we gain much information.

I did some meassurement with and without dt.  Note that I configure
my tests machines with sysctl kern.allowdt=1.  I had to disable it
in kernel diff.

http://bluhm.genua.de/perform/results/2022-03-21T09%3A08%3A37Z/perform.html

I see difference from moving the kernel objects.  Even reboot and
testing again has more variance than dt(4).

The story is different when btrace(8) is actually running.  Look
at the numbers in the right column.

http://bluhm.genua.de/perform/results/2022-03-21T09%3A08%3A37Z/2022-03-21T00%3A00%3A00Z/perform.html

For the network test it does not matter, as our IP stack uses only
one or maybe two cores.  On a 4 core machine btrace userland can
use 1 core.  When compiling the kernel in the "make-bsd-j4" test
row, the build time goes up as btrace takes CPU time from the
compiler.

In my opinion tracepoints give insight at minimal cost.  It is worth
it to have it in GENERIC to make it easy to use.

bluhm



Re: refcount btrace

2022-03-21 Thread Martin Pieuchot
On 20/03/22(Sun) 05:39, Visa Hankala wrote:
> On Sat, Mar 19, 2022 at 12:10:11AM +0100, Alexander Bluhm wrote:
> > On Thu, Mar 17, 2022 at 07:25:27AM +, Visa Hankala wrote:
> > > On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> > > > I would like to use btrace to debug refernce counting.  The idea
> > > > is to a a tracepoint for every type of refcnt we have.  When it
> > > > changes, print the actual object, the current counter and the change
> > > > value.
> > > 
> > > > Do we want that feature?
> > > 
> > > I am against this in its current form. The code would become more
> > > complex, and the trace points can affect timing. There is a risk that
> > > the kernel behaves slightly differently when dt has been compiled in.
> > 
> > On our main architectures dt(4) is in GENERIC.  I see your timing
> > point for uvm structures.
> 
> In my opinion, having dt(4) enabled by default is another reason why
> there should be no carte blanche for adding trace points. Each trace
> point adds a tiny amount of bloat. Few users will use the tracing
> facility.
> 
> Maybe high-rate trace points could be behind a build option...

The whole point of dt(4) is to be able to debug GENERIC kernel.  I doubt
the cost of an additional if () block matters.



Re: refcount btrace

2022-03-19 Thread Visa Hankala
On Sat, Mar 19, 2022 at 12:10:11AM +0100, Alexander Bluhm wrote:
> On Thu, Mar 17, 2022 at 07:25:27AM +, Visa Hankala wrote:
> > On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> > > I would like to use btrace to debug refernce counting.  The idea
> > > is to a a tracepoint for every type of refcnt we have.  When it
> > > changes, print the actual object, the current counter and the change
> > > value.
> > 
> > > Do we want that feature?
> > 
> > I am against this in its current form. The code would become more
> > complex, and the trace points can affect timing. There is a risk that
> > the kernel behaves slightly differently when dt has been compiled in.
> 
> On our main architectures dt(4) is in GENERIC.  I see your timing
> point for uvm structures.

In my opinion, having dt(4) enabled by default is another reason why
there should be no carte blanche for adding trace points. Each trace
point adds a tiny amount of bloat. Few users will use the tracing
facility.

Maybe high-rate trace points could be behind a build option...

> What do you think about this?  The check starts with a
> __predict_false(index > 0) in #define DT_INDEX_ENTER.  The r_traceidx
> is very likely in the same cache line as r_refs.  So the additional
> overhead of the branch should be small compared to the atomic
> operation.  The __predict_false(dt_tracing) might take longer as
> it is a global variable.

I have no hard data to back up my claim, but I think dt_tracing should
be checked first. This would make the situation easier for branch
prediction. It is likely that dt_tracing is already in cache.



Re: refcount btrace

2022-03-18 Thread Alexander Bluhm
On Thu, Mar 17, 2022 at 07:25:27AM +, Visa Hankala wrote:
> On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> > I would like to use btrace to debug refernce counting.  The idea
> > is to a a tracepoint for every type of refcnt we have.  When it
> > changes, print the actual object, the current counter and the change
> > value.
> 
> > Do we want that feature?
> 
> I am against this in its current form. The code would become more
> complex, and the trace points can affect timing. There is a risk that
> the kernel behaves slightly differently when dt has been compiled in.

On our main architectures dt(4) is in GENERIC.  I see your timing
point for uvm structures.

What do you think about this?  The check starts with a
__predict_false(index > 0) in #define DT_INDEX_ENTER.  The r_traceidx
is very likely in the same cache line as r_refs.  So the additional
overhead of the branch should be small compared to the atomic
operation.  The __predict_false(dt_tracing) might take longer as
it is a global variable.

Default is not to trace refcnt.  But I would like to have it for
network objects.  For sending network packets the additional branch
instruction depending on a global variable does not count.

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 -  1.13
+++ dev/dt/dt_prov_static.c 18 Mar 2022 20:35:02 -
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 2019 Martin Pieuchot 
+ * Copyright (c) 2022 Alexander Bluhm 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -87,6 +88,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 +134,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 -  1.13
+++ dev/dt/dtvar.h  18 Mar 2022 20:58:28 -
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 2019 Martin Pieuchot 
+ * Copyright (c) 2022 Alexander Bluhm 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -313,11 +314,30 @@ extern volatile uint32_t  dt_tracing; /* 
 #defineDT_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(index > 0) &&   \
+   __predict_false(dt_tracing) &&  \
+   __predict_true(_DT_INDEX_P(func) != NULL)) {\
+   struct dt_probe *dtp = _DT_INDEX_P(func)[index];\
+

Re: refcount btrace

2022-03-18 Thread Visa Hankala
On Thu, Mar 17, 2022 at 06:16:51PM +0100, Alexander Bluhm wrote:
> On Thu, Mar 17, 2022 at 07:25:27AM +, Visa Hankala wrote:
> > On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> > > I would like to use btrace to debug refernce counting.  The idea
> > > is to a a tracepoint for every type of refcnt we have.  When it
> > > changes, print the actual object, the current counter and the change
> > > value.
> > 
> > > Do we want that feature?
> > 
> > I am against this in its current form. The code would become more
> > complex, and the trace points can affect timing. There is a risk that
> > the kernel behaves slightly differently when dt has been compiled in.
> 
> Can we get in this part then?
> 
> - Remove DIAGNOSTIC to keep similar in non DIAGNOSTIC case.
> - Rename refcnt to refs.  refcnt is the struct, refs contains the
>   r_refs value.
> - Add KASSERT(refs != ~0) in refcnt_finalize().
> - Always use u_int refs so I can insert my btrace diff easily.

I think this is fine.

OK visa@

> Index: kern/kern_synch.c
> ===
> RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_synch.c,v
> retrieving revision 1.184
> diff -u -p -r1.184 kern_synch.c
> --- kern/kern_synch.c 16 Mar 2022 14:13:01 -  1.184
> +++ kern/kern_synch.c 17 Mar 2022 16:12:50 -
> @@ -810,25 +810,21 @@ refcnt_init(struct refcnt *r)
>  void
>  refcnt_take(struct refcnt *r)
>  {
> -#ifdef DIAGNOSTIC
> - u_int refcnt;
> + u_int refs;
>  
> - refcnt = atomic_inc_int_nv(&r->r_refs);
> - KASSERT(refcnt != 0);
> -#else
> - atomic_inc_int(&r->r_refs);
> -#endif
> + refs = atomic_inc_int_nv(&r->r_refs);
> + KASSERT(refs != 0);
> + (void)refs;
>  }
>  
>  int
>  refcnt_rele(struct refcnt *r)
>  {
> - u_int refcnt;
> + u_int refs;
>  
> - refcnt = atomic_dec_int_nv(&r->r_refs);
> - KASSERT(refcnt != ~0);
> -
> - return (refcnt == 0);
> + refs = atomic_dec_int_nv(&r->r_refs);
> + KASSERT(refs != ~0);
> + return (refs == 0);
>  }
>  
>  void
> @@ -842,26 +838,33 @@ void
>  refcnt_finalize(struct refcnt *r, const char *wmesg)
>  {
>   struct sleep_state sls;
> - u_int refcnt;
> + u_int refs;
>  
> - refcnt = atomic_dec_int_nv(&r->r_refs);
> - while (refcnt) {
> + refs = atomic_dec_int_nv(&r->r_refs);
> + KASSERT(refs != ~0);
> + while (refs) {
>   sleep_setup(&sls, r, PWAIT, wmesg, 0);
> - refcnt = atomic_load_int(&r->r_refs);
> - sleep_finish(&sls, refcnt);
> + refs = atomic_load_int(&r->r_refs);
> + sleep_finish(&sls, refs);
>   }
>  }
>  
>  int
>  refcnt_shared(struct refcnt *r)
>  {
> - return (atomic_load_int(&r->r_refs) > 1);
> + u_int refs;
> +
> + refs = atomic_load_int(&r->r_refs);
> + return (refs > 1);
>  }
>  
>  unsigned int
>  refcnt_read(struct refcnt *r)
>  {
> - return (atomic_load_int(&r->r_refs));
> + u_int refs;
> +
> + refs = atomic_load_int(&r->r_refs);
> + return (refs);
>  }
>  
>  void
> 



Re: refcount btrace

2022-03-17 Thread Alexander Bluhm
On Thu, Mar 17, 2022 at 07:25:27AM +, Visa Hankala wrote:
> On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> > I would like to use btrace to debug refernce counting.  The idea
> > is to a a tracepoint for every type of refcnt we have.  When it
> > changes, print the actual object, the current counter and the change
> > value.
> 
> > Do we want that feature?
> 
> I am against this in its current form. The code would become more
> complex, and the trace points can affect timing. There is a risk that
> the kernel behaves slightly differently when dt has been compiled in.

Can we get in this part then?

- Remove DIAGNOSTIC to keep similar in non DIAGNOSTIC case.
- Rename refcnt to refs.  refcnt is the struct, refs contains the
  r_refs value.
- Add KASSERT(refs != ~0) in refcnt_finalize().
- Always use u_int refs so I can insert my btrace diff easily.

Maybe I can optimize btrace diff later.

bluhm

Index: kern/kern_synch.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_synch.c,v
retrieving revision 1.184
diff -u -p -r1.184 kern_synch.c
--- kern/kern_synch.c   16 Mar 2022 14:13:01 -  1.184
+++ kern/kern_synch.c   17 Mar 2022 16:12:50 -
@@ -810,25 +810,21 @@ refcnt_init(struct refcnt *r)
 void
 refcnt_take(struct refcnt *r)
 {
-#ifdef DIAGNOSTIC
-   u_int refcnt;
+   u_int refs;
 
-   refcnt = atomic_inc_int_nv(&r->r_refs);
-   KASSERT(refcnt != 0);
-#else
-   atomic_inc_int(&r->r_refs);
-#endif
+   refs = atomic_inc_int_nv(&r->r_refs);
+   KASSERT(refs != 0);
+   (void)refs;
 }
 
 int
 refcnt_rele(struct refcnt *r)
 {
-   u_int refcnt;
+   u_int refs;
 
-   refcnt = atomic_dec_int_nv(&r->r_refs);
-   KASSERT(refcnt != ~0);
-
-   return (refcnt == 0);
+   refs = atomic_dec_int_nv(&r->r_refs);
+   KASSERT(refs != ~0);
+   return (refs == 0);
 }
 
 void
@@ -842,26 +838,33 @@ void
 refcnt_finalize(struct refcnt *r, const char *wmesg)
 {
struct sleep_state sls;
-   u_int refcnt;
+   u_int refs;
 
-   refcnt = atomic_dec_int_nv(&r->r_refs);
-   while (refcnt) {
+   refs = atomic_dec_int_nv(&r->r_refs);
+   KASSERT(refs != ~0);
+   while (refs) {
sleep_setup(&sls, r, PWAIT, wmesg, 0);
-   refcnt = atomic_load_int(&r->r_refs);
-   sleep_finish(&sls, refcnt);
+   refs = atomic_load_int(&r->r_refs);
+   sleep_finish(&sls, refs);
}
 }
 
 int
 refcnt_shared(struct refcnt *r)
 {
-   return (atomic_load_int(&r->r_refs) > 1);
+   u_int refs;
+
+   refs = atomic_load_int(&r->r_refs);
+   return (refs > 1);
 }
 
 unsigned int
 refcnt_read(struct refcnt *r)
 {
-   return (atomic_load_int(&r->r_refs));
+   u_int refs;
+
+   refs = atomic_load_int(&r->r_refs);
+   return (refs);
 }
 
 void



Re: refcount btrace

2022-03-17 Thread Visa Hankala
On Thu, Mar 17, 2022 at 12:42:13AM +0100, Alexander Bluhm wrote:
> I would like to use btrace to debug refernce counting.  The idea
> is to a a tracepoint for every type of refcnt we have.  When it
> changes, print the actual object, the current counter and the change
> value.

> Do we want that feature?

I am against this in its current form. The code would become more
complex, and the trace points can affect timing. There is a risk that
the kernel behaves slightly differently when dt has been compiled in.



refcount btrace

2022-03-16 Thread Alexander Bluhm
Hi,

I would like to use btrace to debug refernce counting.  The idea
is to a a tracepoint for every type of refcnt we have.  When it
changes, print the actual object, the current counter and the change
value.

#!/usr/sbin/btrace
tracepoint:refcnt:inpcb{
printf("%s %x %u %+d\n", probe, arg0, arg1, arg2)
}

It should look like this:

tracepoint:refcnt:inpcb fd8078e31840 0 +1
tracepoint:refcnt:inpcb fd8078e31840 1 +1
tracepoint:refcnt:inpcb fd8078e31840 2 +1
tracepoint:refcnt:inpcb fd8078e31840 3 -1
tracepoint:refcnt:inpcb fd8078e31840 2 +1
tracepoint:refcnt:inpcb fd8078e31840 3 -1
tracepoint:refcnt:inpcb fd8078e31840 2 -1
tracepoint:refcnt:inpcb fd8078e31840 1 -1

Unfortunately btrace cannot deal with negative numbers right now.
So it looks like this, but that can be fixed independently.

tracepoint:refcnt:inpcb fd8078e31840 0 +1
tracepoint:refcnt:inpcb fd8078e31840 1 +1
tracepoint:refcnt:inpcb fd8078e31840 2 +1
tracepoint:refcnt:inpcb fd8078e31840 3 +4294967295
tracepoint:refcnt:inpcb fd8078e31840 2 +1
tracepoint:refcnt:inpcb fd8078e31840 3 +4294967295
tracepoint:refcnt:inpcb fd8078e31840 2 +4294967295
tracepoint:refcnt:inpcb fd8078e31840 1 +4294967295

To debug leaks, btrace can also print kernel stack trace.

tracepoint:refcnt:inpcb fd8078e31840 0 +1
in_pcballoc+0x92
tcp_attach+0xd1
sonewconn+0x23d
syn_cache_get+0x1bf
tcp_input+0x885
ip_deliver+0xd3
ip6_input_if+0x762
ipv6_input+0x39
ether_input+0x3a2
if_input_process+0x6f
ifiq_process+0x69
taskq_thread+0xdc
proc_trampoline+0x17
kernel
tracepoint:refcnt:inpcb fd8078e31840 1 +1
in_pcbref+0x29
pf_inp_link+0x4e
tcp_input+0x8d2
ip_deliver+0xd3
ip6_input_if+0x762
ipv6_input+0x39
ether_input+0x3a2
if_input_process+0x6f
ifiq_process+0x69
taskq_thread+0xdc
proc_trampoline+0x17
kernel
tracepoint:refcnt:inpcb fd8078e31840 2 +1
in_pcbref+0x29
pf_mbuf_link_inpcb+0x27
tcp_output+0x1455
tcp_usrreq+0x386
sosend+0x37c
dofilewritev+0x14d
sys_write+0x51
syscall+0x314
Xsyscall+0x128
kernel

I register the tracepoint when initializing the refcnt.  There
exists a global array of possible refcnt types.  I implemented it
only for inpcb and tdb as a prove of concept.

Do we want that feature?

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.12
diff -u -p -r1.12 dt_prov_static.c
--- dev/dt/dt_prov_static.c 26 Jan 2022 06:31:31 -  1.12
+++ dev/dt/dt_prov_static.c 16 Mar 2022 23:22:34 -
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 2019 Martin Pieuchot 
+ * Copyright (c) 2022 Alexander Bluhm 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -87,6 +88,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 +134,24 @@ struct dt_probe *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 **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 -  1.13
+++ dev/dt/dtvar.h  16 Mar 2022 23:22:34 -
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 2019 Martin Pieuchot 
+ * Copyright (c) 2022 Alexander Bluhm 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -313,11 +314,29 @@ extern volatile uint32_t  dt_tracing; /* 
 #defineDT_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