Skip to content

Port FunctionGemma's eager facade to androidNativeArm32 - #319

Merged
michalharakal merged 1 commit into
developfrom
feature/functiongemma-androidnative-eager
Aug 30, 2026
Merged

michalharakal merged 1 commit into
developfrom
feature/functiongemma-androidnative-eager

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Summary

  • Adds NativeFunctionGemma (llm-runtime:kgemma, androidNativeArm32Main) — same contract as the existing JVM FunctionGemma.fromGguf(path).call(text), same gemmaNetwork() DSL / DirectCpuExecutionContext / chat template / tool-call parser. Only the file-access layer differs: createRandomAccessSource + SystemFileSystem/kotlinx-io instead of JvmRandomAccessSource/java.io.File.
  • Adds a real CLI entry point in its own package (cli.android, not cli) so it doesn't collide with the existing nativeMain stub shared by the linux/macos targets (that one stays a stub, unchanged — this is additive).
  • llm-inference:gemma and llm-runtime:gemma-iree needed androidNativeArm32 added — neither had it at all (only llm-inference:functiongemma's host-only export tooling is not pulled in here; that's compile-leg, out of scope for an on-device eager binary).
  • Depends on Add androidNativeArm32 target support (random-access I/O + eager backend) SKaiNET#990 (base SKaiNET needed the same target added through its own dependency chain first — -PuseLocalSkainet=true against that branch to build this one until it's merged/released).

Verified on real hardware

Linked a genuine ELF 32-bit ARM EABI5 executable, pushed it + a real 260 MB FunctionGemma-270M checkpoint to the actual device (no Docker, no IREE, no host involvement at runtime beyond adb push/shell), ran it standalone:

text: <tool_0>(state="on")<end>
call: set_lights({state=on})

Correct. Full writeup incl. a follow-up perf investigation (root-caused why it takes ~35 min: DIRECT mode's inherent cost + a separate, real bug in OPTIMIZED mode's graph tracing for this model — Node 'n1_mulScalar' has 0 outputs but index 0 was requested, reproduces on JVM/x64, llm-core, not filed/fixed in this PR): https://github.com/... (SKaiNET-functiongemma's docs/DEVICE-BRINGUP.md, private repo).

Test plan

  • :llm-runtime:kgemma:compileKotlinAndroidNativeArm32 — compiles clean
  • :llm-runtime:kgemma:linkReleaseExecutableAndroidNativeArm32 — links a real binary
  • Every existing target of every touched module (llm-inference:gemma, llm-runtime:gemma-iree, llm-runtime:kgemma) still compiles — no regressions
  • Ran on real hardware (see above) — correct output

Ports FunctionGemma.kt's eager facade (fromGguf().call()) to a target
that didn't exist before: androidNativeArm32. Same gemmaNetwork() DSL,
DirectCpuExecutionContext, chat template, and tool-call parser as every
other path — only the file-access layer differs (createRandomAccessSource
+ SystemFileSystem/kotlinx-io instead of JvmRandomAccessSource/java.io).

Needed androidNativeArm32 added to llm-inference:gemma and
llm-runtime:gemma-iree first (both had it missing entirely). CLI entry
point lives in its own package (cli.android, not cli) so it doesn't
collide with the existing nativeMain stub shared by linux/macos.

Board-verified on the actual device (SKaiNET-functiongemma's
docs/DEVICE-BRINGUP.md): linked ELF 32-bit ARM EABI5 executable, real
260MB checkpoint, correct output (set_lights), no host involvement at
runtime. Eager throughput is a known, root-caused separate gap (DIRECT
mode cost + a graph-tracing bug in OPTIMIZED mode) — not blocking here.
@michalharakal
michalharakal merged commit 784a362 into develop Aug 30, 2026
0 of 2 checks passed
@michalharakal
michalharakal deleted the feature/functiongemma-androidnative-eager branch August 30, 2026 06:53
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