[PATCH v4 16/41] dyndbg: add drm.debug style bitmap support

jim.cromie at gmail.com jim.cromie at gmail.com
Thu Jul 28 21:25:14 UTC 2022


On Fri, Jul 22, 2022 at 2:33 PM Jason Baron <jbaron at akamai.com> wrote:
>
>
>
> On 7/20/22 11:32, Jim Cromie wrote:
> > Add kernel_param_ops and callbacks to apply a class-map to a
> > sysfs-node, which then can control classes defined in that class-map.
> > This supports uses like:
> >
> >   echo 0x3 > /sys/module/drm/parameters/debug
> >
> > IE add these:
> >
> >  - int param_set_dyndbg_classes()
> >  - int param_get_dyndbg_classes()
> >  - struct kernel_param_ops param_ops_dyndbg_classes
> >
> > Following the model of kernel/params.c STANDARD_PARAM_DEFS, these are
> > non-static and exported.  This might be unnecessary here.
> >
> > get/set use an augmented kernel_param; the arg refs a new struct
> > ddebug_classes_bitmap_param, initialized by DYNAMIC_DEBUG_CLASSBITS
> > macro, which contains:
> >
> > BITS: a pointer to the user module's ulong holding the bits/state.  By
> > ref'g the client's bit-state _var, we coordinate with existing code
> > (such as drm_debug_enabled) which uses the _var, so it works
> > unchanged, even as the foundation is switched out underneath it..
> > Using a ulong allows use of BIT() etc.
> >
> > FLAGS: dyndbg.flags toggled by changes to bitmap. Usually just "p".
> >
> > MAP: a pointer to struct ddebug_classes_map, which maps those
> > class-names to .class_ids 0..N that the module is using.  This
> > class-map is declared & initialized by DEFINE_DYNDBG_CLASSMAP.
> >
> > map-type: add support here for DD_CLASS_DISJOINT, DD_CLASS_VERBOSE.
> >
> > These 2 class-types both expect an integer; _DISJOINT treats input
> > like a bit-vector (ala drm.debug), and sets each bit accordingly.
> >
> > _VERBOSE treats input like a bit-pos:N, then sets bits(0..N)=1, and
> > bits(N+1..max)=0.  This applies (bit<N) semantics on top of disjoint
> > bits.
> >
> > cases DD_CLASS_SYMBOLIC, DD_CLASS_LEVELS are included for the complete
> > picture, with commented out call to a following commit.
> >
> > NOTES:
> >
> > this now includes SYMBOLIC/LEVELS support, too tedious to keep
> > separate thru all the tweaking.
> >
> > get-param undoes the bit-pos -> bitmap transform that set-param does
> > on VERBOSE inputs, this gives the read-what-was-written property.
> >
> > _VERBOSE is overlay on _DISJOINT:
> >
> > verbose-maps still need class-names, even though theyre not usable at
> > the sysfs interface (unlike with _SYMBOLIC/_LEVELS).
> >
> >  - It must have a "V0" name,
> >    something below "V1" to turn "V1" off.
> >    __pr_debug_cls(V0,..) is printk, don't do that.
> >
> >  - "class names" is required at the >control interface.
> >  - relative levels are not enforced at >control
> >
> > IOW this is possible, and maybe confusing:
> >
> >   echo class V3 +p > control
> >   echo class V1 -p > control
> >
> > IMO thats ok, relative verbosity is an interface property.
> >
> > Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
> > ---
> > . drop kp->mod->name as unneeded (build-dependent) <lkp>
> > ---
> >  include/linux/dynamic_debug.h |  18 ++++
> >  lib/dynamic_debug.c           | 193 ++++++++++++++++++++++++++++++++++
> >  2 files changed, 211 insertions(+)
> >
> > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > index f57076e02767..b50bdd5c8184 100644
> > --- a/include/linux/dynamic_debug.h
> > +++ b/include/linux/dynamic_debug.h
> > @@ -113,6 +113,12 @@ struct ddebug_class_map {
> >  #define NUM_TYPE_ARGS(eltype, ...)                           \
> >       (sizeof((eltype[]) {__VA_ARGS__}) / sizeof(eltype))
> >
> > +struct ddebug_classes_bitmap_param {
> > +     unsigned long *bits;
> > +     char flags[8];
> > +     const struct ddebug_class_map *map;
> > +};
> > +
> >  #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
> >
> >  int ddebug_add_module(struct _ddebug *tab, unsigned int num_debugs,
> > @@ -274,6 +280,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
> >                                  KERN_DEBUG, prefix_str, prefix_type, \
> >                                  rowsize, groupsize, buf, len, ascii)
> >
> > +struct kernel_param;
> > +int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp);
> > +int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp);
> > +
> >  /* for test only, generally expect drm.debug style macro wrappers */
> >  #define __pr_debug_cls(cls, fmt, ...) do {                   \
> >       BUILD_BUG_ON_MSG(!__builtin_constant_p(cls),            \
> > @@ -322,6 +332,14 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
> >                               rowsize, groupsize, buf, len, ascii);   \
> >       } while (0)
> >
> > +struct kernel_param;
> > +static inline int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
> > +{ return 0; }
> > +static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
> > +{ return 0; }
> > +
> >  #endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
> >
> > +extern const struct kernel_param_ops param_ops_dyndbg_classes;
> > +
> >  #endif
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 4c27bbe5187e..dd27dc514aa3 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -596,6 +596,199 @@ static int ddebug_exec_queries(char *query, const char *modname)
> >       return nfound;
> >  }
> >
> > +static int ddebug_apply_class_bitmap(const struct ddebug_classes_bitmap_param *dcp,
> > +                                  unsigned long inbits)
> > +{
> > +#define QUERY_SIZE 128
> > +     char query[QUERY_SIZE];
> > +     const struct ddebug_class_map *map = dcp->map;
> > +     int matches = 0;
> > +     int bi, ct;
> > +
> > +     v2pr_info("in: 0x%lx on: 0x%lx\n", inbits, *dcp->bits);
> > +
> > +     for (bi = 0; bi < map->length; bi++) {
> > +             if (test_bit(bi, &inbits) == test_bit(bi, dcp->bits))
> > +                     continue;
> > +
> > +             snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
> > +                      test_bit(bi, &inbits) ? '+' : '-', dcp->flags);
> > +
> > +             ct = ddebug_exec_queries(query, NULL);
> > +             matches += ct;
> > +
> > +             v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
> > +                       ct, map->class_names[bi], inbits);
> > +     }
> > +     return matches;
> > +}
> > +
> > +/* support for [+-] symbolic-name boolean list */
> > +static int param_set_dyndbg_class_strings(const char *instr, const struct kernel_param *kp)
> > +{
> > +     const struct ddebug_classes_bitmap_param *dcp = kp->arg;
> > +     const struct ddebug_class_map *map = dcp->map;
> > +     unsigned long inbits;
> > +     int idx, totct = 0;
> > +     bool wanted;
> > +     char *cls, *p;
> > +
> > +     cls = kstrdup(instr, GFP_KERNEL);
> > +     p = strchr(cls, '\n');
> > +     if (p)
> > +             *p = '\0';
> > +
> > +     vpr_info("\"%s\" > %s\n", cls, kp->name);
> > +     inbits = *dcp->bits;
> > +
> > +     for (; cls; cls = p) {
> > +             p = strchr(cls, ',');
> > +             if (p)
> > +                     *p++ = '\0';
> > +
> > +             if (*cls == '-') {
> > +                     wanted = false;
> > +                     cls++;
> > +             } else {
> > +                     wanted = true;
> > +                     if (*cls == '+')
> > +                             cls++;
> > +             }
> > +             idx = match_string(map->class_names, map->length, cls);
> > +             if (idx < 0) {
> > +                     pr_err("%s unknown to %s\n", cls, kp->name);
> > +                     continue;
> > +             }
> > +
> > +             switch (map->map_type) {
> > +             case DD_CLASS_TYPE_SYMBOLIC:
> > +                     if (test_bit(idx, &inbits) == wanted) {
> > +                             v3pr_info("no change on %s\n", cls);
> > +                             continue;
> > +                     }
> > +                     inbits ^= BIT(idx);
>
> Didn't test this out but the code here confused me. In this case the bit at idx
> in inbits doesn't match. But you are doing an exclusive OR here. So doesn't that
> always set it? Shouldn't it be cleared if wanted is false?
>

I think the trouble is - in part - inbits varname;
it starts with the old bit vector value -

        inbits = *dcp->bits;  // i'll add comment here

2nd, this is while parsing the csv of classnames,
and evaluating 1 bit/class at a time here,
and only valid class-names

and wanted therefore only pertains to classes/bits that need toggled,
wanted = 1/0  based on +/- setting for that class.

>
> > +                     break;
> > +             case DD_CLASS_TYPE_LEVELS:
> > +                     /* bitmask must respect classmap ranges, this does not */
> > +                     inbits = (1 << (idx + wanted));
>
> This line also confused me - below in DD_CLASS_TYPE_VERBOSE: case you use the
> CLASSMAP_BITMASK() which will set all the 'levels' below. So I was expecting
> that here as well as this is the symbolic level case. I think I'm missing
> something...

So this is a bit inscrutable - and the comment needs refresh.

again, we are taking classnames here, so are working a single class-id,
this time the bits are not independent, as they were above.
idx is the valid class-id pertaining to the classname
- I'll pick a better varname here too
so
   inbits = (1<< ( cls_id + wanted ? 1 : 0 ))

forces all bits below cls_id on, and maybe cls_id too.

at bottom of the classnames loop, apply-bitmap applies the bits.
it applies only changes made to inbits, by re-fetching orig dcp->bits
and comparing.

Note also the usage diffs for the 2 _NAMED styles

   echo DRM_UT_CORE,-DRM_UT_KMS,+DRM_UT_DRIVER > debug_catnames

   echo +NV_TRACE  > nv_debug_level_names

while this would be weird / makework / stress-test

   echo +V7,-V1,+V7,-V1 > /sys/module/test_dynamic_debug/p_level_names



Ive been reworking the set - including your enum suggestions,
also adding
0010-dyndbg-cleanup-local-vars-in-ddebug_init.patch
0011-dyndbg-create-and-use-struct-_ddebug_info.patch
- this gathers __dyndbg and __dyndbg_classes sections
- maybe infos, or something more subsystem-state-ey
any suggestions ?

I'll change varnames I mentioned, and add comments.
I'll add comments derived from this explanation
(hope it clears things up)

and have a few things to sort and retest, I'll send a new rev shortly.


More information about the amd-gfx mailing list