From f9e7527e0357236746396f531f5eef583dde80a6 Mon Sep 17 00:00:00 2001 From: DaanDeMeyer Date: Thu, 25 Dec 2025 20:48:47 +0100 Subject: [PATCH] kmod: Stop retrieving dependency info of all modules Instead of running modinfo once to retrieve the dependency information of all modules, let's only retrieve the dependency information of the modules that are to be included in the image and their transitive dependencies. This means we have to run modinfo multiple times, but with far fewer modules than before. This ends up being faster than retrieving the dependency information of all modules, especially after the optimization from e276dac87a530efac4376a5059b980f2d43460f5. For the mkosi default image build on Arch Linux this reduces the time for calculating the required kernel modules and firmware on my laptop from 5s to 0.5s. Co-Authored-By: Laurence Kiln <246209442+LaurenceKiln@users.noreply.github.com> --- mkosi/kmod.py | 53 ++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/mkosi/kmod.py b/mkosi/kmod.py index 925194bfe..875fc03d0 100644 --- a/mkosi/kmod.py +++ b/mkosi/kmod.py @@ -209,7 +209,7 @@ class ModuleDependencyInfo: def modinfo(context: Context, kver: str, modules: Sequence[str]) -> dict[str, ModuleDependencyInfo]: - cmdline = ["modinfo", "--set-version", kver, "--null"] + cmdline = ["modinfo", "--modname", "--set-version", kver, "--null"] if context.config.output_format.is_extension_image() and not context.config.overlay: cmdline += ["--basedir", "/buildroot"] @@ -272,45 +272,42 @@ def resolve_module_dependencies( root directory. """ modulesd = Path("usr/lib/modules") / kver + if (p := context.root / modulesd / "modules.builtin").exists(): - builtin = set(module_path_to_name(Path(m)) for m in p.read_text().splitlines()) + builtin = {module_path_to_name(Path(m)) for m in p.read_text().splitlines()} else: builtin = set() + with chdir(context.root): allmodules = set(modulesd.rglob("*.ko*")) nametofile = {module_path_to_name(m): m for m in allmodules} - moddep: dict[str, ModuleDependencyInfo] = {} - - # We could run modinfo once for each module but that's slow. Luckily we can pass multiple modules to - # modinfo and it'll process them all in a single go. We get the modinfo for all modules to build - # a map that maps the module name to both its module dependencies and its firmware dependencies. - # Because there's more kernel modules than the max number of accepted CLI arguments, we split the - # modules list up into chunks if needed. - for i in range(0, len(nametofile.keys()), 8500): - chunk = list(nametofile.keys())[i : i + 8500] - moddep |= modinfo(context, kver, chunk) - todo = [*builtin, *modules] mods = set() firmware = set() while todo: - m = todo.pop() - if m in mods: - continue - - depinfo = moddep.get(m) - if not depinfo: - continue - - for d in depinfo.modules: - if d not in nametofile and d not in builtin: - logging.warning(f"{d} is a dependency of {m} but is not installed, ignoring ") - - mods.add(m) - todo += depinfo.modules - firmware.update(depinfo.firmware) + moddep: dict[str, ModuleDependencyInfo] = {} + + # We could run modinfo once for each module but that's slow. Luckily we can pass multiple modules + # to modinfo and it'll process them all in a single go. We get the modinfo for all modules to + # build a map that maps the module name to both its module dependencies and its firmware + # dependencies. Because there's more kernel modules than the max number of accepted CLI + # arguments, we split the modules list up into chunks if needed. + for i in range(0, len(todo), 8500): + chunk = todo[i : i + 8500] + moddep |= modinfo(context, kver, chunk) + + todo = [] + + for name, depinfo in moddep.items(): + for d in depinfo.modules: + if d not in nametofile and d not in builtin: + logging.warning(f"{d} is a dependency of {name} but is not installed, ignoring ") + + mods.add(name) + firmware.update(depinfo.firmware) + todo += [m for m in depinfo.modules if m not in mods] return set(nametofile[m] for m in mods if m in nametofile), set(firmware) -- 2.47.3