Skip to content

Rebuild the Whisper Android AAR for 16 KB memory pages - #5688

Merged
shai-almog merged 10 commits into
masterfrom
fix/5682-whisper-16kb-page-alignment
Sep 3, 2026
Merged

shai-almog merged 10 commits into
masterfrom
fix/5682-whisper-16kb-page-alignment

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Fixes #5682.

The defect

Every 64-bit library in the checked-in cn1-ai-whisper-android.aar had PT_LOAD p_align 0x1000 -- libcn1aiwhisper.so, libc++_shared.so and libomp.so, for both arm64-v8a and x86_64. Google Play requires 0x4000 for every 64-bit shared library in an upload: API 35+ uploads since 2025-11-01, and Wear OS uploads containing native code from 2026-09-15.

Alignment is settled at link time. AGP aligns the ZIP entries and bundletool reports the outcome, but neither can move a segment inside a prebuilt .so, so an app could not repair it -- and the failure is silent, because the app builds and runs on every 4 KB device. Only Play review or a real 16 KB device says otherwise.

The fix

The AAR is rebuilt with NDK r28 (28.2.13676358). r28 is the first release that links this way by default and, more to the point, the first whose prebuilt libc++_shared.so and libomp.so are aligned -- those two are copied out of the NDK, so no flag set in this project could have fixed them on r26/r27.

CMakeLists.txt also passes -Wl,-z,max-page-size=16384 and -Wl,-z,common-page-size=16384, which covers libcn1aiwhisper.so for a standalone CMake run or an older NDK.

Verification

  • All six 64-bit libraries are now 0x4000; the six 32-bit ones are untouched.
  • The rebuild is equivalent, not merely aligned: identical AAR entry set, identical JNI exports on all four ABIs, identical DT_NEEDED, the same whisper.cpp commit (0874de3e), same recorded API level, ~2 KB size delta.
  • The packaged .cn1lib was checked too, not only the file in src/main/resources -- that is the artifact an app build actually consumes.
  • The CMake flags were proven independently: a probe under NDK r26 moves a library from 0x1000 to 0x4000, and the flags appear in the generated link command.
  • Both gates are non-vacuous: pointed at the pre-rebuild artifact, the script exits 1 and the test fails, naming all six libraries.

Two things worth flagging in review

minSdk 19 -> 21 is not a consequence of the NDK bump. The NDK's floor has been API 21 since r26, so every slice ever shipped here -- 32-bit included -- already carried API 21 in .note.android.ident while the manifest claimed 19. The old value was a claim the native code never honoured, and an API 19 install would have failed at System.loadLibrary. PlatformFeatureCatalog now raises a consuming app's android.min_sdk_version to match, so the manifest merge still succeeds for a default project.

The gate is 64-bit only, deliberately. 16 KB pages are a 64-bit feature, and NDK r28 itself ships 4 KB 32-bit libc++_shared.so/libomp.so -- a wider rule would be unsatisfiable. 32-bit slices are still listed under --verbose.

The whisper.cpp pin is now recorded in the README. Nothing in the tree derived it; it was only recoverable because the version and abbreviated hash survived as strings inside the shipped library.

Not in this PR

Issue #5682 also asks to check every shipped native dependency. Five CN1-pinned third-party artifacts are non-compliant as well:

Pin Broken ABIs Compliant version
com.microsoft.onnxruntime:onnxruntime-android:1.16.3 arm64-v8a, x86_64 1.22.0 (1.19.2 / 1.20.0 / 1.21.0 still bad)
org.tensorflow:tensorflow-lite:2.13.0 arm64-v8a, x86_64 none exists
com.google.ai.edge.litert:litert:1.0.1 x86_64 only 1.4.0
com.google.mlkit:barcode-scanning:17.2.0 arm64-v8a, x86_64 17.3.0
com.google.mlkit:face-detection:16.1.5 arm64-v8a, x86_64 16.1.7

Already compliant: ARCore 1.44.0, SQLCipher 4.17.0, language-id 17.0.6, smart-reply 17.0.4.

tensorflow-lite has no fix by version bump: 2.16.1 is the last real AAR and is still 4 KB, and 2.17.0 is a 1.4 KB stub because the artifact moved to com.google.ai.edge.litert. That one needs a migration.

Held back deliberately -- bumping five ML dependency pins is a different change with its own device-testing needs, and this issue is scoped to the whisper AAR. The audit covers direct pins only, not natives arriving transitively via play-services-*.

Local test plan

scripts/check-16k-page-alignment.py --verbose
cd maven && mvn -pl cn1-ai-whisper/common,platform-feature-catalog test

Both green. check-control-characters.py and check-copyright-headers.sh pass over the branch range.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-03T17:30:28.368142Z c3da2d4 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f9b06487b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
@shai-almog

shai-almog commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 151 screenshots: 151 matched.

Native Android coverage

  • 📊 Line coverage: 9.14% (9061/99176 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.91% (46674/523952), branch 3.50% (1739/49639), complexity 3.49% (1849/52940), method 5.37% (1496/27852), class 10.81% (403/3727)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 9.14% (9061/99176 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.91% (46674/523952), branch 3.50% (1739/49639), complexity 3.49% (1849/52940), method 5.37% (1496/27852), class 10.81% (403/3727)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 320ms / native 164ms = 1.9x speedup
SIMD float-mul (64K x300) java 275ms / native 144ms = 1.9x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 92.000 ms
Base64 CN1 decode 84.000 ms
Base64 native encode 316.000 ms
Base64 encode ratio (CN1/native) 0.291x (70.9% faster)
Base64 native decode 263.000 ms
Base64 decode ratio (CN1/native) 0.319x (68.1% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ✅ ByteCodeTranslator: 0 findings (no issues)
    • ✅ android: 0 findings (no issues)
    • ✅ build-hint-catalog: 0 findings (no issues)
    • ✅ build-hint-tools: 0 findings (no issues)
    • ✅ codenameone-maven-plugin: 0 findings (no issues)
    • ✅ core-unittests: 0 findings (no issues)
    • ✅ ios: 0 findings (no issues)
  • ✅ PMD: 0 findings (no issues) [Report archive]
  • ✅ Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

shai-almog added a commit that referenced this pull request Sep 3, 2026
Review finding on #5688: an unreadable `.so` payload was exempted rather
than reported, so a corrupted native library could be committed while the
check still exited 0.

Two ways through. A file named `.so` that is not an ELF at all returned
None and was dropped silently, counting toward nothing. And a *truncated*
64-bit library still begins with the ELF magic, so it fell out of the same
branch and was announced as "32-bit, not subject to 16 KB pages" -- the
exemption for an ABI the rule does not cover was reachable by corruption.
MIN_LIBRARIES_SCANNED did not help: the six valid Whisper slices satisfy
the floor on their own.

This is the rule already applied to archives the gate cannot open, which
the ELF parse itself was not holding to: an entry nobody could read is an
entry whose alignment nobody checked, and that must not come out reading
the same as one checked and found compliant.

So `read_load_alignments` now raises for anything that does not parse and
returns the ELF class alongside the alignments. A 32-bit library is exempt
only once it has been parsed and shown to really be a 32-bit ELF, which
means the 32-bit program header layout had to be read too -- the two
layouts differ in field order, not just in width.

It also rejects a PT_LOAD segment that ends past the end of the file.
Program headers sit near the front, so a library truncated mid-file parses
happily and reports correct alignment for contents that are not there.

The "rebuild with NDK r28" advice is now printed only when something was
actually misaligned; for a truncated artifact it pointed at the wrong fix.

The same hole existed in the Java check in AndroidWhisperAarProjectTest and
is closed the same way, with the entry name threaded in so a failure says
which library.

Verified against a probe AAR carrying a non-ELF `.so`, a 40-byte truncation,
a mid-file truncation, a valid 32-bit slice and a valid aligned 64-bit one:
the first three fail in both the script and the test, the last two behave as
before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: abc43040c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
@shai-almog

shai-almog commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 181 screenshots: 181 matched.
✅ JavaScript-port screenshot tests passed.

shai-almog added a commit that referenced this pull request Sep 3, 2026
Review finding on #5688: the whole-tree scan walked past every tracked
`.cn1lib`, so a misaligned native library shipped through Codename One's own
library format was never inspected and the gate still exited 0.
`tests/core/lib/QRScanner.cn1lib` reaches real `.so` files through
`nativeand.zip` and then `ZBarScannerLibrary.aar`, three archives deep, and
none of them were being read.

The reported fix is to add `.cn1lib` to the extension list. The extension
list is the defect, though: it is a curated allow-list, it was already wrong
about the one format this project defines itself, and adding an entry leaves
the next container -- `.kar`, `.srcjar`, `.apks`, whatever a future packaging
step emits -- just as invisible. So containers and ELFs are now recognised
by their magic bytes and the list is gone. Only the first four bytes of an
entry are decompressed unless it turns out to be one or the other, which
keeps a whole-tree run at about two seconds over eleven thousand files.

MAX_ARCHIVE_DEPTH goes 3 -> 8. The QRScanner chain is exactly three deep, so
the old limit had no headroom at all, and since exceeding it is now reported
as a failure rather than a silent skip, a limit set that close to real usage
would have produced false alarms rather than quiet gaps.

This does not change the verdict on the tree as it stands: the six libraries
inside that cn1lib are all 32-bit (armeabi, armeabi-v7a, x86), which the
16 KB rule does not cover. The scan simply sees twelve 32-bit libraries now
instead of six.

Proven against a probe that injects the pre-rebuild 4 KB whisper library into
the cn1lib -> nativeand.zip -> aar chain: the previous gate reports "6
libraries aligned" and exits 0, and this one fails naming the full nested
path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a78ae943aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
@shai-almog

shai-almog commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 160 screenshots: 160 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 226 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 71ms / native 5ms = 14.2x speedup
SIMD float-mul (64K x300) java 66ms / native 3ms = 22.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 222.000 ms
Base64 CN1 decode 122.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 12.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.250x (75.0% faster)
Image applyMask (SIMD off) 80.000 ms
Image applyMask (SIMD on) 67.000 ms
Image applyMask ratio (SIMD on/off) 0.838x (16.2% faster)
Image modifyAlpha (SIMD off) 69.000 ms
Image modifyAlpha (SIMD on) 52.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.754x (24.6% faster)
Image modifyAlpha removeColor (SIMD off) 70.000 ms
Image modifyAlpha removeColor (SIMD on) 64.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.914x (8.6% faster)

shai-almog added a commit that referenced this pull request Sep 3, 2026
Review finding on #5688, and a regression I introduced two commits ago.
abc4304 made "not an ELF file" a failure; a78ae94 then dispatched on
magic bytes instead of extension, which removed the only route to that
check. A zeroed or corrupted `libfoo.so` matched no magic, was classified as
an ordinary file, and was skipped in silence -- and the six valid Whisper
slices satisfy MIN_LIBRARIES_SCANNED on their own, so the run still exited 0.
Trading a curated allow-list for a silent skip was not the intended bargain.

Content still decides what gets scanned, which is what finds a container or
a library under a name nobody anticipated. A name is now a second, separate
signal deciding what gets challenged: a file whose name declares a format
must actually be that format. Anything named like a shared library goes to
the ELF reader whatever its bytes say, so corruption is reported instead of
being quietly reclassified as a format the rule does not cover.

The same is done for archive names, because a zeroed `.aar` went through the
identical hole. Those suffixes are not the old allow-list returning: nothing
is discovered by being on them, and a container is still found by its magic
under any name.

Verified safe against the whole tree before changing anything -- 3461 archive
entries and every tracked file, with zero name/content mismatches, so nothing
existing newly fails. Probe cases: a zeroed `.so`, a `.so` holding text, and
a zeroed `.aar` are all reported now; an ELF named `weirdname.bin` is still
found and checked by magic; the truncation and misalignment probes from the
previous commits still fail as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5a7dab389

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
shai-almog added a commit that referenced this pull request Sep 3, 2026
Review finding on #5688: 16 KB pages are a Google Play requirement, not a
property of ELF. An ordinary desktop Linux x86_64 `.so` is built for 4 KB
pages and is correct at 0x1000, but the gate reads every tracked file and was
holding every 64-bit ELF to the Android rule, so a valid artifact would have
failed the workflow and blocked every PR.

Codename One really can carry one. Cn1libMojo.buildLinux() packages a
cn1lib's `linux/src/main/resources` into `nativelinux`, and buildJavase()
does the same for `nativese`, so a prebuilt desktop library on either path is
a supported thing to check in. Nothing in the tree does today, which is why
this was latent rather than red.

A library is subject to the rule when its scan path shows Android packaging:
an Android container anywhere in the chain (`.aar`, `.apk`, `.aab`, or the
`nativeand.zip` a cn1lib carries), or an Android ABI directory sitting inside
`jni`/`lib`/`jniLibs` -- the second so a loose `jniLibs/arm64-v8a/libfoo.so`
in a port is still covered. The label already carries the whole chain, so an
`.so` reached through `QRScanner.cn1lib!nativeand.zip!ZBarScannerLibrary.aar`
is recognised from containers three levels up.

Only alignment is scoped. A `.so` that is not an ELF, or one that is
truncated, still fails wherever it sits: those are bugs on any platform, and
scoping them would reopen the silent skip the previous two commits closed.

Demonstrated with one byte-identical 4 KB-aligned 64-bit library placed on
three paths: exempt as a loose desktop `.so`, exempt inside
`cn1lib!nativelinux.zip`, and still failing under `aar!jni/arm64-v8a/`. The
six Whisper slices remain enforced, the pre-rebuild AAR still produces its
six findings, and a zeroed `.so` on a non-Android path is still reported.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e48a227de3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
shai-almog added a commit that referenced this pull request Sep 3, 2026
Review finding on #5688: `looks_like_shared_library` tested `".so." in base`,
so `libfoo.so.sha256` and `libfoo.so.asc` were routed to the ELF reader and
failed the run with "not an ELF file". The gate reads every tracked path, so
committing an ordinary checksum or signature beside a native library would
have blocked the PR. A soname version is numeric -- `libfoo.so.1`,
`libfoo.so.1.2` -- so that is what is matched now. Being strict costs
nothing: a file that really is a library is still found by its magic whatever
it is called.

This is the fifth review finding on this script, and all five were the same
question answered wrong in a different place -- where the boundary sits
between enforced, exempt, and unreadable. Two let something unreadable pass
as compliant; two rejected a valid artifact under a rule that does not apply
to it. That is a boundary worth pinning rather than re-deriving, so the
predicates now have tests.

scripts/test_check_16k_page_alignment.py covers all three verdicts
separately: enforced for a 64-bit library under Android packaging, exempt for
32-bit and for desktop payloads, reported for anything unreadable, truncated
or not an ELF. The sharpest case asserts that one byte-identical payload is
enforced or exempt purely by where it is packaged. ELF payloads are
synthesised in the test, so it needs no toolchain and no checked-in fixture,
and it runs in two milliseconds.

Each test was checked against the bug it exists for by reverting that fix in
turn: the broad `.so.` match, the Android scoping, the name-forces-ELF
routing, the segment-past-end-of-file check, and magic-based container
detection. Every reversion turns the suite red; restoring it turns it green.

The workflow runs the tests before the scan, so a gate broken in a way that
makes it scan nothing is reported as a broken gate rather than as a clean
tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81315839bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
shai-almog and others added 7 commits September 3, 2026 19:21
Google Play requires every 64-bit shared library in an upload to be linked
for 16 KB memory pages: API 35+ uploads since 2025-11-01, and Wear OS
uploads containing native code from 2026-09-15. Every 64-bit library in the
checked-in cn1-ai-whisper AAR had PT_LOAD p_align 0x1000.

Alignment is settled at link time, so nothing downstream repairs it. AGP
aligns the ZIP entries and bundletool reports the outcome, but neither can
move a segment inside a prebuilt .so -- and because the artifact is ours
rather than the developer's, they could not fix it from their own sources.
The failure is also silent: the app builds and runs on every 4 KB device,
and only Play review or a real 16 KB device says otherwise.

The AAR is rebuilt with NDK r28. r28 is the first release that links this
way by default and, more to the point, the first whose prebuilt
libc++_shared.so and libomp.so are aligned -- those are copied out of the
NDK, so no flag set in this project could have fixed them on r26/r27. The
CMake link options cover libcn1aiwhisper.so for a standalone CMake run or
an older NDK; a probe under r26 confirms they move a library from 0x1000 to
0x4000.

The rebuild is equivalent and not merely aligned: identical AAR entry set,
identical JNI exports on all four ABIs, identical DT_NEEDED, the same
whisper.cpp commit, and a 2 KB size delta. That commit is now recorded in
the README, because nothing in the tree derived it and it was only
recoverable from strings inside the shipped library.

minSdk moves 19 -> 21, which is not a consequence of the NDK bump. The
NDK's floor has been API 21 since r26, so every slice ever shipped here --
32-bit included -- already carried API 21 in .note.android.ident while the
manifest claimed 19. An API 19 install would have failed at
System.loadLibrary. PlatformFeatureCatalog raises a consuming app's
android.min_sdk_version to match so the manifest merge still succeeds for a
default project.

scripts/check-16k-page-alignment.py gates this over every tracked archive
and loose .so, in its own workflow rather than inside pr.yml, whose paths
filter would let a PR that only adds a native artifact skip it. It reports
rather than skips an archive it cannot open or that nests too deep, so
"could not look" never reads the same as "looked and found nothing". Scope
is 64-bit only: 16 KB pages are a 64-bit feature, and NDK r28 itself ships
4 KB 32-bit prebuilts, so a wider rule would be unsatisfiable.

Both gates were confirmed non-vacuous against the pre-rebuild artifact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review finding on #5688: an unreadable `.so` payload was exempted rather
than reported, so a corrupted native library could be committed while the
check still exited 0.

Two ways through. A file named `.so` that is not an ELF at all returned
None and was dropped silently, counting toward nothing. And a *truncated*
64-bit library still begins with the ELF magic, so it fell out of the same
branch and was announced as "32-bit, not subject to 16 KB pages" -- the
exemption for an ABI the rule does not cover was reachable by corruption.
MIN_LIBRARIES_SCANNED did not help: the six valid Whisper slices satisfy
the floor on their own.

This is the rule already applied to archives the gate cannot open, which
the ELF parse itself was not holding to: an entry nobody could read is an
entry whose alignment nobody checked, and that must not come out reading
the same as one checked and found compliant.

So `read_load_alignments` now raises for anything that does not parse and
returns the ELF class alongside the alignments. A 32-bit library is exempt
only once it has been parsed and shown to really be a 32-bit ELF, which
means the 32-bit program header layout had to be read too -- the two
layouts differ in field order, not just in width.

It also rejects a PT_LOAD segment that ends past the end of the file.
Program headers sit near the front, so a library truncated mid-file parses
happily and reports correct alignment for contents that are not there.

The "rebuild with NDK r28" advice is now printed only when something was
actually misaligned; for a truncated artifact it pointed at the wrong fix.

The same hole existed in the Java check in AndroidWhisperAarProjectTest and
is closed the same way, with the entry name threaded in so a failure says
which library.

Verified against a probe AAR carrying a non-ELF `.so`, a 40-byte truncation,
a mid-file truncation, a valid 32-bit slice and a valid aligned 64-bit one:
the first three fail in both the script and the test, the last two behave as
before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review finding on #5688: the whole-tree scan walked past every tracked
`.cn1lib`, so a misaligned native library shipped through Codename One's own
library format was never inspected and the gate still exited 0.
`tests/core/lib/QRScanner.cn1lib` reaches real `.so` files through
`nativeand.zip` and then `ZBarScannerLibrary.aar`, three archives deep, and
none of them were being read.

The reported fix is to add `.cn1lib` to the extension list. The extension
list is the defect, though: it is a curated allow-list, it was already wrong
about the one format this project defines itself, and adding an entry leaves
the next container -- `.kar`, `.srcjar`, `.apks`, whatever a future packaging
step emits -- just as invisible. So containers and ELFs are now recognised
by their magic bytes and the list is gone. Only the first four bytes of an
entry are decompressed unless it turns out to be one or the other, which
keeps a whole-tree run at about two seconds over eleven thousand files.

MAX_ARCHIVE_DEPTH goes 3 -> 8. The QRScanner chain is exactly three deep, so
the old limit had no headroom at all, and since exceeding it is now reported
as a failure rather than a silent skip, a limit set that close to real usage
would have produced false alarms rather than quiet gaps.

This does not change the verdict on the tree as it stands: the six libraries
inside that cn1lib are all 32-bit (armeabi, armeabi-v7a, x86), which the
16 KB rule does not cover. The scan simply sees twelve 32-bit libraries now
instead of six.

Proven against a probe that injects the pre-rebuild 4 KB whisper library into
the cn1lib -> nativeand.zip -> aar chain: the previous gate reports "6
libraries aligned" and exits 0, and this one fails naming the full nested
path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review finding on #5688, and a regression I introduced two commits ago.
abc4304 made "not an ELF file" a failure; a78ae94 then dispatched on
magic bytes instead of extension, which removed the only route to that
check. A zeroed or corrupted `libfoo.so` matched no magic, was classified as
an ordinary file, and was skipped in silence -- and the six valid Whisper
slices satisfy MIN_LIBRARIES_SCANNED on their own, so the run still exited 0.
Trading a curated allow-list for a silent skip was not the intended bargain.

Content still decides what gets scanned, which is what finds a container or
a library under a name nobody anticipated. A name is now a second, separate
signal deciding what gets challenged: a file whose name declares a format
must actually be that format. Anything named like a shared library goes to
the ELF reader whatever its bytes say, so corruption is reported instead of
being quietly reclassified as a format the rule does not cover.

The same is done for archive names, because a zeroed `.aar` went through the
identical hole. Those suffixes are not the old allow-list returning: nothing
is discovered by being on them, and a container is still found by its magic
under any name.

Verified safe against the whole tree before changing anything -- 3461 archive
entries and every tracked file, with zero name/content mismatches, so nothing
existing newly fails. Probe cases: a zeroed `.so`, a `.so` holding text, and
a zeroed `.aar` are all reported now; an ELF named `weirdname.bin` is still
found and checked by magic; the truncation and misalignment probes from the
previous commits still fail as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review finding on #5688: 16 KB pages are a Google Play requirement, not a
property of ELF. An ordinary desktop Linux x86_64 `.so` is built for 4 KB
pages and is correct at 0x1000, but the gate reads every tracked file and was
holding every 64-bit ELF to the Android rule, so a valid artifact would have
failed the workflow and blocked every PR.

Codename One really can carry one. Cn1libMojo.buildLinux() packages a
cn1lib's `linux/src/main/resources` into `nativelinux`, and buildJavase()
does the same for `nativese`, so a prebuilt desktop library on either path is
a supported thing to check in. Nothing in the tree does today, which is why
this was latent rather than red.

A library is subject to the rule when its scan path shows Android packaging:
an Android container anywhere in the chain (`.aar`, `.apk`, `.aab`, or the
`nativeand.zip` a cn1lib carries), or an Android ABI directory sitting inside
`jni`/`lib`/`jniLibs` -- the second so a loose `jniLibs/arm64-v8a/libfoo.so`
in a port is still covered. The label already carries the whole chain, so an
`.so` reached through `QRScanner.cn1lib!nativeand.zip!ZBarScannerLibrary.aar`
is recognised from containers three levels up.

Only alignment is scoped. A `.so` that is not an ELF, or one that is
truncated, still fails wherever it sits: those are bugs on any platform, and
scoping them would reopen the silent skip the previous two commits closed.

Demonstrated with one byte-identical 4 KB-aligned 64-bit library placed on
three paths: exempt as a loose desktop `.so`, exempt inside
`cn1lib!nativelinux.zip`, and still failing under `aar!jni/arm64-v8a/`. The
six Whisper slices remain enforced, the pre-rebuild AAR still produces its
six findings, and a zeroed `.so` on a non-Android path is still reported.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review finding on #5688: `looks_like_shared_library` tested `".so." in base`,
so `libfoo.so.sha256` and `libfoo.so.asc` were routed to the ELF reader and
failed the run with "not an ELF file". The gate reads every tracked path, so
committing an ordinary checksum or signature beside a native library would
have blocked the PR. A soname version is numeric -- `libfoo.so.1`,
`libfoo.so.1.2` -- so that is what is matched now. Being strict costs
nothing: a file that really is a library is still found by its magic whatever
it is called.

This is the fifth review finding on this script, and all five were the same
question answered wrong in a different place -- where the boundary sits
between enforced, exempt, and unreadable. Two let something unreadable pass
as compliant; two rejected a valid artifact under a rule that does not apply
to it. That is a boundary worth pinning rather than re-deriving, so the
predicates now have tests.

scripts/test_check_16k_page_alignment.py covers all three verdicts
separately: enforced for a 64-bit library under Android packaging, exempt for
32-bit and for desktop payloads, reported for anything unreadable, truncated
or not an ELF. The sharpest case asserts that one byte-identical payload is
enforced or exempt purely by where it is packaged. ELF payloads are
synthesised in the test, so it needs no toolchain and no checked-in fixture,
and it runs in two milliseconds.

Each test was checked against the bug it exists for by reverting that fix in
turn: the broad `.so.` match, the Android scoping, the name-forces-ELF
routing, the segment-past-end-of-file check, and magic-based container
detection. Every reversion turns the suite red; restoring it turns it green.

The workflow runs the tests before the scan, so a gate broken in a way that
makes it scan nothing is reported as a broken gate rather than as a clean
tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… spots

Review finding on #5688: `classify` asked the library name first but left the
archive name as a fallback *after* the magic bytes. A valid ELF left in place
of an `.aar` was therefore read as a library and counted as a compliant
Android slice; the same bytes named `.cn1lib` were waved through as
non-Android. Either way a destroyed container kept the run green, which is
the opposite of what the format-integrity rule is for. Both reproduced before
the change.

The rule was only ever half-applied. Declarations are now answered before
discoveries, for both formats symmetrically: a name that declares a format
routes to that format's reader whatever the bytes say, and content decides
only when the name declares nothing. Discovery under an unanticipated name is
unaffected.

Two problems in the test file itself, found while verifying that:

Its loader served stale bytecode. `python3 -m py_compile` on the gate leaves a
`.pyc` behind, and importlib really did shadow an edit with it, reporting a
behaviour the source no longer had -- a pinning test that can pass against
code that no longer exists is worse than no test. The gate is now compiled
from source every run, demonstrated by mutating the source with a stale `.pyc`
in place and watching the suite go red.

And a mutation survey of every guard found six with no coverage at all: the
program header table bounds, the entry-size floor, the no-program-headers and
no-PT_LOAD cases, the unknown ELF class, and the archive depth limit. Each now
has a test, and each was confirmed to fail when its guard is removed. Removing
any of the twelve guards now turns the suite red; before, half of them could
have been deleted silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shai-almog
shai-almog force-pushed the fix/5682-whisper-16kb-page-alignment branch from 8131583 to 4046597 Compare September 3, 2026 16:23

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40465975a0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
Review finding on #5688: the alignment test was a minimum-only comparison,
so a `p_align` of 0x4001 cleared it and was announced as 16 KB compliant.
ELF permits 0 and 1 ("no alignment required") or a power of two, and nothing
else, so 0x4001 is a malformed segment rather than a value above the floor --
the gate would have been vouching for a library no loader would honour.

Reported as malformed rather than misaligned. It is not a number a linker
produces, so "rebuild it with a newer NDK" would be the wrong advice, and the
check sits with the other integrity checks in read_load_alignments rather
than in the Android-scoped alignment comparison: a corrupt alignment is
corrupt on any platform.

Surveyed the tree first: every PT_LOAD in it is 0x1000 or 0x4000, all powers
of two, so nothing existing newly fails. Tests pin both directions -- 0x4001
and 0x6000 are reported, and 0x8000 and 0x10000 still pass, because the rule
is a floor and a larger legal alignment is compliant. Removing the guard
turns the suite red.

Practical likelihood is low: no real toolchain emits such a value, so this
protects against a corrupted or hand-crafted artifact rather than a build
mistake. It is cheap and it keeps one rule intact -- the gate never reports
something it cannot vouch for as compliant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e987fbb837

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
Comment thread scripts/check-16k-page-alignment.py Resolved
Two review findings on #5688, both variants of the gate vouching for a
library it has no grounds to vouch for.

ELF requires p_vaddr and p_offset to be congruent modulo p_align. A segment
that is not cannot be mapped as it declares itself, and the alignment test
never looked, so such a library was reported compliant.

The second is about the gate's own reasoning rather than the file. The ABI
directory is the evidence used to decide which rule applies, so when the file
contradicts it there is no sound verdict left to reach: a 32-bit ELF under
jni/arm64-v8a was exempted as "32-bit, rule does not apply", and x86_64 bytes
under the same directory were counted as a compliant arm64 slice. Both are
guesses dressed as answers, and Android can load neither. Reported now, for
the same reason an unreadable file is.

That check is deliberately narrow. It fires only where a path actually names
an Android ABI directory, and a library outside one is not second-guessed --
this is not general ABI validation, which is another tool's job, but a guard
on the inference this gate makes.

Measured against every library in the tree before switching either on: 18
libraries, zero congruence violations, and all 18 agreeing with their ABI
directory, so nothing existing newly fails. Tests pin both directions -- each
ABI directory still accepts its own architecture, and a library outside one
is untouched. Removing either guard turns the suite red.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20db45ecd5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-16k-page-alignment.py Resolved
Comment thread scripts/check-16k-page-alignment.py Resolved
Two review findings on #5688, and one missing field behind both. The parser
never read `e_type`, so it could neither tell that a file was not a library
nor that it was not the kind of library Android can load.

The one that mattered is the false positive. A relocatable object from
`cc -c` legitimately has no program header table, and the gate demanded one
of every ELF it found, rejecting it with "program header entry size 0 is too
small". Reproduced with a real object built by the NDK's clang: checking a
prebuilt `.o` into the tree would have blocked every PR. That is the same
shape as the desktop `.so` and the checksum sidecar -- a valid artifact
failed by a rule that was never about it.

The other is hardening: an `ET_EXEC` or `ET_CORE` with aligned, in-bounds
segments was counted compliant, though Android's linker loads only `ET_DYN`.

Both fall out of one rule, the same declaration-versus-discovery split the
rest of the gate already uses. A file that claims to be a library -- by a
`.so` name, or by sitting in an Android ABI directory -- must be a shared
object, and is reported when it is not. An ELF found purely by its magic
under a name that claims nothing never claimed to be a library, and is not
this gate's business.

Reading the header is now separate from reading the segments, so the gate can
find out WHAT a file is before committing to parse it as something it may not
be. The program header table is required only once `e_type` says it should
have one.

Verified against the tree: all 18 libraries are ET_DYN, so nothing existing
newly fails. Tests pin the split in both directions -- a `.o` found by magic
is left alone, the same bytes named `.so` or placed under an ABI directory
are reported, and a real shared object is still inspected as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shai-almog
shai-almog merged commit e833273 into master Sep 3, 2026
30 checks passed
@shai-almog
shai-almog deleted the fix/5682-whisper-16kb-page-alignment branch September 3, 2026 17:39
@shai-almog

shai-almog commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 148 screenshots: 148 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 341 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 89ms / native 8ms = 11.1x speedup
SIMD float-mul (64K x300) java 105ms / native 6ms = 17.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 200.000 ms
Base64 CN1 decode 107.000 ms
Base64 native encode 663.000 ms
Base64 encode ratio (CN1/native) 0.302x (69.8% faster)
Base64 native decode 281.000 ms
Base64 decode ratio (CN1/native) 0.381x (61.9% faster)
Base64 SIMD encode 69.000 ms
Base64 encode ratio (SIMD/CN1) 0.345x (65.5% faster)
Base64 SIMD decode 67.000 ms
Base64 decode ratio (SIMD/CN1) 0.626x (37.4% faster)
Base64 encode ratio (SIMD/native) 0.104x (89.6% faster)
Base64 decode ratio (SIMD/native) 0.238x (76.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 11.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.182x (81.8% faster)
Image applyMask (SIMD off) 55.000 ms
Image applyMask (SIMD on) 38.000 ms
Image applyMask ratio (SIMD on/off) 0.691x (30.9% faster)
Image modifyAlpha (SIMD off) 44.000 ms
Image modifyAlpha (SIMD on) 38.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.864x (13.6% faster)
Image modifyAlpha removeColor (SIMD off) 58.000 ms
Image modifyAlpha removeColor (SIMD on) 60.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.034x (3.4% slower)

@shai-almog

shai-almog commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 144 screenshots: 144 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 143 screenshots: 143 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1365 seconds

Build and Run Timing

Metric Duration
Simulator Boot 114000 ms
Simulator Boot (Run) 0 ms
App Install 13000 ms
App Launch 5000 ms
Test Execution 456000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 249ms / native 3ms = 83.0x speedup
SIMD float-mul (64K x300) java 120ms / native 4ms = 30.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 284.000 ms
Base64 CN1 decode 102.000 ms
Base64 native encode 1450.000 ms
Base64 encode ratio (CN1/native) 0.196x (80.4% faster)
Base64 native decode 1574.000 ms
Base64 decode ratio (CN1/native) 0.065x (93.5% faster)
Base64 SIMD encode 54.000 ms
Base64 encode ratio (SIMD/CN1) 0.190x (81.0% faster)
Base64 SIMD decode 61.000 ms
Base64 decode ratio (SIMD/CN1) 0.598x (40.2% faster)
Base64 encode ratio (SIMD/native) 0.037x (96.3% faster)
Base64 decode ratio (SIMD/native) 0.039x (96.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 18.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.222x (77.8% faster)
Image applyMask (SIMD off) 66.000 ms
Image applyMask (SIMD on) 54.000 ms
Image applyMask ratio (SIMD on/off) 0.818x (18.2% faster)
Image modifyAlpha (SIMD off) 51.000 ms
Image modifyAlpha (SIMD on) 44.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.863x (13.7% faster)
Image modifyAlpha removeColor (SIMD off) 44.000 ms
Image modifyAlpha removeColor (SIMD on) 41.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.932x (6.8% faster)

@shai-almog

shai-almog commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 217 screenshots: 217 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 149 screenshots: 149 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1271 seconds

Build and Run Timing

Metric Duration
Simulator Boot 85000 ms
Simulator Boot (Run) 1000 ms
App Install 41000 ms
App Launch 8000 ms
Test Execution 469000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 72ms / native 4ms = 18.0x speedup
SIMD float-mul (64K x300) java 87ms / native 3ms = 29.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 226.000 ms
Base64 CN1 decode 204.000 ms
Base64 native encode 4389.000 ms
Base64 encode ratio (CN1/native) 0.051x (94.9% faster)
Base64 native decode 330.000 ms
Base64 decode ratio (CN1/native) 0.618x (38.2% faster)
Base64 SIMD encode 81.000 ms
Base64 encode ratio (SIMD/CN1) 0.358x (64.2% faster)
Base64 SIMD decode 57.000 ms
Base64 decode ratio (SIMD/CN1) 0.279x (72.1% faster)
Base64 encode ratio (SIMD/native) 0.018x (98.2% faster)
Base64 decode ratio (SIMD/native) 0.173x (82.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.571x (42.9% faster)
Image applyMask (SIMD off) 69.000 ms
Image applyMask (SIMD on) 40.000 ms
Image applyMask ratio (SIMD on/off) 0.580x (42.0% faster)
Image modifyAlpha (SIMD off) 45.000 ms
Image modifyAlpha (SIMD on) 252.000 ms
Image modifyAlpha ratio (SIMD on/off) 5.600x (460.0% slower)
Image modifyAlpha removeColor (SIMD off) 374.000 ms
Image modifyAlpha removeColor (SIMD on) 143.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.382x (61.8% faster)

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.

[Platform deprecation][Google] Rebuild cn1-ai-whisper native libraries for 16 KB pages before 2026-09-15

1 participant