@@ -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;
@@ -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)
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@Oracle.com> cc: Matthew Wilcox (Oracle) <willy@infradead.org> cc: linux-mm@kvack.org Cc: jbaron@akamai.com Signed-off-by: Jim Cromie <jim.cromie@gmail.com> --- lib/dynamic_debug.c | 44 ++++++++++++++++++++++++++++++++++++++++ lib/test_dynamic_debug.c | 16 +++++++++++++++ 2 files changed, 60 insertions(+)