Skip to content

Releases: john-rocky/edge-llm-bench

LiteRT-LM v0.18.0 Android arm64 binaries

Choose a tag to compare

Prebuilt litert_lm_main, litert_lm_advanced_main and the ML Drift GPU .so set for Android arm64, built from google-ai-edge/LiteRT-LM v0.18.0.

Upstream ships no Android binary for v0.18.0 (its assets are two xcframeworks and a macOS CLI). Without this archive, the Android lane needs a bazel + NDK source build.

How to use it:

  • Attached phone: untar into android/bin/v0.18.0/ and push per android/README.md.
  • Lab phone over Device Run: untar anywhere and point BENCH_ANDROID_BIN_DIR at the parent directory. See the README section "Run the Android cells on a Developer Device Platform phone".

SHA256SUMS inside the archive covers all nine files. The same hashes are pinned in android/engine-pins.json, and every result row stamps the sha256 observed on the device.

Built on 2026-10-07 with android/scripts/build_litert_lm_main.sh (bazelisk, Android NDK, macOS host, --config=android_arm64 --enable_platform_specific_config) at the v0.18.0 tag (commit b2f686e). License: Apache-2.0 (LiteRT-LM); libwebgpu_dawn.so is Dawn, BSD-3-Clause.

Repro: enable_profiling = true changes the LiteRT 2.2.0 GPU accelerator's numbers (Adreno OpenCL, 2026-09-29)

Choose a tag to compare

enable_profiling = true changes the GPU accelerator's numbers — LiteRT 2.2.0, Galaxy S26 (Adreno 840, OpenCL), 2026-09-29

profiling_repro.cc (112 lines, LiteRT CompiledModel C API) runs one graph once through the CPU accelerator (the reference, always compiled with enable_profiling = false) and then four times through a second CompiledModel, printing max |output − reference| after every invocation. MODE selects that second model:

  • off: GPU accelerator, runtime_options_string = enable_profiling = false
  • flag: GPU accelerator, enable_profiling = true, no profiler API call
  • start / startstop / stopfirst: GPU accelerator, enable_profiling = true plus LiteRtStartProfiler / LiteRtStopProfiler around invocation 1, or a stop right after compile
  • cpuflag: the CPU accelerator with enable_profiling = true (control: does the option move the CPU path?)

gpu_options is precision = 2 (FP32) in every GPU mode; nothing else is set on the options.

Build (NDK r29 aarch64-linux-android28-clang++, headers litert/c/ from the LiteRT v2.2.0 tag, libLiteRt.so from the LiteRT 2.2.0 Android AAR jni/arm64-v8a/; build.sh is the same line with the NDK, header and library directories taken from ANDROID_NDK_HOME, LITERT_INCLUDE and LITERT_LIB — against the same headers and library it reproduces the binary I ran, sha256 c27b0553…):

aarch64-linux-android28-clang++ -std=c++17 -O2 -fPIE -pie -static-libstdc++ -I<litert v2.2.0 headers> profiling_repro.cc -L<dir with libLiteRt.so> -lLiteRt -llog -ldl -Wl,-rpath,'$ORIGIN' -o profiling_repro

Run — <dir> on the phone holds profiling_repro, libLiteRt.so (found through LD_LIBRARY_PATH), libLiteRtClGlAccelerator.so (the runtime loads it from <dir>, which the binary passes as kLiteRtEnvOptionTagRuntimeLibraryDir), the graph and its input:

adb shell "cd <dir> && LD_LIBRARY_PATH=<dir> ./profiling_repro affine.tflite input.bin <dir> off 4"
adb shell "cd <dir> && LD_LIBRARY_PATH=<dir> ./profiling_repro affine.tflite input.bin <dir> flag 4"

Results: max |output − CPU reference| after each of the 4 invocations (the same number in all four invocations and in both processes of every cell):

graph (ops, input → output) off flag start startstop stopfirst cpuflag
affine.tflite (MUL, ADD, RESHAPE; [1,512,1] → [1,512]; x*1.25+0.125) 0 4.13306367 (128 of 512 elements > 1e-4) 4.13306367 4.13306367 4.13306367 0
square.tflite (MUL, RESHAPE; [1,512,1] → [1,512]; x*x) 0 107.499513 (128 of 512) 107.499513 107.499513 107.499513 0
c512_std_2d_fp32.tflite (SUM, MUL, SUB, SQRT, ADD, DIV, CEIL, RESHAPE; [1,512,1] → [1,1]) 0 0.242640674 (1 of 1) 0.242640674 0.242640674 0.242640674 0
bare_fc_rank3.tflite (FULLY_CONNECTED; [1,85,32] → [85,16]) 0 0.985351562 (1344 of 1360) — — — 0
bare_fc_rank2.tflite (FULLY_CONNECTED; [85,32] → [85,16]) 0 0 — — — 0
isolated_add_input_rank2.tflite (ADD runtime [85,16] + const [1,85,16] → [1,85,16]) 0.992675781 (1344 of 1360) 0.992675781 — — — 0
isolated_add_input_rank3.tflite (ADD runtime [1,85,16] + const [1,85,16] → [1,85,16]) 0 0 — — — 0

gpu fully_accelerated=1 in every GPU process; the delegate log is Replacing N out of N node(s) with delegate (LITERT_CL) in both settings. In affine and square the 128 wrong elements are the indices with i mod 16 < 4 (affine.gpu_profiling_on.f32 and square.gpu_profiling_on.f32: the GPU output of one profiling-on process of each graph, dumped by my diagnostic runner — 512 float32 each — against affine.cpu.f32 / square.cpu.f32). The isolated_add_input_rank2 row is wrong with the option off as well: that is google-ai-edge/LiteRT#10231 (rank-2 runtime operand against a rank-3 constant), a separate thing, kept here because it is the graph family the finding came from.

Files: profiling_repro.cc, build.sh, the seven graphs (litert-torch 0.9.4 exports), input.bin (512 float32 for the first three graphs), <graph>.input.f32 (inputs of the four control graphs), <graph>.cpu.f32 (LiteRT CPU output of every graph, ai_edge_litert 2.2.0 interpreter), affine.gpu_profiling_on.f32 / square.gpu_profiling_on.f32 (GPU outputs with the option on), logs/ (stdout + stderr of one off, flag, cpuflag process per graph, startstop for the first three, and the profiler summary of a profiling-on run of affine through the original runner), SHA256SUMS.

Device: Galaxy S26 SM-S942Q, SM8850 / Adreno 840, Android 16 (security patch 2026-06-05), GL driver V@0842.19.8 (03/26/26), ro.gfx.driver.0 = com.samsung.gamedriver.sm8850. The adb serial and the home directory of the build machine are redacted in these copies (adb -s <serial> in the logs; variables in build.sh). Runtime: libLiteRt.so sha256 97355a36… and libLiteRtClGlAccelerator.so 7c63d606… from com.google.ai.edge.litert:litert:2.2.0 (AAR sha256 624518d7…).

Repro: ADD(runtime [85,16], constant [1,85,16]) on the LiteRT GPU accelerator (Adreno OpenCL) — LiteRT#10231 at a second shape (2026-09-29)

Choose a tag to compare

ADD(runtime [85,16], constant [1,85,16]) on the LiteRT GPU accelerator (Adreno OpenCL) — google-ai-edge/LiteRT#10231 at a second shape

Three one-ADD graphs (litert-torch 0.9.4 export; the RESHAPE graph was made post-export because the converter folds an explicit reshape before the add away), run through LiteRT's own gpu_numerics_check_cl_gl on a Galaxy S26 (SM8850 / Adreno 840, Android 16, GL driver V@0842.19.8) on 2026-09-29. Tool built from LiteRT 0da36b31 for android_arm64 inside the LiteRT-LM 1dadd00c workspace; GPU accelerator = LiteRT-LM 1dadd00c prebuilt/android_arm64/libLiteRtGpuAccelerator.so (sha256 88e716f4…). Inputs = the tool's deterministic pattern (element i = (((i + 17·b) mod 41) − 20) × 0.05). Constant table = ((i mod 37) − 18) × 0.1, i = flat index in [1,85,16].

graph ADD operands precision max abs diff mean abs diff elements > 1e-4 (of 1360) cosine
add_rank2_input_const_rank3.tflite x [85,16] + const [1,85,16] fp32 2.0 0.725257 1312 (96.5 %) 0.742253
add_rank2_input_const_rank3.tflite same fp16 1.9998 0.725275 1345 (98.9 %) 0.742246
add_reshape3_const_rank3.tflite RESHAPE x → [1,85,16], then + const [1,85,16] fp32 0.0 0.0 0 1.000000
add_reshape3_const_rank3.tflite same fp16 0.0015626 0.000257474 869 (63.9 %) 1.000000
add_rank3_input_const_rank3.tflite x [1,85,16] + const [1,85,16] fp32 0.0 0.0 0 1.000000
add_rank3_input_const_rank3.tflite same fp16 0.0015626 0.000257474 869 (63.9 %) 1.000000

Three runs per cell, all identical. Every run logs Replacing 1 out of 1 (2 out of 2 for the RESHAPE graph) node(s) with delegate (LITERT_CL). The fp16 rows of the two passing graphs are fp16 rounding (≤ 0.0016).

In all 40 elements the tool prints for the rank-2 graph in fp32 (the first 20 mismatches and the 20 largest), the GPU value equals the first row of the runtime input plus the constant's own row: GPU[r,c] = x[0,c] + table[r,c], while the CPU value is x[r,c] + table[r,c]. The first row (elements 0–15) is exact; the first mismatch is element #16.

Run line (logs/run-<graph>-<precision>.log, one per graph and precision, first of the three runs):

adb -s <serial> shell "cd <dir> && LD_LIBRARY_PATH=<libdir> ./gpu_numerics_check_cl_gl --graph=<graph>.tflite --print_diff_stats --print_difference_distribution --fail_on_threshold=false [--use_fp16]"

SHA256SUMS lists the three graphs and the six logs. The adb serial is redacted in these log copies (adb -s <serial>).

Unrolled LSTM vs. LiteRT 2.2.0 GPU accelerator (Adreno OpenCL): compile-time SIGSEGV boundary

Choose a tag to compare

Seeded random-weight LSTM graphs (repro.py, litert-torch 0.9.3) that mark where CompiledModel creation with the LiteRT 2.2.0 GPU accelerator faults on a Galaxy S26 (Adreno, Android 16): unidirectional H=128 compiles at T=84 unrolled steps and faults at T=88; bidirectional compiles at T=48 and faults at T=96 — following the sequential step count, not operators, bytes or memory (12.9 MB RSS at the fault). Backtrace ends in /vendor/lib64/libCB.so cb_enqueue_nd_range_kernel via clEnqueueNDRangeKernel from libLiteRtClGlAccelerator.so. RESULTS.md has the 13-row table, the backtrace, the runner setup and sha256 of every file. Cut from the NER head of knowledgator/gliformer-large-v1 (litert-community/GLiFormer-Large-NER-LiteRT).

Repro: Metal GPU delegate ADD(runtime rank-2, constant rank-3) miscompute (2026-09-24)

Choose a tag to compare

Two-op graphs cut from the litert-community LFM2.5-VL-450M vision encoder (fp32 export, weights included) for the LiteRT issue on the Metal GPU delegate. fc_add_const_rank3.tflite: FULLY_CONNECTED -> ADD(runtime [1024,768], const [1,1024,768]) — CPU vs Metal cosine 0.818. prefix2-reshape3.tflite: the same with a RESHAPE to [1,1024,768] before the ADD — exact. prefix2-input.tflite: the constant as a second input — exact. repro_add.py runs one file on CPU and GPU through ai_edge_litert CompiledModel. Record: results/raw/2026-09-24-vl-response-v1-m4max-mac/NOTES.md finding 1, probes/metal-bisect/.

LiteRT-LM v0.17.0 Android arm64 binaries

Choose a tag to compare

Prebuilt litert_lm_main, litert_lm_advanced_main, and the ML Drift GPU .so set for Android arm64, built from google-ai-edge/LiteRT-LM v0.17.0. Upstream ships no Android binary (verified v0.14–v0.17: the v0.17.0 assets are two xcframeworks and a macOS CLI), so without this archive the Android lane needs a bazel + NDK source build.

Use: untar into android/bin/v0.17.0/ and push per android/README.md. SHA256SUMS is inside the archive; the same hashes are pinned in android/engine-pins.json, and every result row stamps the sha256 observed on-device.

Built 2026-09-14 with android/scripts/build_litert_lm_main.sh (bazelisk → bazel 7.6.1, NDK 29.0.13113456, macOS host — --config=android_arm64 --enable_platform_specific_config) at the v0.17.0 tag (commit 945edf3). License: Apache-2.0 (LiteRT-LM); libwebgpu_dawn.so is Dawn, BSD-3-Clause.

LiteRT-LM v0.16.0 Android arm64 binaries

Choose a tag to compare

Prebuilt litert_lm_main, litert_lm_advanced_main, and the ML Drift GPU .so set for Android arm64, built from google-ai-edge/LiteRT-LM v0.16.0. Upstream ships no Android binary (verified v0.14–v0.16), so without this archive the Android lane needs a bazel + NDK source build.

Use: untar into android/bin/v0.16.0/ and push per android/README.md. SHA256SUMS is inside the archive; the same hashes are pinned in environment.lock.json / android/engine-pins.json, and every result row stamps the sha256 observed on-device.

Built with android/scripts/build_litert_lm_main.sh (bazelisk, NDK r28b, macOS host — --enable_platform_specific_config, google-ai-edge/LiteRT-LM#3247). License: Apache-2.0 (LiteRT-LM); libwebgpu_dawn.so is Dawn, BSD-3-Clause.