From 893a3f658fc2ab47650de392a22ca5dd8442811d Mon Sep 17 00:00:00 2001 From: Douglas Raillard Date: Mon, 12 Jun 2023 10:41:36 +0100 Subject: [PATCH 1/2] lisa._assets.kmodules.lisa: Allow module-specific make variables FIX Add a way for the LISA module to be compiled with some module-specific make variables. Also ensure Makefile contains proper quoting. --- lisa/_assets/kmodules/lisa/Makefile | 18 +++++++++--------- lisa/_kmod.py | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/lisa/_assets/kmodules/lisa/Makefile b/lisa/_assets/kmodules/lisa/Makefile index bcf0b104c..e22bceaa4 100644 --- a/lisa/_assets/kmodules/lisa/Makefile +++ b/lisa/_assets/kmodules/lisa/Makefile @@ -35,12 +35,12 @@ ifneq ($(KERNELRELEASE),) LISA_KMOD_NAME ?= lisa obj-m := $(LISA_KMOD_NAME).o $(LISA_KMOD_NAME)-y := main.o tp.o wq.o features.o pixel6.o -ldflags-y += -T $(M)/features.lds +ldflags-y += -T "$(M)/features.lds" clean-files := vmlinux.h # -fno-stack-protector is needed to possibly undefined __stack_chk_guard symbol -ccflags-y = -I$(MODULE_SRC) -std=gnu11 -fno-stack-protector -Wno-declaration-after-statement +ccflags-y = "-I$(MODULE_SRC)" -std=gnu11 -fno-stack-protector -Wno-declaration-after-statement VMLINUX_TXT = $(MODULE_SRC)/private_types.txt @@ -75,15 +75,15 @@ $(VMLINUX_H): $(VMLINUX_TXT) $(VMLINUX) # definitions that would come from public kernel headers, while still allowing # easy attribute access. - pahole -F btf,dwarf -E --suppress_force_paddings --show_only_data_members --skip_missing --expand_types_once -C file://$(VMLINUX_TXT) $(VMLINUX) > _header + pahole -F btf,dwarf -E --suppress_force_paddings --show_only_data_members --skip_missing --expand_types_once -C "file://$(VMLINUX_TXT)" "$(VMLINUX)" > _header # Rename all defined types to include the prefix sed "s/\(struct\|union\|enum\)\s*\([a-zA-Z0-9_]\+\)/\1 $(VMLINUX_H_TYPE_PREFIX)\2/g" -i _header # Create a sed script to rename back to initial state the types that we explicitly asked for - sed -n "s@\(.*\)@s/\\\(struct\\\|union\\\|enum\\\)\\\s*$(VMLINUX_H_TYPE_PREFIX)\1/\\\1 \\1/;@gp" $(VMLINUX_TXT) | sed -f - -i _header + sed -n "s@\(.*\)@s/\\\(struct\\\|union\\\|enum\\\)\\\s*$(VMLINUX_H_TYPE_PREFIX)\1/\\\1 \\1/;@gp" "$(VMLINUX_TXT)" | sed -f - -i _header # Strip comments to avoid matching them with the sed regex. - $(CC) -P -E - < _header > _header_no_comment + "$(CC)" -P -E - < _header > _header_no_comment # Create forward declaration of every type sed -r -n 's/.*(struct|union|enum) ([0-9a-zA-Z_]*) .*/\1 \2;/p' _header_no_comment | sort -u > _fwd_decl # Create TYPED_DEFINED_struct_foo macros for every type, so the client code can @@ -102,7 +102,7 @@ $(VMLINUX_H): $(VMLINUX_TXT) $(VMLINUX) # There does not seem to be any other source for the info in e.g. sysfs or # procfs, so we rely on that hack for now. $(SYMBOL_NAMESPACES_H): - find $(KERNEL_SRC) '(' -name '*.c' -o -name '*.h' ')' -print0 | xargs -0 sed -n 's/MODULE_IMPORT_NS([^;]*;/\0/p' | sort -u > $@ + find "$(KERNEL_SRC)" '(' -name '*.c' -o -name '*.h' ')' -print0 | xargs -0 sed -n 's/MODULE_IMPORT_NS([^;]*;/\0/p' | sort -u > $@ echo "MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);" >> $@ # Make all object files depend on the generated sources @@ -116,12 +116,12 @@ else all: install build: - $(MAKE) -C $(KERNEL_SRC) M=$(MODULE_SRC) modules + "$(MAKE)" -C "$(KERNEL_SRC)" "M=$(MODULE_SRC)" modules install: build - $(MAKE) -C $(KERNEL_SRC) M=$(MODULE_SRC) modules_install + "$(MAKE)" -C "$(KERNEL_SRC)" "M=$(MODULE_SRC)" modules_install clean: - rm -f $(VMLINUX_H) $(SYMBOL_NAMESPACES_H) + rm -f "$(VMLINUX_H)" "$(SYMBOL_NAMESPACES_H)" endif diff --git a/lisa/_kmod.py b/lisa/_kmod.py index 1db792943..90f01172e 100644 --- a/lisa/_kmod.py +++ b/lisa/_kmod.py @@ -1844,13 +1844,20 @@ class DynamicKmod(Loggable): # Dummy memoized wrapper. The only reason we need one is that _do_compile() # needs to be pickleable to be sent to a multiprocessing Process, so it # cannot be overriden by a wrapper + + def _compile(self, make_vars=None): + make_vars = make_vars or {} + return self._memoized_compile(make_vars=tuple(sorted(make_vars.items()))) + @memoized - def _compile(self): + def _memoized_compile(self, make_vars): + make_vars = dict(make_vars) + compile_ = self._do_compile.__func__ if self._compile_needs_root: compile_ = ensure_root(compile_, inline=True) - bin_, spec = compile_(self) + bin_, spec = compile_(self, make_vars=make_vars) # Get back KernelTree._to_spec() and update the KernelTree we have in # this process with it to remember the checksum, in case ensure_root() # spawned a new process. This is then used by Target.get_kmod() that @@ -1859,8 +1866,13 @@ class DynamicKmod(Loggable): self.kernel_tree._update_spec(spec) return bin_ - def _do_compile(self): + def _do_compile(self, make_vars=None): kernel_tree = self.kernel_tree + extra_make_vars = make_vars or {} + all_make_vars = { + **extra_make_vars, + **kernel_tree.make_vars, + } src = self.src def get_key(kernel_tree): @@ -1870,7 +1882,7 @@ class DynamicKmod(Loggable): else: var_tokens = [ f'{k}={v}' - for k, v in sorted(kernel_tree.make_vars.items()) + for k, v in sorted(all_make_vars.items()) ] # Cache the compilation based on: # * the kernel tree @@ -1881,6 +1893,7 @@ class DynamicKmod(Loggable): def get_bin(kernel_tree): return src.compile( kernel_tree=kernel_tree, + make_vars=extra_make_vars, ) def lookup_cache(kernel_tree, key, enter_cm=False): -- GitLab From 619674d098251ba2c93068f093eae539ab2b0f25 Mon Sep 17 00:00:00 2001 From: Douglas Raillard Date: Tue, 4 Jul 2023 10:44:18 +0100 Subject: [PATCH 2/2] lisa._assets.kmodules.lisa: Add config macro system FEATURE Add crude config macro system that will default to enable all config options, unless they were explicitly disabled. Each config option is prefixed with LISA_CONFIG_ and takes a 0 or 1 value. This is _not_ like Kconfig, where enabling disabling is based on being defined or not. LISA_CONFIG_ can be defined to 0, meaning the option is disabled. --- lisa/_assets/kmodules/lisa/Makefile | 11 +++++++- lisa/_assets/kmodules/lisa/ftrace_events.h | 6 +++- lisa/_assets/kmodules/lisa/main.h | 3 ++ lisa/_assets/kmodules/lisa/pixel6.c | 2 ++ lisa/_assets/kmodules/lisa/tp.c | 2 ++ lisa/_kmod.py | 32 ++++++++++++++++++++++ 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lisa/_assets/kmodules/lisa/Makefile b/lisa/_assets/kmodules/lisa/Makefile index e22bceaa4..215b27a81 100644 --- a/lisa/_assets/kmodules/lisa/Makefile +++ b/lisa/_assets/kmodules/lisa/Makefile @@ -25,6 +25,7 @@ else KERNEL_SRC ?= /lib/modules/`uname -r`/build endif +CONFIG_H = $(MODULE_OBJ)/config.h VMLINUX_H = $(MODULE_OBJ)/vmlinux.h SYMBOL_NAMESPACES_H = $(MODULE_OBJ)/symbol_namespaces.h @@ -105,8 +106,16 @@ $(SYMBOL_NAMESPACES_H): find "$(KERNEL_SRC)" '(' -name '*.c' -o -name '*.h' ')' -print0 | xargs -0 sed -n 's/MODULE_IMPORT_NS([^;]*;/\0/p' | sort -u > $@ echo "MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);" >> $@ +CONFIGS='{"FOO": 1, "BAR": "hello" }' + +$(CONFIG_H): + echo "import os, json\nconfigs = json.loads(os.getenv('LISA_KMOD_CONFIG', '{}'))\nfor name, value in configs.items():\n print(f'#define LISA_CONFIG_{name.upper()} {json.dumps(value)}')" | python3 /dev/stdin > $@ + find "$(MODULE_SRC)" '(' -name '*.h' -o -name '*.c' ')' -exec sed -n 's/.*\b\(LISA_CONFIG_[a-zA-Z0-9_]*\)\b.*/\1/p' '{}' ';' | sort -u | sed 's/\(.*\)/\n#ifndef \1\n #define \1 1\n#endif\n/' >> $@ + cat $@ + + # Make all object files depend on the generated sources -$(addprefix $(MODULE_OBJ)/,$($(LISA_KMOD_NAME)-y)): $(VMLINUX_H) $(SYMBOL_NAMESPACES_H) +$(addprefix $(MODULE_OBJ)/,$($(LISA_KMOD_NAME)-y)): $(CONFIG_H) $(VMLINUX_H) $(SYMBOL_NAMESPACES_H) # Non-Kbuild part else diff --git a/lisa/_assets/kmodules/lisa/ftrace_events.h b/lisa/_assets/kmodules/lisa/ftrace_events.h index e71d6961f..b068dc404 100644 --- a/lisa/_assets/kmodules/lisa/ftrace_events.h +++ b/lisa/_assets/kmodules/lisa/ftrace_events.h @@ -303,6 +303,7 @@ TRACE_EVENT_CONDITION(lisa__uclamp_util_cfs, #define trace_lisa__uclamp_util_cfs_enabled() false #endif /* CONFIG_UCLAMP_TASK */ +#if LISA_CONFIG_FEATURE_LISA__EVENT__SCHED_CPU_CAPACITY #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) && (defined(CONFIG_ARM64) || defined(CONFIG_ARM)) TRACE_EVENT(lisa__sched_cpu_capacity, @@ -331,8 +332,9 @@ TRACE_EVENT(lisa__sched_cpu_capacity, __entry->cpu, __entry->capacity, __entry->capacity_orig, __entry->capacity_curr) ); #endif +#endif // LISA_CONFIG_FEATURE_LISA__EVENT__SCHED_CPU_CAPACITY - +#if LISA_CONFIG_FEATURE_LISA__EVENT__PIXEL6_EMETER #define PIXEL6_EMETER_CHAN_NAME_MAX_SIZE 64 TRACE_EVENT(lisa__pixel6_emeter, @@ -359,6 +361,8 @@ TRACE_EVENT(lisa__pixel6_emeter, __entry->ts, __entry->device, __entry->chan, __entry->chan_name, __entry->value) ); +#endif // LISA_CONFIG_FEATURE_LISA__EVENT__PIXEL6_EMETER + #endif /* _FTRACE_EVENTS_H */ /* This part must be outside protection */ diff --git a/lisa/_assets/kmodules/lisa/main.h b/lisa/_assets/kmodules/lisa/main.h index e3691166d..a36307e10 100644 --- a/lisa/_assets/kmodules/lisa/main.h +++ b/lisa/_assets/kmodules/lisa/main.h @@ -4,6 +4,9 @@ #include +// Generated by the Makefile +#include "config.h" + #undef pr_fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/lisa/_assets/kmodules/lisa/pixel6.c b/lisa/_assets/kmodules/lisa/pixel6.c index 142482b3f..1e5eb34c5 100644 --- a/lisa/_assets/kmodules/lisa/pixel6.c +++ b/lisa/_assets/kmodules/lisa/pixel6.c @@ -21,6 +21,7 @@ #define POWER_METER_SAMPLE_FILE_1 "/sys/bus/iio/devices/iio:device1/energy_value" #define POWER_METER_RATE_FILE_1 "/sys/bus/iio/devices/iio:device1/sampling_rate" +#if LISA_CONFIG_FEATURE_LISA__EVENT__PIXEL6_EMETER static PARSE_RESULT(int) parse_content(parse_buffer *); typedef struct sample { @@ -251,3 +252,4 @@ SEQUENCE(int, parse_content, ({ /* Parse all the following sample lines */ PARSE(parse_all_samples, 0); })) +#endif // LISA_CONFIG_FEATURE_LISA__EVENT__PIXEL6_EMETER diff --git a/lisa/_assets/kmodules/lisa/tp.c b/lisa/_assets/kmodules/lisa/tp.c index c11d82b15..3c2937e9b 100644 --- a/lisa/_assets/kmodules/lisa/tp.c +++ b/lisa/_assets/kmodules/lisa/tp.c @@ -149,6 +149,7 @@ static void sched_util_est_se_probe(struct feature *feature, struct sched_entity DEFINE_TP_EVENT_FEATURE(lisa__sched_util_est_se, sched_util_est_se_tp, sched_util_est_se_probe); #endif +#if LISA_CONFIG_FEATURE_LISA__EVENT__SCHED_CPU_CAPACITY #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) && (defined(CONFIG_ARM64) || defined(CONFIG_ARM)) static void sched_cpu_capacity_probe(struct feature *feature, struct rq *rq) { @@ -156,6 +157,7 @@ static void sched_cpu_capacity_probe(struct feature *feature, struct rq *rq) } DEFINE_TP_EVENT_FEATURE(lisa__sched_cpu_capacity, sched_cpu_capacity_tp, sched_cpu_capacity_probe); #endif +#endif // LISA_CONFIG_FEATURE_LISA__EVENT__SCHED_CPU_CAPACITY static int init_tp(struct feature *_) { diff --git a/lisa/_kmod.py b/lisa/_kmod.py index 90f01172e..580619e51 100644 --- a/lisa/_kmod.py +++ b/lisa/_kmod.py @@ -2131,4 +2131,36 @@ class LISAFtraceDynamicKmod(FtraceDynamicKmod): def _event_features(cls, events): return set(f'event__{event}' for event in events) + @property + @memoized + def _feature_macros(self): + """ + Ftrace events possibly defined in that module. + + Note that this is based on crude source code analysis so it's expected + to be a superset of the actually defined events. + """ + find_macro = re.compile(rb'\bLISA_CONFIG_(FEATURE_[a-zA-Z0-9_].*?)\b') + def find_macros(code): + return map(bytes.decode, find_macro.findall(code)) + + return sorted({ + macro + for code in self.src.code_files.values() + for macro in find_macros(code) + }) + + + def _compile(self): + macros = self._feature_macros + make_vars = { + 'LISA_KMOD_CONFIG': json.dumps({ + **{ + macro: 1 + for macro in macros + }, + }) + } + return super()._compile(make_vars=make_vars) + # vim :set tabstop=4 shiftwidth=4 expandtab textwidth=80 -- GitLab