[Intel-gfx] [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 Intel-gfx
mailing list