Skip to content

Commit e1e9eaf

Browse files
kmod: eliminate duplication in calls to modinfo
The original guard when building the new todo is: ``` todo += [m for m in depinfo.modules if m not in mods and m in nametofile] ``` `mods` only accumulates modules from previous iterations of the outer while loop. Within a single iteration, modules in the current batch are added to mods one at a time as `moddep.items()` is iterated. This means two distinct failure modes: 1. Cross-dependency within a batch: if modules A and B are both in the current todo and both depend on X, X passes the m not in mods check when processing A's deps and again when processing B's (since X hasn't been added to mods yet). X ends up in todo twice. 2. Intra-batch back-edge: if A depends on B and both are already in the current todo/moddep, B still passes m not in mods when processing A's dep list, queuing B for a redundant second modinfo call in the next iteration. Both boil down to the same root cause: the check doesn't account for modules currently being processed. The fix addresses both issues: 1. `m not in moddep.keys()` prevents modules from the current batch being re-queued into the next iteration's `todo`. 2. Turning`todo` into a set prevents a module from appearing *multiple times* in the same next `todo`, when two modules in the current batch share a dependency Because these duplicates frequently occur in practice, eliminating them provides an incremental speedup on top of the original optimization made in GH4092/GH4017. Co-Authored-By: Jörg Behrmann <behrmann@physik.fu-berlin.de>
1 parent df68b27 commit e1e9eaf

1 file changed

Lines changed: 7 additions & 7 deletions

File tree

mkosi/kmod.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ def resolve_module_dependencies(
292292
with chdir(context.root):
293293
nametofile = {module_path_to_name(m): m for m in all_modules(modulesd)}
294294

295-
todo = [*builtin, *modules]
296-
mods = set()
295+
todo = {*builtin, *modules}
296+
mods: set[str] = set()
297297
firmware = set()
298298

299299
while todo:
@@ -304,20 +304,20 @@ def resolve_module_dependencies(
304304
# build a map that maps the module name to both its module dependencies and its firmware
305305
# dependencies. Because there's more kernel modules than the max number of accepted CLI
306306
# arguments, we split the modules list up into chunks if needed.
307-
for i in range(0, len(todo), 8500):
308-
chunk = todo[i : i + 8500]
307+
ittodo = iter(todo)
308+
while chunk := tuple(itertools.islice(ittodo, 8500)):
309309
moddep |= modinfo(context, kver, chunk)
310310

311-
todo = []
311+
todo = set()
312+
mods |= moddep.keys()
312313

313314
for name, depinfo in moddep.items():
314315
for d in depinfo.modules:
315316
if d not in nametofile and d not in builtin:
316317
logging.warning(f"{d} is a dependency of {name} but is not installed, ignoring ")
317318

318-
mods.add(name)
319319
firmware.update(depinfo.firmware)
320-
todo += [m for m in depinfo.modules if m not in mods and m in nametofile]
320+
todo.update(m for m in depinfo.modules if m not in mods and m in nametofile)
321321

322322
return set(nametofile[m] for m in mods if m in nametofile), set(firmware)
323323

0 commit comments

Comments
 (0)