Skip to content

feat(kernel): JVM ServiceLoader auto-discovery for KernelProvider#559

Merged
michalharakal merged 1 commit intodevelopfrom
feature/jvm-kernel-serviceloader
Apr 28, 2026
Merged

feat(kernel): JVM ServiceLoader auto-discovery for KernelProvider#559
michalharakal merged 1 commit intodevelopfrom
feature/jvm-kernel-serviceloader

Conversation

@michalharakal
Copy link
Copy Markdown
Contributor

Summary

  • Adds KernelServiceLoader (skainet-backend-api/jvmMain) — a JVM-only object exposing discover() and installAll() that scan META-INF/services/sk.ainet.backend.api.kernel.KernelProvider and register every declared provider into KernelRegistry.
  • Ships JVM service factories ScalarKernelProviderFactory / PanamaVectorKernelProviderFactory in the cpu backend, plus the META-INF service file listing both. The factories delegate to the existing singletons via KernelProvider by <singleton>ServiceLoader needs a public no-arg constructor that Kotlin object doesn't expose, so the wrappers are the standard workaround.
  • Updates the KernelRegistry kdoc 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

ServiceLoader doesn't exist on Kotlin/Native, JS, or Wasm targets. Those platforms continue to call KernelRegistry.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; new KernelServiceLoaderTest adds 4 (discover finds both, installAll registers in priority order, bestAvailable picks Panama on test JDK, idempotent reinstall).
  • No regressions in existing kernel tests (KernelRegistryTest, ScalarMatmulKernelTest, PanamaVectorMatmulKernelTest, PanamaVectorKernelProviderTest) — all green.

Caller-facing usage

Typical JVM startup wiring becomes:

KernelServiceLoader.installAll()
val kernel = KernelRegistry.bestAvailable()?.matmulFp32()
    ?: error("no FP32 matmul kernel available")

Follow-ups (M5)

  • Route DefaultCpuOpsJvm.matmul through KernelRegistry — calling KernelServiceLoader.installAll() once at backend init and looking up bestAvailable().matmulFp32() instead of calling JvmVectorKernels.matmulFloat* directly. Caveat from bench(kernel): KernelMatmulBench — scalar vs Panama (M5 evidence) #558: until PanamaVectorMatmulKernel gets cache-blocking, routing will show a 14–52% regression at 512²/1024² vs the existing matmulFloatBlocked path. Recommended order: port tiling first, then route.
  • Native kernel provider (priority 100, FFM-based).
  • Quant kernel SPIs (Q4_K / Q6_K / Q8_0 — JVM-only because of MemorySegment).

🤖 Generated with Claude Code

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>
@michalharakal michalharakal marked this pull request as ready for review April 28, 2026 14:11
@michalharakal michalharakal merged commit b3b0c05 into develop Apr 28, 2026
6 checks passed
@michalharakal michalharakal deleted the feature/jvm-kernel-serviceloader branch April 28, 2026 20:57
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.

1 participant