dynamic debug - core infrastructure
Subsystems (7)
PATCH 2/8 dynamic debug - core infrastructure
This is the core patch that implements a new dynamic debug infrastructure.
Each kernel sub-system seems to have its own way of dealing with debugging statements. Some of these methods include 'dprintk', 'pr_debug', 'dev_debug', 'DEBUGP'. There are also a myriad of ways of enabling these statements. Some require CONFIG_ parameters to be set, some provide /proc interfaces, while others require 'DEBUG' to be set in header files. Most of these methods also require kernel re-compiles in order to set the appropriate knobs.
I've attempted to standardize how how the kernel deals with debugging statements, both from the user as well as the kernel perspective. Why aren't these debug statements made into printk(KERN_DEBUG), and be done with it? The problem here is that 'dprintk', 'pr_debug', etc. were introduced b/c they are often provide too verbose a level of output, could potentially adversly affect system performance if they were always enabled, and they clutter up the system logs.
I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes control of debugging statements on a per-module basis in one /proc file, currently, <debugfs>/dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG, is not set, debugging statements can still be enabled as before, often by defining 'DEBUG' for the proper compilation unit. Thus, this patch set has not affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set. The rest of the discussion deals with the case where CONFIG_DYNAMIC_PRINTK_DEBUG is set.
---
Documentation/kernel-parameters.txt | 5 include/asm-generic/vmlinux.lds.h | 10 + include/linux/device.h | 16 + include/linux/dynamic_printk.h | 49 +++ include/linux/kernel.h | 78 +++++- include/linux/module.h | 5 kernel/module.c | 24 ++ lib/Kconfig.debug | 67 +++++ lib/Makefile | 2 lib/dynamic_printk.c | 492 +++++++++++++++++++++++++++++++++++ net/netfilter/nf_conntrack_pptp.c | 2 11 files changed, 744 insertions(+), 6 deletions(-) create mode 100644 include/linux/dynamic_printk.h create mode 100644 lib/dynamic_printk.c
Documentation/kernel-parameters.txt +5 -0
@@ -1580,6 +1580,11 @@ and is between 256 and 4096 characters. It is defined in the file autoconfiguration. Ranges are in pairs (memory base and size). + dynamic_printk + Enables pr_debug()/dev_dbg() calls if + CONFIG_PRINK_DYNAMIC has been enabled. These can also + be switched on/off via <debugfs>/dynamic_printk/modules + print-fatal-signals= [KNL] debug: print fatal signals print-fatal-signals=1: print segfault info to
include/asm-generic/vmlinux.lds.h +8 -2
@@ -167,7 +167,6 @@ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ *(__ksymtab_strings) \ } \ - \/* __*init sections */ \ __init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) { \ *(.ref.rodata) \
@@ -249,7 +248,14 @@ CPU_DISCARD(init.data) \ CPU_DISCARD(init.rodata) \ MEM_DISCARD(init.data) \ - MEM_DISCARD(init.rodata) + MEM_DISCARD(init.rodata) \ + VMLINUX_SYMBOL(__start___verbose_strings) = .; \ + *(__verbose_strings ) \ + VMLINUX_SYMBOL(__stop___verbose_strings) = .; \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___verbose) = .; \ + *(__verbose ) \ + VMLINUX_SYMBOL(__stop___verbose) = .;#define INIT_TEXT \ *(.init.text) \
include/linux/device.h +16 -0
@@ -595,6 +595,22 @@ extern const char *dev_driver_string(struct device *dev);#ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define dev_dbg (dev, format, ...) do { \ + static char mod_name[] \ + __attribute__((section("__verbose_strings"))) \ + = KBUILD_MODNAME; \ + static struct mod_debug foobar \ + __used \ + __attribute__((section("__verbose"), aligned(8))) = \ + { mod_name, mod_name, "0", "0", NULL }; \ + int hash = dynamic_name_hash(KBUILD_MODNAME); \ + if (dynamic_printk_enabled[raw_smp_processor_id()] & (1 << hash)) \ + dynamic_printk(KBUILD_MODNAME, \ + KERN_DEBUG KBUILD_MODNAME ": %s %s: " format,\ + dev_driver_string(dev), (dev)->bus_id, \ + ##__VA_ARGS__); \ + } while (0)#else #define dev_dbg(dev, format, arg...) \ ({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
include/linux/dynamic_printk.h new file +49 -0
49 lines not on this page · raw message
include/linux/kernel.h +75 -3
96 lines not on this page · raw message
include/linux/module.h +5 -0
@@ -16,6 +16,7 @@#include <linux/kobject.h> #include <linux/moduleparam.h> #include <linux/marker.h> +#include <linux/dynamic_printk.h> #include <asm/local.h> #include <asm/module.h>
@@ -359,6 +360,10 @@ struct modulestruct marker *markers;unsigned int num_markers;#endif +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +struct mod_debug *start_verbose; +unsigned int num_verbose; +#endif };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}
kernel/module.c +24 -0
@@ -42,6 +42,7 @@#include <linux/string.h> #include <linux/mutex.h> #include <linux/unwind.h> +#include <linux/dynamic_printk.h> #include <asm/uaccess.h> #include <asm/cacheflush.h> #include <linux/license.h>
@@ -744,6 +745,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) }/* Store the name of the last unloaded module for diagnostic purposes */ strlcpy (last_unloaded_module, mod->name,sizeof (last_unloaded_module)); +unregister_debug_module (mod->name);free_module (mod); out:
@@ -1717,6 +1719,9 @@ static struct module *load_module(void __user *umod,unsigned int unusedgplcrcindex;unsigned int markersindex;unsigned int markersstringsindex; +unsigned int verboseindex; +struct mod_debug *iter; +unsigned long value;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */
@@ -1993,6 +1998,7 @@ static struct module *load_module(void __user *umod, markersindex =find_sec (hdr, sechdrs, secstrings,"__markers" ); markersstringsindex =find_sec (hdr, sechdrs, secstrings,"__markers_strings" ); + verboseindex =find_sec (hdr, sechdrs, secstrings,"__verbose" );/* Now do relocations. */ for (i =1 ; i < hdr->e_shnum; i++) {
@@ -2020,6 +2026,11 @@ static struct module *load_module(void __user *umod, mod->num_markers = sechdrs[markersindex].sh_size /sizeof (*mod->markers);#endif +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG + mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr; + mod->num_verbose = sechdrs[verboseindex].sh_size / +sizeof (*mod->start_verbose); +#endif /* Find duplicate symbols */ err =verify_export_symbols (mod);
@@ -2043,6 +2054,19 @@ static struct module *load_module(void __user *umod,marker_update_probe_range (mod->markers, mod->markers + mod->num_markers);#endif +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +for (value = (unsigned long )mod->start_verbose; + value < (unsigned long )mod->start_verbose + + (unsigned long )(mod->num_verbose *sizeof (struct mod_debug )); + value +=sizeof (struct mod_debug )) { + iter = (struct mod_debug *)value; +register_debug_module (iter->modname, +simple_strtoul (iter->type,NULL ,10 ), + iter->logical_modname, +simple_strtoul (iter->num_flags,NULL ,10 ), + iter->flag_names); + } +#endif err =module_finalize (hdr, sechdrs, mod);if (err <0 ) goto cleanup;
lib/Kconfig.debug +67 -0
73 lines not on this page · raw message
lib/Makefile +2 -0
@@ -70,6 +70,8 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o obj-$(CONFIG_HAVE_LMB) += lmb.o +obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o + hostprogs-y := gen_crc32table clean-files := crc32table.h
lib/dynamic_printk.c new file +492 -0
492 lines not on this page · raw message
net/netfilter/nf_conntrack_pptp.c +1 -1
@@ -65,7 +65,7 @@ void struct nf_conntrack_expect *exp) __read_mostly;EXPORT_SYMBOL_GPL (nf_nat_pptp_hook_expectfn); -#ifdef DEBUG +#if defined(DEBUG ) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG )/* PptpControlMessageType names */ const char *const pptp_msg_name[] = { "UNKNOWN_MESSAGE",
Quoted 2 lines · Jason Baron
This is the core patch that implements a new dynamic debug infrastructure.
Some general and specific comments.
Quoted 1 line
+int dynamic_printk_enabled[NR_CPUS];
I don't understand why you use NR_CPUS.
Also, I think the major use cases are 1 or 2 modules enabled, no modules enabled, or all modules enabled, so the hashing of module names is particularly not useful.
Any pr_debug or dev_dbg is in a slow path.
I think a list and a direct comparison to KBUILD_MODNAME would be simpler and as fast as necessary.
lib/Kconfig.debug config FIREWIRE_OHCI_REMOTE_DMA · line 690
Quoted 4 lines
lib/Kconfig.debug +4
-0+ To set the level or flag value for type 'level' or 'flag': + + $echo "set level=<#> <module_name>" > dynamic_printk/modules +
I think that set level=<#> should also work for "all"
Perhaps a simpler interface would be to use
enable <module> <level>
where <level> not specified is 0.
lib/dynamic_printk.c line 138
Quoted 13 lines
lib/dynamic_printk.c new file +13
-0+int unregister_debug_module (char *mod_name) +{ +struct debug_name *element; +struct debug_name *parent =NULL ; +int ret =0 ; +int i; + +down (&debug_list_mutex); + element =find_debug_module (mod_name); +if (!element) { + ret = -EINVAL ; + goto out; + }
[]
lib/dynamic_printk.c line 170
Quoted 4 lines
lib/dynamic_printk.c new file +4
-0+out: +up (&debug_list_mutex); +return 0 ; +}
Because the return values aren't used,
the functions might as well be declared void
You should probably add a sprinkling of "const"
to the argument lists.
+extern void dynamic_printk(char *, char *, ...);
+ dynamic_printk(KBUILD_MODNAME, \
+ KERN_DEBUG KBUILD_MODNAME ": " fmt,\
Instead of prefixing every fmt with KBUILD_MODNAME ": ", why not change this to something like:
extern void dynamic_printk(const char *level, const char *module,
const char *fmt, ...);
and just do the printk in 2 parts?
if (module_enabled) {
printk("%s%s: ", level, module);
vprintk(fmt, args);
}If not that, why should dynamic_printk prefix a KBUILD_MODNAME at all? Why not just check if the module is enabled, then output what the code specifies?
trivial: The dynamic versions of the dev_dbg and pr_debug macros don't return the number of chars output, but always return 0.
Quoted 10 lines · Joe Perches
Quoted 2 lines · Jason Baron
This is the core patch that implements a new dynamic debug infrastructure.
Some general and specific comments.
Quoted 1 line
+int dynamic_printk_enabled[NR_CPUS];
I don't understand why you use
NR_CPUS.
Quoted 9 lines
Also, I think the major use cases are 1 or 2 modules enabled, no modules enabled, or all modules enabled, so the hashing of module names is particularly not useful.
Any
pr_debugordev_dbgis in a slow path.I think a list and a direct comparison to
KBUILD_MODNAMEwould be simpler and as fast as necessary.
NR_CPUS is used to set up a per-cpu int variable where bit 'n' is set if any enabled module's name hashes into bucket 'n'. Having a single linked list of the enabled modules would work, but i like just checking a bit in the common case. Like you pointed out, most modules are likely disabled which means in the common case, i'm just checking a bit, whereas in a linked list I'd be walking a small number of entries.
However, we can better optimize the case of no modules enabled or all modules enabled, by simply checking globals that indicate this state. I think that would be improvment. So dynamic_dbg_enabled() looks something like:
if (alloff)
return 0; elseif (allon) return 1; elseif (if hash bucket of KBUILD_MODNAME is disabled) return 0; else lookup KBUILD_MODNAME in hash table if (level or flag comparisons pass and enabled) return 1; else return 0;
Quoted 7 lines
lib/Kconfig.debug config FIREWIRE_OHCI_REMOTE_DMA · line 690
Quoted 4 lines
lib/Kconfig.debug +4
-0+ To set the level or flag value for type 'level' or 'flag': + + $echo "set level=<#> <module_name>" > dynamic_printk/modules +I think that set level=<#> should also work for "all"
good idea.
Quoted 4 lines
Perhaps a simpler interface would be to use
enable <module> <level>
where <level> not specified is 0.
hmmm, there are also 'flags' that can be set for certain modules. Right now flags and level are set the same way, via 'set level=". However, i want flags to be able to be set via their name - "set FLAG_FOOBAR=1" or
"set FLAG_FOOBAR=0". I also like having this independent of whether the module is enabled or disabled.
Quoted 16 lines
lib/dynamic_printk.c line 138
Quoted 13 lines
lib/dynamic_printk.c new file +13
-0+int unregister_debug_module (char *mod_name) +{ +struct debug_name *element; +struct debug_name *parent =NULL ; +int ret =0 ; +int i; + +down (&debug_list_mutex); + element =find_debug_module (mod_name); +if (!element) { + ret = -EINVAL ; + goto out; + }[]
Quoted 8 lines
lib/dynamic_printk.c line 170
Quoted 4 lines
lib/dynamic_printk.c new file +4
-0+out: +up (&debug_list_mutex); +return 0 ; +}Because the return values aren't used,
the functions might as well be declared void
ok
Quoted 3 lines
You should probably add a sprinkling of "const"
to the argument lists.
ok
Quoted 18 lines
include/linux/kernel.h +3
-0+extern void dynamic_printk (char *,char *, ...); + dynamic_printk(KBUILD_MODNAME, \ + KERN_DEBUG KBUILD_MODNAME ": " fmt,\Instead of prefixing every fmt with
KBUILD_MODNAME": ", why not change this to something like:extern void dynamic_printk(const char *level, const char *module,
const char *fmt, ...);and just do the printk in 2 parts?
if (module_enabled) { printk("%s%s: ", level, module); vprintk(fmt, args); }
Quoted 8 lines
If not that, why should
dynamic_printkprefix aKBUILD_MODNAMEat all? Why not just check if the module is enabled, then output what the code specifies?trivial: The dynamic versions of the
dev_dbgandpr_debugmacros don't return the number of chars output, but always return 0.
good idea - i think pr_debug and dev_dbg should simply be implemented on top of dynamic_dbg_enabled(). I'll add that in the next spin.
thanks,
-Jason
Quoted 5 lines · Jason Baron
include/linux/device.h +0
-0@@ -595,6 +595,22 @@ extern const char *dev_driver_string(struct device *dev);#ifdef DEBUG #define dev_dbg(dev, format, arg...) \
include/linux/device.h extern const char *dev_driver_string(struct device *dev); · line 606
Quoted 10 lines
include/linux/device.h +9
-0dev_printk(KERN_DEBUG , dev , format , ## arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG) +#define dev_dbg (dev, format, ...) do { \ + static char mod_name[] \ + __attribute__((section("__verbose_strings"))) \ + = KBUILD_MODNAME; \ + static struct mod_debug foobar \ + __used \ + __attribute__((section("__verbose"), aligned(8))) = \ + { mod_name, mod_name, "0", "0", NULL }; \
Does the compiler merge all of these variables together into one within the same file?
If not, should we have a new macro, one per file, for this information?
Quoted 11 lines
include/linux/kernel.h +1
-0@@ -14,6 +14,7 @@#include <linux/compiler.h> #include <linux/bitops.h> #include <linux/log2.h> +#include <linux/dynamic_printk.h> #include <asm/byteorder.h> #include <asm/bug.h>
include/linux/kernel.h extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type, · line 292
Quoted 5 lines
include/linux/kernel.h +0
-2@@ -288,15 +289,86 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type, #define pr_info(fmt, arg...) \ printk(KERN_INFO fmt, ##arg) -#ifdef DEBUG -/* If you are writing a driver, please use dev_dbg instead */
Hm, this comment is still correct, please don't delete it :)
Other than those minor nits, and the fact that your patch has a lot of trailing whitespace, it's looking very good so far.
thanks,
greg k-h
Quoted 11 lines · Greg KH
Quoted 10 lines · Jason Baron
include/linux/device.h +4
-0@@ -595,6 +595,22 @@ extern const char *dev_driver_string(struct device *dev);#ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define dev_dbg (dev, format, ...) do { \ + static char mod_name[] \ + __attribute__((section("__verbose_strings"))) \
Quoted 9 lines
include/linux/device.h extern const char *dev_driver_string(struct device *dev); · line 606
Quoted 5 lines
include/linux/device.h +5
-0+ =KBUILD_MODNAME ; \ + static struct mod_debug foobar \ +__used \ + __attribute__((section("__verbose"), aligned(8))) = \ + { mod_name, mod_name,"0" ,"0" ,NULL }; \Does the compiler merge all of these variables together into one within the same file?
no.
Quoted 2 lines
If not, should we have a new macro, one per file, for this information?
With this feature enabled, the above 'meta-data' added ~32K to the .init.data section. This memory is freed when the system boots because it is placed in the .init.data section. The same is true for modules, the 'meta-data' is freed when the module loads.
We could reduce the vmlinux by having 'register()' type calls for this infrastructure, or a new marco per file as you suggest, and i had something like that in an earlier iteration, but I think the memory savings is very small when compared to the increased complexity. The simplicity to just put a 'pr_debug()" anywhere and just have it do the right thing is nice.
Also, it should be noted that the total increase in the size of the 'vmlinux' was 3%, or 2M, this is due to the above 'meta-data', the new code, and probably most significantly, the strings, for the additinal printks. Thus, compressing the above meta-data, or eliminating it by some other means would only decrease the size of this infrastructure by 2% or so.
thanks,
-Jason
Quoted 38 lines · Jason Baron
Quoted 11 lines · Greg KH
Quoted 10 lines · Jason Baron
include/linux/device.h +4
-0@@ -595,6 +595,22 @@ extern const char *dev_driver_string(struct device *dev);#ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define dev_dbg (dev, format, ...) do { \ + static char mod_name[] \ + __attribute__((section("__verbose_strings"))) \Quoted 9 lines
include/linux/device.h extern const char *dev_driver_string(struct device *dev); · line 606
Quoted 5 lines
include/linux/device.h +5
-0+ =KBUILD_MODNAME ; \ + static struct mod_debug foobar \ +__used \ + __attribute__((section("__verbose"), aligned(8))) = \ + { mod_name, mod_name,"0" ,"0" ,NULL }; \Does the compiler merge all of these variables together into one within the same file?
no.
Quoted 2 lines
If not, should we have a new macro, one per file, for this information?
With this feature enabled, the above 'meta-data' added ~32K to the .init.data section. This memory is freed when the system boots because it is placed in the .init.data section. The same is true for modules, the 'meta-data' is freed when the module loads.
We could reduce the vmlinux by having '
register()' type calls for this infrastructure, or a new marco per file as you suggest, and i had something like that in an earlier iteration, but I think the memory savings is very small when compared to the increased complexity. The simplicity to just put a 'pr_debug()" anywhere and just have it do the right thing is nice.
Quoted 5 lines
Also, it should be noted that the total increase in the size of the 'vmlinux' was 3%, or 2M, this is due to the above 'meta-data', the new code, and probably most significantly, the strings, for the additinal printks. Thus, compressing the above meta-data, or eliminating it by some other means would only decrease the size of this infrastructure by 2% or so.
Ok, thanks for the good explaination. As long as there is a way to turn this off for the EMBEDDED people who do care about 2% at times, this should be ok.
greg k-h
Hi!
Quoted 9 lines
This is the core patch that implements a new dynamic debug infrastructure.
Each kernel sub-system seems to have its own way of dealing with debugging statements. Some of these methods include 'dprintk', '
pr_debug', 'dev_debug', 'DEBUGP'. There are also a myriad of ways of enabling these statements. Some requireCONFIG_parameters to be set, some provide /proc interfaces, while others require 'DEBUG' to be set in header files. Most of these methods also require kernel re-compiles in order to set the appropriate knobs.
Quoted 7 lines
I've attempted to standardize how how the kernel deals with debugging statements, both from the user as well as the kernel perspective. Why aren't these debug statements made into
printk(KERN_DEBUG), and be done with it? The problem here is that 'dprintk', 'pr_debug', etc. were introduced b/c they are often provide too verbose a level of output, could potentially adversly affect system performance if they were always enabled, and they clutter up the system logs.
Its good that someone is finallu cleaning this up. Thanks!
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html