mirror of
https://github.com/Helldez/BigMoeOnEdge.git
synced 2026-10-03 03:25:42 +00:00
chore: declare the app a game, pin what CI claims, and list every flag (#148)
Four things an audit found, none of which changes engine behaviour. The demo app declares android:appCategory="game". Vendor performance layers read that attribute to pick a governor profile, and on the OxygenOS test device it moved the app onto the boosted path: the foreground CPU ceiling went from 1.9/1.65 GHz to the hardware maximum of 3.32/3.80 GHz, measured before and after. Decode is the most CPU-hungry thing a phone does outside a game. The effect belongs to the vendor rather than to Android, and Samsung's game service has historically throttled what it classifies this way, so the manifest, the changelog and the app README all say to treat a per-device figure as a measurement. In-app numbers from before this are not comparable with numbers from after it. CI now enforces the versions it claims. The format job installs clang-format-18 by name instead of whatever the runner image ships, which happened to be 18 and would have started failing every PR against an unannounced version on the next image bump. The APK job builds with NDK r27c, the release that produces published APKs, so CI stops validating a build nobody installs. It also passes -DGGML_OPENCL=OFF, the flag whose absence once shipped a stray backend into two releases. checkout moves to v5, since v4 pins a deprecated Node runtime. --help lists every one of the fifty flags the CLI accepts. Six were missing. --io-trace is the one that mattered: a fully documented, guarded diagnostic that the usage text never mentioned, so the only way to find it was to read docs/telemetry.md. .gitignore covers .claude/, which until now was excluded only by a machine-local ignore file. A clone elsewhere would have shown a second checkout with build output and .so binaries as untracked, which is precisely the situation the never-"git add -A" rule exists to survive.
This commit is contained in:
parent
4645dc6b09
commit
50e7571bb7
7 changed files with 70 additions and 10 deletions
23
.github/workflows/ci.yml
vendored
23
.github/workflows/ci.yml
vendored
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
outputs:
|
||||
code: ${{ steps.decide.outputs.code }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: decide
|
||||
|
|
@ -65,19 +65,22 @@ jobs:
|
|||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: clang-format (our sources only)
|
||||
# Pinned to 18 because AGENTS.md tells contributors to match that version locally. Plain
|
||||
# `clang-format` is whatever the runner image ships, which happens to be 18 today: an image
|
||||
# bump would silently start failing every PR against a version nobody was told about.
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y clang-format
|
||||
sudo apt-get update && sudo apt-get install -y clang-format-18
|
||||
find core cli tests -type f \( -name '*.cpp' -o -name '*.h' \) \
|
||||
-print0 | xargs -0 clang-format --dry-run --Werror
|
||||
-print0 | xargs -0 clang-format-18 --dry-run --Werror
|
||||
|
||||
host-linux:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install deps
|
||||
|
|
@ -96,7 +99,7 @@ jobs:
|
|||
if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/v')
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Configure & build (compile-check the Win32 I/O paths)
|
||||
|
|
@ -116,7 +119,7 @@ jobs:
|
|||
permissions:
|
||||
contents: write # only used by the tag-triggered release attach step
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up JDK 17
|
||||
|
|
@ -128,7 +131,9 @@ jobs:
|
|||
uses: nttld/setup-ndk@v1
|
||||
id: ndk
|
||||
with:
|
||||
ndk-version: r26d
|
||||
# r27c == 27.2.12479018, the NDK release-apk.yml builds published APKs with. These two
|
||||
# must not drift, or CI validates a build nobody installs.
|
||||
ndk-version: r27c
|
||||
- name: Cross-compile bmoe-cli (arm64)
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.ndk.outputs.ndk-path }}
|
||||
|
|
@ -137,7 +142,7 @@ jobs:
|
|||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-29 \
|
||||
-DCMAKE_BUILD_TYPE=Release -DBMOE_BUILD_TESTS=OFF \
|
||||
-DGGML_NATIVE=OFF -DGGML_OPENMP=OFF \
|
||||
-DGGML_NATIVE=OFF -DGGML_OPENMP=OFF -DGGML_OPENCL=OFF \
|
||||
-DGGML_CPU_ARM_ARCH="armv8.2-a+dotprod+fp16" \
|
||||
-DLLAMA_CURL=OFF
|
||||
cmake --build build-android -j
|
||||
|
|
|
|||
2
.github/workflows/release-apk.yml
vendored
2
.github/workflows/release-apk.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
echo "tag=${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ steps.tag.outputs.tag }}
|
||||
submodules: recursive
|
||||
|
|
|
|||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -52,3 +52,9 @@ __pycache__/
|
|||
*.jks
|
||||
*.keystore
|
||||
keystore.properties
|
||||
|
||||
# Agent session state and its worktrees. Ignored belt-and-braces rather than relying on a
|
||||
# machine-local exclude: a clone elsewhere would otherwise show a second checkout, build output
|
||||
# and .so binaries as untracked, which is exactly what the never-'git add -A' rule exists to
|
||||
# survive.
|
||||
.claude/
|
||||
|
|
|
|||
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -116,6 +116,25 @@ Semantic Versioning.
|
|||
batch. Default `0` (never stop), which is what the host numbers were measured at.
|
||||
|
||||
### Changed
|
||||
- **The demo app declares `android:appCategory="game"`.** Vendor performance layers read that
|
||||
attribute, and on the OxygenOS test device it moves the app onto the boosted path: with the app
|
||||
in the foreground the CPU ceiling went from 1.9/1.65 GHz to the hardware maximum of 3.32/3.80 GHz,
|
||||
measured before and after. Decode is the most CPU-hungry thing a phone does outside a game, so
|
||||
that is the right path to be on. It cannot be a runtime setting — a manifest attribute is fixed
|
||||
at install — and the effect belongs to the vendor rather than to Android: neutral on stock
|
||||
builds, and Samsung's game service has historically throttled what it classifies this way, so any
|
||||
per-device figure is a measurement rather than a rule. **In-app numbers taken before this change
|
||||
are not comparable with numbers taken after it.**
|
||||
- **CI enforces the versions it claims to.** The format job installs `clang-format-18` explicitly
|
||||
instead of whatever the runner image ships, which happened to be 18 and would have started
|
||||
failing every PR against an unannounced version on the next image bump; the APK job builds with
|
||||
NDK r27c, the same release that produces published APKs, so CI stops validating a build nobody
|
||||
installs; and it passes `-DGGML_OPENCL=OFF`, the flag whose absence once shipped a stray backend
|
||||
into two releases. `actions/checkout` moves to v5 (v4 pins a deprecated Node runtime).
|
||||
- **`--help` lists every flag the CLI accepts.** `--io-trace` in particular was a fully documented,
|
||||
guarded diagnostic that the usage text never mentioned; `--version`, `-h`, `--prefetch-sync` and
|
||||
the two deprecated `--dense-weights` aliases are named now too. A flag that works but is not
|
||||
listed reads as an accident rather than a decision.
|
||||
- **The speculation config generalised to a draft *source*, and the flags with it.** `MtpConfig`
|
||||
became `SpecConfig` with `DraftSource { none, mtp, ngram }`, and `--mtp-draft N` became `--draft N`
|
||||
because the width belongs to the verify batch, not to whoever filled it; `--mtp` and `--ngram`
|
||||
|
|
|
|||
10
cli/main.cpp
10
cli/main.cpp
|
|
@ -378,8 +378,13 @@ static void print_usage(const char * argv0) {
|
|||
" same trace at layer granularity: one barrier per layer, so\n"
|
||||
" coalescing and the expert prefetch survive and the numbers stay\n"
|
||||
" close to an untraced run. Rows aggregate per layer (op LAYER)\n"
|
||||
" --io-trace PATH diagnostics: one row per expert read — its (layer, expert,\n"
|
||||
" projection), size and latency. Needs --moe-stream; this is how a\n"
|
||||
" flash-bandwidth claim is checked against the reads that made it\n"
|
||||
" --n-expert-used N override active MoE experts per token (top-k); lower = faster\n"
|
||||
" but changes the output (quality). 0 = model default\n"
|
||||
" -h, --help show this text and exit\n"
|
||||
" --version print the engine version and exit\n"
|
||||
"\n"
|
||||
" Sampling (default: greedy/argmax, deterministic):\n"
|
||||
" --temp F sampling temperature; <= 0 keeps greedy (default 0). > 0 enables\n"
|
||||
|
|
@ -423,6 +428,8 @@ static void print_usage(const char * argv0) {
|
|||
" ahwb = as anon, but into dma-buf memory the kernel may not reclaim\n"
|
||||
" at all — not even to zram, which is what anon still pays for.\n"
|
||||
" Android-only; measured +17.9%% on a long generation, off by default)\n"
|
||||
" Deprecated aliases kept for old scripts: --dense-odirect means\n"
|
||||
" `--dense-weights anon`, --no-warm-dense means `--dense-weights mmap`\n"
|
||||
" --load-all debug: read ALL experts each token (A/B baseline)\n"
|
||||
" --force-cache allow a cache-mb in the pathological band\n"
|
||||
" --overlap overlap async expert reads with FFN compute (needs the fork)\n"
|
||||
|
|
@ -430,6 +437,9 @@ static void print_usage(const char * argv0) {
|
|||
" rest, so the lanes start sooner (needs --overlap and the cache;\n"
|
||||
" experimental, off by default pending the on-device A/B)\n"
|
||||
" --prefetch K temporally prefetch the next K layers' experts (needs the cache)\n"
|
||||
" --prefetch-sync debug/tests only: complete each speculative read on the eval\n"
|
||||
" thread before returning. Defeats the point (nothing overlaps) but\n"
|
||||
" makes the integrate-then-hit path deterministic for the gates\n"
|
||||
" --drop-cold-experts F skip a routed expert that is a cache MISS and carries less than\n"
|
||||
" F x (1/top-k) of the routing's weight. F in (0, 1]; 1.0 is the\n"
|
||||
" uniform share and the useful maximum. LOSSY and cache-dependent:\n"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,16 @@ Two build flavors differ only in how a model reaches the device:
|
|||
- **play** — Play-Store-compliant. No broad storage permission: models come only through the
|
||||
in-app downloader or the file picker. `./gradlew assemblePlayDebug`.
|
||||
|
||||
Both declare `android:appCategory="game"`. That is a performance decision rather than a claim
|
||||
about what the app is: vendor layers read the attribute to pick a CPU governor profile, and on the
|
||||
OxygenOS test device it lifted the foreground ceiling from 1.9/1.65 GHz to the hardware maximum of
|
||||
3.32/3.80 GHz. Decode is the most CPU-hungry thing a phone does outside a game. The effect is the
|
||||
vendor's, not Android's — neutral on stock builds, and Samsung's game service has historically
|
||||
throttled apps it classifies this way — so treat any figure as a per-device measurement. It cannot
|
||||
be toggled at runtime; a manifest attribute is fixed at install, and the only lever would be a
|
||||
per-flavor manifest. **Numbers measured in the app before this landed are not comparable with
|
||||
numbers measured after it.**
|
||||
|
||||
## Getting a model onto the device
|
||||
|
||||
The picker lists every MoE `.gguf` it finds (dense models are filtered out by a gguf-header
|
||||
|
|
|
|||
|
|
@ -15,8 +15,18 @@
|
|||
filesystem where O_DIRECT works). The dev flavor overlay (src/dev/AndroidManifest.xml)
|
||||
adds all-files access to also read adb-pushed models in place. -->
|
||||
|
||||
<!-- appCategory="game" is a performance decision, not a claim about what this app is. Vendor
|
||||
performance layers read it: on the OxygenOS test device it moves the app onto the boosted
|
||||
path, where the foreground CPU ceiling goes from 1.9/1.65 GHz to the hardware maximum of
|
||||
3.32/3.80 GHz — measured before and after, with the app in the foreground. Decode is the
|
||||
most CPU-hungry thing a phone can do outside a game, so the boosted path is the right one.
|
||||
It cannot be a runtime setting: a manifest attribute is fixed at install time, and the
|
||||
only lever would be a per-flavor manifest. The effect is the vendor's, not Android's:
|
||||
neutral on stock builds, and Samsung's game service has historically THROTTLED what it
|
||||
classifies this way, so treat any per-device number as a measurement rather than a rule. -->
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:appCategory="game"
|
||||
android:extractNativeLibs="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue