Skip to content

kmodule: insert independent modules in parallel (Fixes #3424)#3429

Merged
andrewsun2898 merged 2 commits into
u-root:mainfrom
khazhyk:kmod-parallel
Aug 21, 2025
Merged

kmodule: insert independent modules in parallel (Fixes #3424)#3429
andrewsun2898 merged 2 commits into
u-root:mainfrom
khazhyk:kmod-parallel

Conversation

@khazhyk

@khazhyk khazhyk commented Aug 6, 2025

Copy link
Copy Markdown
Contributor

This can be used to speed up boot if there's some modules that take a long time (e.g. probing hardware, etc.).

Probe() et. al. are concurrent unsafe since they create independent depMaps, and may in turn end up calling loadModule for the same module at once. This is wasteful since we'll load the images multiple times, and the init module syscall should return EEXIST if we actually try to load the same module twice.

This PR adds a new call: ParallelProbeOptions - that calls a new concurrent-safe implementation to load modules in parallel.

I would like to expose a concurrent safe API to allow for several goroutines that concurrently load then follow up with additional configuration that depends on those modules.

My first thought for what that could look like would just be promote depMap -> ModuleLoader and export the current parallelProbe().

This PR passes go test, though admittedly I haven't yet figured out the setup for end to end testing... I've tested a similar change end-to-end on our internal build system and the concept works.

@codecov

codecov Bot commented Aug 6, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.53846% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.18%. Comparing base (b6c6143) to head (ccdb126).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3429      +/-   ##
==========================================
- Coverage   59.40%   59.18%   -0.23%     
==========================================
  Files         637      633       -4     
  Lines       54089    54079      -10     
==========================================
- Hits        32134    32009     -125     
- Misses      21955    22070     +115     
Flag Coverage Δ
.-amd64 88.88% <ø> (ø)
cmds/...-amd64 49.12% <ø> (+<0.01%) ⬆️
integration/generic-tests/...-amd64 30.14% <0.00%> (-0.03%) ⬇️
integration/generic-tests/...-arm ?
integration/generic-tests/...-arm64 29.39% <0.00%> (-0.03%) ⬇️
integration/gotests/...-amd64 59.85% <61.53%> (-0.16%) ⬇️
integration/gotests/...-arm ?
integration/gotests/...-arm64 ?
pkg/...-amd64 57.64% <61.53%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
everything 64.06% <61.53%> (-0.27%) ⬇️
cmds/exp 31.08% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rminnich rminnich requested review from binjip978 and leongross August 7, 2025 02:52

@rminnich rminnich left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like something we need to have.
module loading is used at scale in several places; we'll need to be certain that your changes are harmless or not used in existing code paths. You seem to have gotten a long way there.

I am thinking that if you are updating this package, the VM tests will exercise the code. WDYT?

Comment thread pkg/kmodule/kmodule_linux.go Outdated
Comment thread pkg/kmodule/kmodule_linux.go
Comment thread pkg/kmodule/kmodule_linux.go Outdated
Comment thread pkg/kmodule/kmodule_linux.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces parallel kernel module loading capabilities to speed up boot times by loading independent modules concurrently. The change addresses concurrency safety issues in the existing sequential module loading approach.

  • Adds a new ParallelProbeOptions function that loads multiple modules concurrently using goroutines
  • Introduces thread-safe module loading with sync.Once to prevent duplicate loads
  • Refactors existing ProbeOptions to use the new parallel loading infrastructure

Comment thread pkg/kmodule/kmodule_linux.go Outdated
Comment thread pkg/kmodule/kmodule_linux.go Outdated
Comment thread pkg/kmodule/kmodule_linux.go Outdated
@khazhyk

khazhyk commented Aug 8, 2025

Copy link
Copy Markdown
Contributor Author

This seems like something we need to have. module loading is used at scale in several places; we'll need to be certain that your changes are harmless or not used in existing code paths. You seem to have gotten a long way there.

I am thinking that if you are updating this package, the VM tests will exercise the code. WDYT?

Which VM tests are you referring to? I took a look at runvmtest, but at least the default image seems nonmodular, or at the least doesn't bring lib/modules into the image.

@khazhyk khazhyk force-pushed the kmod-parallel branch 2 times, most recently from 2e3f430 to ebd737c Compare August 8, 2025 17:23
@khazhyk

khazhyk commented Aug 8, 2025

Copy link
Copy Markdown
Contributor Author

I would like to expose a concurrent safe API to allow for several goroutines that concurrently load then follow up with additional configuration that depends on those modules.

My first thought for what that could look like would just be promote depMap -> ModuleLoader and export the current parallelProbe().

Took a crack at this, which also allows for simplifying the interface by removing ParallelProbeOptions - we're just left with Prober.Probe & the backwards compatible Probe[Options].

@khazhyk khazhyk changed the title [rfc] kmodule: insert independent modules in parallel (Fixes #3424) kmodule: insert independent modules in parallel (Fixes #3424) Aug 11, 2025

@leongross leongross left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm.

@khazhyk

khazhyk commented Aug 18, 2025

Copy link
Copy Markdown
Contributor Author

Not super familiar with the review process here - is there some release window this waiting for, some more LGTMs, or does this PR look good-to-go?

@khazhyk

khazhyk commented Aug 20, 2025

Copy link
Copy Markdown
Contributor Author

A related discussion to this PR is

  • if we say module loading is parallelized, for those modules with dependencies where we want to specify parameters, you can achieve this by just calling in the right order, and blocking where needed, e.g.:
loader := kmodule.NewProber({})
go loadModChain() {
  loader.Probe("driver-common", "opt=b")
  loader.Probe("driver-main", "var=c")
}()

Which involves knowing (and encoding) these dependencies beforehand - which isn't a significant burden, but is a potential footgun. e.g. if you instead write the below, now you've introduced a race where driver-common will sometimes be loaded with no params

go loader.Probe("driver-common", "opt=b")
go loader.Probe("driver-main", "var=c")

One of my colleagues suggested we could instead have some stateful mechanism for desired module parameters, maybe like below to avoid needing to encode the dependencies and simplify the caller code.

for moduleInfo in moduleInfos {
  loader.PrepareProbe(moduleInfo.name, moduleInfo.params)
}

for moduleInfo in moduleInfos {
 go loader.FinishProbe(moduleInfo.name)
}

It does expand the API here a bit, though.

kernel modules are allowed to run thier initialization code in parallel,
and for modules that take a long time (e.g. probing hardware, etc.), we
can noticably reduce boot times by loading modules in parallel.

We want to avoid calling loadModule() for the same dep multiple times as
the kernel will return EEXIST for the duplicate module load (plus the
wasted cycles loading a duplicate image).

Adds a concurrent-safe parallelProbeDep() loading implementation, and
updates ProbeOptions() to load dependency modules in parallel.

Probe() and ProbeOptions() themselves remain concurrent-unsafe.

Fixes u-root#3424

Signed-off-by: Khazhismel Kumykov <khazhy@google.com>
Export new Prober type holding known module state (depMap) & probing
options, and new concurrent-safe Prober.Probe method for loading one
module and its dependencies.

Fixes u-root#3424

Signed-off-by: Khazhismel Kumykov <khazhy@google.com>
@andrewsun2898 andrewsun2898 merged commit 50c7c00 into u-root:main Aug 21, 2025
30 of 37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants