tracepoints: Add warnings for unused tracepoints and trace events
Subsystems (3)
v8 cover tracepoints: Add warnings for unused tracepoints and trace events
Every trace event can take up to 5K of memory in text and metadata regardless if they are used or not. Trace events should not be created if they are not used. Currently there's several events in the kernel that are defined but unused, either because their callers were removed without removing the trace event with it, or a config hides the trace event caller but not the trace event itself. And in some cases, trace events were simply added but were never called for whatever reason. The number of unused trace events continues to grow.
This patch series aims to fix this.
The first patch moves the elf parsing out of sorttable.c so that it can be used by other tooling.
The second patch creates a new program to run during build called tracepoint-update (note this may be extended to do other tracepoint modifications in the future). It also creates a new section called __tracepoint_check, where all callers of a tracepoint creates a variable that is placed in this section with the name of the tracepoint they use. The scripts/tracepoint-update.c is used to find tracepoints that are defined but not used which would mean they would not be in the __tracepoint_check section. It sorts the names from that section, and then reads the __tracepoint_strings section that has all compiled in tracepoint names. It makes sure that every tracepoint is found in the check section and if not, it prints a warning message about it. This lists the missing tracepoints at build time.
The third patch adds EXPORT_TRACEPOINT() to the __tracepoint_check section as well. There was several locations that adds tracepoints in the kernel proper that are only used in modules. It was getting quite complex trying to move things around that I just decided to make any tracepoint in a EXPORT_TRACEPOINT "used". I'm using the analogy of static and global functions. An unused static function gets a warning but an unused global one does not.
Changes since v7: https://lore.kernel.org/all/[email protected]/
- Removed accidentally added .PRECIOUS from Makefile.vmlinux (Nicolas Schier)
- Fixed some comment issues (Randy Dunlap)
git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
unused-tracepoints/core
Head SHA1: d2bdb5b9bb9047849016b7862741282900665a08
Steven Rostedt (3):
sorttable: Move ELF parsing into scripts/elf-parse.[ch]
tracing: Add a tracepoint verification check at build time
tracepoint: Do not warn for unused event that is exported
----
include/asm-generic/vmlinux.lds.h | 1 + include/linux/tracepoint.h | 12 + kernel/trace/Kconfig | 10 + scripts/Makefile | 6 + scripts/elf-parse.c | 198 ++++++++++++++++ scripts/elf-parse.h | 305 ++++++++++++++++++++++++ scripts/link-vmlinux.sh | 4 + scripts/sorttable.c | 477 +++----------------------------------- scripts/tracepoint-update.c | 232 ++++++++++++++++++ 9 files changed, 802 insertions(+), 443 deletions(-) create mode 100644 scripts/elf-parse.c create mode 100644 scripts/elf-parse.h create mode 100644 scripts/tracepoint-update.c
PATCH v8 1/3 sorttable: Move ELF parsing into scripts/elf-parse.[ch]
From: Steven Rostedt <[email protected]>
In order to share the elf parsing that is in sorttable.c so that other programs could use the same code, move it into elf-parse.c and elf-parse.h.
---
Changes since v7: https://lore.kernel.org/[email protected]
- Removed accidentally added .PRECIOUS from Makefile.vmlinux (Nicolas Schier)
scripts/Makefile | 3 + scripts/elf-parse.c | 198 ++++++++++++++++++ scripts/elf-parse.h | 305 ++++++++++++++++++++++++++++ scripts/sorttable.c | 477 ++++---------------------------------------- 4 files changed, 540 insertions(+), 443 deletions(-) create mode 100644 scripts/elf-parse.c create mode 100644 scripts/elf-parse.h
scripts/Makefile +3 -0
@@ -12,6 +12,8 @@ hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen +sorttable-objs := sorttable.o elf-parse.o + ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),) always-$(CONFIG_RUST) += target.json filechk_rust_target = $< < include/config/auto.conf
@@ -25,6 +27,7 @@ generate_rust_target-rust := y rustdoc_test_builder-rust := y rustdoc_test_gen-rust := y +HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include HOSTLDLIBS_sorttable = -lpthread HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
scripts/elf-parse.c new file +198 -0
198 lines not on this page · raw message
scripts/elf-parse.h new file +305 -0
305 lines not on this page · raw message
scripts/sorttable.c +34 -443
622 lines not on this page · raw message
Signature · 1 line
2.50.1
PATCH v8 2/3 tracing: Add a tracepoint verification check at build time
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
If a tracepoint is defined via DECLARE_TRACE() or TRACE_EVENT() but never called (via the trace_<tracepoint>() function), its metadata is still around in memory and not discarded.
When created via TRACE_EVENT() the situation is worse because the TRACE_EVENT() creates metadata that can be around 5k per trace event. Having unused trace events causes several thousand of wasted bytes.
Add a verifier that injects a string of the name of the tracepoint it calls that is added to the discarded section "__tracepoint_check". For every builtin tracepoint, its name (which is saved in the in-memory section "__tracepoint_strings") will have its name also in the "__tracepoint_check" section if it is used.
Add a new program that is run on build called tracepoint-update. This is executed on the vmlinux.o before the __tracepoint_check section is discarded (the section is discarded before vmlinux is created). This program will create an array of each string in the __tracepoint_check section and then sort it. Then it will walk the strings in the __tracepoint_strings section and do a binary search to check if its name is in the __tracepoint_check section. If it is not, then it is unused and a warning is printed.
Note, this currently only handles tracepoints that are builtin and not in modules.
Enabling this currently with a given config produces:
warning: tracepoint 'sched_move_numa' is unused.
warning: tracepoint 'sched_stick_numa' is unused.
warning: tracepoint 'sched_swap_numa' is unused.
warning: tracepoint 'pelt_hw_tp' is unused.
warning: tracepoint 'pelt_irq_tp' is unused.
warning: tracepoint 'rcu_preempt_task' is unused.
warning: tracepoint 'rcu_unlock_preempted_task' is unused.
warning: tracepoint 'xdp_bulk_tx' is unused.
warning: tracepoint 'xdp_redirect_map' is unused.
warning: tracepoint 'xdp_redirect_map_err' is unused.
warning: tracepoint 'vma_mas_szero' is unused.
warning: tracepoint 'vma_store' is unused.
warning: tracepoint 'hugepage_set_pmd' is unused.
warning: tracepoint 'hugepage_set_pud' is unused.
warning: tracepoint 'hugepage_update_pmd' is unused.
warning: tracepoint 'hugepage_update_pud' is unused.
warning: tracepoint 'block_rq_remap' is unused.
warning: tracepoint 'xhci_dbc_handle_event' is unused.
warning: tracepoint 'xhci_dbc_handle_transfer' is unused.
warning: tracepoint 'xhci_dbc_gadget_ep_queue' is unused.
warning: tracepoint 'xhci_dbc_alloc_request' is unused.
warning: tracepoint 'xhci_dbc_free_request' is unused.
warning: tracepoint 'xhci_dbc_queue_request' is unused.
warning: tracepoint 'xhci_dbc_giveback_request' is unused.
warning: tracepoint 'tcp_ao_wrong_maclen' is unused.
warning: tracepoint 'tcp_ao_mismatch' is unused.
warning: tracepoint 'tcp_ao_key_not_found' is unused.
warning: tracepoint 'tcp_ao_rnext_request' is unused.
warning: tracepoint 'tcp_ao_synack_no_key' is unused.
warning: tracepoint 'tcp_ao_snd_sne_update' is unused.
warning: tracepoint 'tcp_ao_rcv_sne_update' is unused.
Some of the above is totally unused but others are not used due to their "trace_" functions being inside configs, in which case, the defined tracepoints should also be inside those same configs. Others are architecture specific but defined in generic code, where they should either be moved to the architecture or be surrounded by #ifdef for the architectures they are for.
This tool could be updated to process modules in the future.
I'd like to thank Mathieu Desnoyers for suggesting using strings instead of pointers, as using pointers in vmlinux.o required handling relocations and it required implementing almost a full feature linker to do so.
---
Changes since v7: https://lore.kernel.org/[email protected]
- Fixed some comment issues (Randy Dunlap)
include/asm-generic/vmlinux.lds.h | 1 + include/linux/tracepoint.h | 10 ++ kernel/trace/Kconfig | 10 ++ scripts/Makefile | 3 + scripts/link-vmlinux.sh | 4 + scripts/tracepoint-update.c | 232 ++++++++++++++++++++++++++++++ 6 files changed, 260 insertions(+) create mode 100644 scripts/tracepoint-update.c
include/asm-generic/vmlinux.lds.h +1 -0
@@ -1047,6 +1047,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) *(.modinfo) \ /* ld.bfd warns about .gnu.version* even when not emitted */ \ *(.gnu.version*) \ + *(__tracepoint_check)#define DISCARDS \ /DISCARD/ : { \
include/linux/tracepoint.h +10 -0
@@ -221,6 +221,14 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) __do_trace_##name(args); \ } +#ifdef CONFIG_TRACEPOINT_WARN_ON_UNUSED +# define TRACEPOINT_CHECK (name) \ + static const char __used __section("__tracepoint_check") __trace_check[] = \ + #name; +#else +# define TRACEPOINT_CHECK (tname) +#endif +/* * Make sure the alignment of the structure in the __tracepoints section will * not add unwanted padding between the beginning of the section and the
@@ -270,6 +278,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) __DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), PARAMS(data_proto)) \ static inline void __do_trace_##name(proto) \ { \ +TRACEPOINT_CHECK (name) \ if (cond) { \guard (preempt_notrace)(); \__DO_TRACE_CALL (name,TP_ARGS (args)); \
@@ -289,6 +298,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) __DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), PARAMS(data_proto)) \ static inline void __do_trace_##name(proto) \ { \ +TRACEPOINT_CHECK (name) \guard (rcu_tasks_trace )(); \__DO_TRACE_CALL (name,TP_ARGS (args)); \ } \
kernel/trace/Kconfig +10 -0
@@ -1067,6 +1067,16 @@ config GCOV_PROFILE_FTRACE Note that on a kernel compiled with this config, ftrace will run significantly slower. +config TRACEPOINT_WARN_ON_UNUSED + bool "Warn on build if a tracepoint is defined but not used" + depends on TRACEPOINTS + help + This option checks if every builtin defined tracepoint is + used in the code. If a tracepoint is defined but not used, + it will waste memory as its metadata is still created. + This will cause a warning at build time if it detects a + tracepoint created but never called. + config FTRACE_SELFTEST bool
scripts/Makefile +3 -0
@@ -11,8 +11,10 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen +hostprogs-always-$(CONFIG_TRACEPOINT_WARN_ON_UNUSED) += tracepoint-update sorttable-objs := sorttable.o elf-parse.o +tracepoint-update-objs := tracepoint-update.o elf-parse.o ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),) always-$(CONFIG_RUST) += target.json
@@ -27,6 +29,7 @@ generate_rust_target-rust := y rustdoc_test_builder-rust := y rustdoc_test_gen-rust := y +HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include HOSTLDLIBS_sorttable = -lpthread
scripts/link-vmlinux.sh +4 -0
@@ -211,6 +211,10 @@ kallsymso= strip_debug= generate_map= +if is_enabled CONFIG_TRACEPOINT_WARN_ON_UNUSED; then + ${objtree}/scripts/tracepoint-update vmlinux.o +fi + if is_enabled CONFIG_KALLSYMS; then true > .tmp_vmlinux0.syms kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms
scripts/tracepoint-update.c new file +232 -0
232 lines not on this page · raw message
Signature · 1 line
2.50.1
PATCH v8 3/3 tracepoint: Do not warn for unused event that is exported
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
There are a few generic events that may only be used by modules. They are defined and then set with EXPORT_TRACEPOINT*(). Mark events that are exported as being used, even though they still waste memory in the kernel proper.
--- include/linux/tracepoint.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
include/linux/tracepoint.h +4 -2
@@ -223,8 +223,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)#ifdef CONFIG_TRACEPOINT_WARN_ON_UNUSED # define TRACEPOINT_CHECK (name) \ - static const char __used __section("__tracepoint_check") __trace_check[] = \ - #name; + static const char __used __section("__tracepoint_check") \ + __trace_check_##name[] = #name;#else # define TRACEPOINT_CHECK (tname)#endif
@@ -381,10 +381,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)__DEFINE_TRACE_EXT (_name,NULL ,PARAMS (_proto),PARAMS (_args));#define EXPORT_TRACEPOINT_SYMBOL_GPL (name) \ + TRACEPOINT_CHECK(name) \ EXPORT_SYMBOL_GPL(__tracepoint_##name); \ EXPORT_SYMBOL_GPL(__traceiter_##name); \ EXPORT_STATIC_CALL_GPL(tp_func_##name)#define EXPORT_TRACEPOINT_SYMBOL (name) \ + TRACEPOINT_CHECK(name) \ EXPORT_SYMBOL(__tracepoint_##name); \ EXPORT_SYMBOL(__traceiter_##name); \ EXPORT_STATIC_CALL(tp_func_##name)
Signature · 1 line
2.50.1