[RFC PATCH 1/1] dyndbg: WIP stuff _ddebug.{modname,filenam,function} into maple-tree

From: Jim Cromie
Date: Tue Sep 12 2023 - 14:59:50 EST


The __dyndbg section, a struct _ddebug[], has 3 columns with
substantial repetition: modname, filename, function, with ~90%, ~90%,
40% each, in the builtin table.

This is hierarchically organized; modame spans 1 or more filenames,
each of which spans many functions, which may have many lines/
callsites.

1/2 baked WAG:

ISTM these nested intervals could be carefully packed into a
maple-tree, and efficiently retrieved.

The tree would be basically read-only for the pr-debugs in builtin
modules, its presumed virtue here is primarily size, speed is bonus.

If that worked, it would be trivial to segregate those _ddebug columns
to another struct, copy the intervals into the tree, then reclaim the
whole section.

I'm not sure how nesting might work. I added the MT_FLAGS_ALLOC_RANGE
flag, thinking maybe I could stuff the nested interval starters (each
distinct function, filename, modname) into the internal RANGE
containing nodes.

So this adds a dd_mt_sites maple-tree, and does 2 things to it:

1- in dynamic_debug_init(), mtree_store_range() on the module's block
of prdbg descriptors, just before calling ddebug_add_module().

2- ddebug_add_module() calls new fn: intervalize_descs(), to scan the
prdbg descriptors, and do mtree_insert() to save each new module,
filename, or function found.

2 probably makes 1 unnecessary, we shall see.

2 happens before 1, though order shouldnt matter, since insert index
does. intervalize_descs() inserts at index: &descriptor - N, where N
is 1,2,3 for function,filename,modname respectively.

this is intervalize_descs() in action:

[ 1.506878] dyndbg: add-module: kobject 10 sites 0.0
[ 1.507383] dyndbg: modname: kobject
[ 1.507763] dyndbg: filename: lib/kobject.c
[ 1.507877] dyndbg: function: kset_release
[ 1.508305] dyndbg: function: dynamic_kobj_release
[ 1.508803] dyndbg: function: kobject_cleanup
[ 1.508880] dyndbg: function: __kobject_del
[ 1.509313] dyndbg: function: kobject_add_internal
[ 1.509817] dyndbg: function: fill_kobj_path
[ 1.509882] dyndbg: 10 debug prints in module kobject

That top-down ordering is mostly preserved at test-mod's do_print
traversal of dd_mt_sites.

Whats weird here is that lines 0-309 are the builtins, and for some
reason dont have the inserts of filename and function. Lines 310
start the modprobed modules, and these include the inserts. I dont
know why..

[ 438.156488] test_dd: 303: mptcp
[ 438.156713] test_dd: 304: i386
[ 438.156926] test_dd: 305: xen
[ 438.157133] test_dd: 306: fixup
[ 438.157354] test_dd: 307: irq
[ 438.157561] test_dd: 308: decompress
[ 438.157808] test_dd: 309: kobject
[ 438.158035] test_dd: 310: i2c_piix4
[ 438.158282] test_dd: 311: drivers/i2c/busses/i2c-piix4.c
[ 438.158637] test_dd: 312: piix4_transaction
[ 438.158929] test_dd: 313: piix4_setup_aux
[ 438.159207] test_dd: 314: piix4_setup_sb800
[ 438.159507] test_dd: 315: piix4_setup
[ 438.159769] test_dd: 316: serio_raw
[ 438.160018] test_dd: 317: drivers/input/serio/serio_raw.c
[ 438.160394] test_dd: 318: serio_raw_reconnect
[ 438.160700] test_dd: 319: serio_raw_connect
[ 438.161002] test_dd: 320: intel_rapl_common
[ 438.161303] test_dd: 321: drivers/powercap/intel_rapl_common.c
[ 438.161697] test_dd: 322: rapl_remove_package
[ 438.162007] test_dd: 323: rapl_detect_domains
[ 438.162412] test_dd: 324: rapl_package_register_powercap
[ 438.163008] test_dd: 325: rapl_update_domain_data
[ 438.163383] test_dd: 326: rapl_check_unit_tpmi
[ 438.163696] test_dd: 327: rapl_check_unit_atom
[ 438.164009] test_dd: 328: rapl_check_unit_core
[ 438.164333] test_dd: 329: rapl_read_data_raw
[ 438.164634] test_dd: 330: contraint_to_pl
[ 438.164922] test_dd: 331: intel_rapl_msr
[ 438.165199] test_dd: 332: drivers/powercap/intel_rapl_msr.c
[ 438.165594] test_dd: 333: rapl_msr_probe
[ 438.165875] test_dd: 334: rapl_msr_read_raw
[ 438.166162] test_dd: 335: test_dynamic_debug
[ 438.166468] test_dd: 336: lib/test_dynamic_debug.c
[ 438.166800] test_dd: 337: test_dynamic_debug_exit
[ 438.167127] test_dd: 338: test_dynamic_debug_init
[ 438.167463] test_dd: 339: do_prints
[ 438.167716] test_dd: 340: do_levels
[ 438.167965] test_dd: 341: do_cats
[ 438.168200] test_dd: 342: test_dynamic_debug_submod
[ 438.168549] test_dd: 343: lib/test_dynamic_debug.c
[ 438.168890] test_dd: 344: test_dynamic_debug_exit
[ 438.169221] test_dd: 345: test_dynamic_debug_init
[ 438.169559] test_dd: 346: do_prints
[ 438.169810] test_dd: 347: do_levels
[ 438.170058] test_dd: 348: do_cats
did do_prints

Then magically, an augmented _find would return a vector of modname,
filename, function when needed. Or maybe a sequence of calls to
mtree_find_upper_range() could collect the internal node values of the
nested intervals {module, filename, function} a descriptor is part of.

And thats about where the souffle collapses.

Any suggestions ?

And how to get the maple-tree size ?

cc: Liam R. Howlett <Liam.Howlett@xxxxxxxxxx>
cc: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
cc: linux-mm@xxxxxxxxx
Cc: jbaron@xxxxxxxxxx
Signed-off-by: Jim Cromie <jim.cromie@xxxxxxxxx>
---
lib/dynamic_debug.c | 44 ++++++++++++++++++++++++++++++++++++++++
lib/test_dynamic_debug.c | 16 +++++++++++++++
2 files changed, 60 insertions(+)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index a5fe37d2bd01..4cfada8b506b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -25,6 +25,9 @@
#include <linux/sysctl.h>
#include <linux/ctype.h>
#include <linux/string.h>
+
+#include <linux/maple_tree.h>
+
#include <linux/parser.h>
#include <linux/string_helpers.h>
#include <linux/uaccess.h>
@@ -74,6 +77,10 @@ struct flag_settings {
unsigned int mask;
};

+/* try packing site info into a tree */
+struct maple_tree dd_mt_sites;
+EXPORT_SYMBOL(dd_mt_sites);
+
static DEFINE_MUTEX(ddebug_lock);
static LIST_HEAD(ddebug_tables);
static int verbose;
@@ -1302,6 +1309,36 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
vpr_dt_info(dt, "attach-client-module: ");
}

+static void intervalize_descs(struct _ddebug_info *di)
+{
+ struct _ddebug *dp;
+ char *mod, *src, *fn;
+ int i;
+
+ mod = src = fn = "";
+ for_each_boxed_vector(di, descs, num_descs, i, dp) {
+
+ if (strcmp(mod, dp->modname)) {
+ v3pr_info(" modname: %s\n", dp->modname);
+ mod = dp->modname;
+ mtree_insert(&dd_mt_sites, (unsigned long)dp - 3,
+ (void*)mod, GFP_KERNEL);
+ }
+ if (strcmp(src, dp->filename)) {
+ v3pr_info(" filename: %s\n", dp->filename);
+ src = dp->filename;
+ mtree_insert(&dd_mt_sites, (unsigned long)dp - 2,
+ (void*)src, GFP_KERNEL);
+ }
+ if (strcmp(fn, dp->function)) {
+ v3pr_info(" function: %s\n", dp->function);
+ fn = dp->function;
+ mtree_insert(&dd_mt_sites, (unsigned long)dp - 1,
+ (void*)fn, GFP_KERNEL);
+ }
+ }
+}
+
/*
* Allocate a new ddebug_table for the given module
* and add it to the global list.
@@ -1332,6 +1369,8 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
dt->ddebugs = di->descs;
dt->num_ddebugs = di->num_descs;

+ intervalize_descs(di);
+
INIT_LIST_HEAD(&dt->link);

mutex_lock(&ddebug_lock);
@@ -1507,6 +1546,8 @@ static int __init dynamic_debug_init(void)
}
#endif /* CONFIG_MODULES */

+ mt_init_flags(&dd_mt_sites, MT_FLAGS_ALLOC_RANGE);
+
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
@@ -1531,6 +1572,9 @@ static int __init dynamic_debug_init(void)
if (ret)
goto out_err;

+ mtree_store_range(&dd_mt_sites, (unsigned long) iter_mod_start,
+ (unsigned long) iter, (void*) modname, GFP_KERNEL);
+
mod_sites = 0;
modname = iter->modname;
iter_mod_start = iter;
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 84e049c07e77..37de3fdc2bb8 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -14,6 +14,7 @@
#endif

#include <linux/module.h>
+#include <linux/maple_tree.h>

/* re-gen output by reading or writing sysfs node: do_prints */

@@ -150,11 +151,26 @@ static void do_levels(void)
prdbg(V7);
}

+extern struct maple_tree dd_mt_sites;
+
+static void do_dd_mt_scan(void)
+{
+ long unsigned int idx;
+ void * ent;
+ int ct = 0;
+
+ mt_for_each(&dd_mt_sites, ent, idx, -1) {
+ pr_info(" %d: %s\n", ct, (char*) ent);
+ ct++;
+ }
+}
+
static void do_prints(void)
{
pr_debug("do_prints:\n");
do_cats();
do_levels();
+ do_dd_mt_scan();
}

static int __init test_dynamic_debug_init(void)
--
2.41.0