feat(kernel): JVM ServiceLoader auto-discovery for KernelProvider#559
Merged
michalharakal merged 1 commit intodevelopfrom Apr 28, 2026
Merged
feat(kernel): JVM ServiceLoader auto-discovery for KernelProvider#559michalharakal merged 1 commit intodevelopfrom
michalharakal merged 1 commit intodevelopfrom
Conversation
Adds `KernelServiceLoader` (skainet-backend-api / jvmMain) that scans `META-INF/services/sk.ainet.backend.api.kernel.KernelProvider` on the classpath, instantiates each declared provider, and registers it into `KernelRegistry`. Now justified by a second concrete provider (Panama Vector, PR #557) — single-provider auto-discovery would have been ceremony for nothing. The cpu backend ships factory wrappers (`ScalarKernelProviderFactory`, `PanamaVectorKernelProviderFactory`) that delegate to the existing singletons via `KernelProvider by <singleton>`, plus the META-INF service file listing both. ServiceLoader needs a public no-arg constructor; Kotlin `object` doesn't expose one, so the wrappers are the standard workaround. JVM-only on purpose: ServiceLoader doesn't exist on Native / JS / Wasm targets. Those continue to use `KernelRegistry.register(...)` directly. Manual registration is still supported on JVM too — useful for tests and for callers that want to pin a specific provider. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
KernelServiceLoader(skainet-backend-api/jvmMain) — a JVM-only object exposingdiscover()andinstallAll()that scanMETA-INF/services/sk.ainet.backend.api.kernel.KernelProviderand register every declared provider intoKernelRegistry.ScalarKernelProviderFactory/PanamaVectorKernelProviderFactoryin the cpu backend, plus the META-INF service file listing both. The factories delegate to the existing singletons viaKernelProvider by <singleton>—ServiceLoaderneeds a public no-arg constructor that Kotlinobjectdoesn't expose, so the wrappers are the standard workaround.KernelRegistrykdoc to document the new discovery path.Why now
The previous SPI doc deferred this until a second concrete provider existed. With Panama landing in #557, that condition is met — single-provider auto-discovery would have been ceremony for nothing.
Why JVM-only
ServiceLoaderdoesn't exist on Kotlin/Native, JS, or Wasm targets. Those platforms continue to callKernelRegistry.register(...)directly. Manual registration is still supported on JVM too — useful for tests, and for callers that want to pin a specific provider.Test plan
./gradlew :skainet-backends:skainet-backend-cpu:jvmTest— all 213 tests pass; newKernelServiceLoaderTestadds 4 (discover finds both, installAll registers in priority order, bestAvailable picks Panama on test JDK, idempotent reinstall).KernelRegistryTest,ScalarMatmulKernelTest,PanamaVectorMatmulKernelTest,PanamaVectorKernelProviderTest) — all green.Caller-facing usage
Typical JVM startup wiring becomes:
Follow-ups (M5)
DefaultCpuOpsJvm.matmulthroughKernelRegistry— callingKernelServiceLoader.installAll()once at backend init and looking upbestAvailable().matmulFp32()instead of callingJvmVectorKernels.matmulFloat*directly. Caveat from bench(kernel): KernelMatmulBench — scalar vs Panama (M5 evidence) #558: untilPanamaVectorMatmulKernelgets cache-blocking, routing will show a 14–52% regression at 512²/1024² vs the existingmatmulFloatBlockedpath. Recommended order: port tiling first, then route.MemorySegment).🤖 Generated with Claude Code