Skip to content
cccskills
FreePublished on GitHub

test-ci

Run MNN checks and regression tests on a host computer or Android device, with stage summaries and failure logs. A separate workflow benchmarks LLM prompt processing and token generation on real iPhones and iPads, including branch comparisons.

OriginalShow the original description

Run MNN tests / benchmarks on host or real devices. Covers two parallel tracks — (1) the regression / CI suite (static checks, host-side tests, on-device Android arm64 matrix via ./test.sh + test_stages.json) and (2) one-command iOS real-device LLM benchmarking (prefill/decode tok/s, branch comparison). Use when the user asks to run the tests, run CI, smoke-test a build, verify a change on a device, benchmark on-device (Android or iPhone/iPad), or add / select / retune a test stage.

Works withHugging Face
See how to install

Good for

  • Run static checks and host regression tests
  • Verify selected backends on an Android device
  • Benchmark LLM speed and compare branches on iPhone or iPad
  • Add or adjust test stages
  • Investigate failed or skipped test stages

Files included (3)

  • SKILL.md10.1 KB
  • ios-llm-bench.md11.6 KB
  • test-suite.md13.8 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

MNN Test / CI SKILL (index)

This skill is an index. Pick the document that matches the task and follow it:

DocumentUse when
test-suite.mdRun the regression / CI suite — static checks, host (local) tests, the on-device Android arm64 matrix (./test.sh + test_stages.json); add / select / retune a test stage; audit stale CI scripts; add a new test.
ios-llm-bench.mdBenchmark LLM prefill/decode speed on a real iPhone/iPad (ios_llm_bench.sh); compare branches on iOS Metal/CPU; verify Metal kernel changes on device.

The two tracks are independent: Android/host regression testing goes through test.sh, while iOS LLM benchmarking goes through transformers/llm/engine/ios/ios_llm_bench.sh.

FileRole
test.shBash driver. static, local (host CPU), and android <serial> modes.
test_stages.jsonDeclarative stage matrix. Edit this to add / drop / retune stages — no shell edits needed for the common cases. It is self-documenting via its _documentation block.
docs/testing.md中文测试文档:阶段说明、字段表、新增算子测试流程。

Quick start

# Static checks only:
./test.sh static

# Host regression (CPU only): build + unit suite + smoke + LLM smoke.
./test.sh local

# Full on-device matrix on the attached arm64 device:
./test.sh android <serial>          # e.g. ./test.sh android R5CY71BJJ9D

<serial> comes from adb devices (the script prefers adbk and falls back to adb). If the device shows as unauthorized, the user must tap Allow USB debugging on the phone first.

Running a subset (filters)

Android mode takes an optional filter as the third argument:

./test.sh android <serial> cpu        # CPU unit + lowmem + llm
./test.sh android <serial> opencl     # OpenCL unit (image+buffer) + opencl smoke
./test.sh android <serial> vulkan     # Vulkan unit + vulkan smoke
./test.sh android <serial> gpu        # opencl + vulkan
./test.sh android <serial> unit       # all unit/op stages only
./test.sh android <serial> lowmem     # only the low-memory matrix
./test.sh android <serial> android-ci # bench + smoke + llm only (no unit/lowmem)

Valid filters: all (default) · cpu · opencl · opencl-image · opencl-buffer · vulkan · gpu · unit · lowmem · android-ci.

Reading the result (agent-friendly)

  • Each stage prints a delimited ═══ stage: <name> ═══ block, then a PASS / FAIL / SKIP line.
  • A final summary prints total / passed / failed / skipped and one line per stage. SKIP is not a failure — it means the prerequisite was absent (e.g. a GPU library, a model, or a missing build artefact).
  • Exit code is non-zero iff any stage failed. Gate automation on the exit code, not on log scraping.
  • Combined stdout/stderr for every stage is saved under logs/test-<UTC-timestamp>/<stage>.log — read the named log of a failing stage for the trailing output. rc=137 ≈ OOM-kill, rc=139 ≈ SIGSEGV.

Dynamic-shape device smoke tests

A zero exit code only proves that a backend context ran; it does not prove that the requested input shape selected the intended dynamic context. For a shape-sensitive device test, record and validate the runtime-observed input shape (for example, from a backend dump manifest or the runner's input tensor) before treating the test as dynamic-shape coverage.

Environment variables

VarModeMeaning
ANDROID_NDKandroidNDK root. Falls back to $HOME/android-ndk-r21.
ANDROID_EXTRA_CMAKEandroidExtra cmake flags appended to the build (e.g. -DMNN_SME2=OFF) — handy for bisecting a backend regression.
LLM_MODEL_DIRbothPath to an existing on-disk MNN-format LLM model. When set, that directory is used as-is and nothing is downloaded. Defaults to models/<repo-basename>/.
LLM_MODEL_REPObothModel repo id for the LLM smoke test. Default taobao-mnn/Qwen2.5-0.5B-Instruct-MNN.
LLM_MODEL_SOURCEbothDownload source when LLM_MODEL_DIR is unset: huggingface (default) or modelscope.
LLM_MODEL_URL_BASEbothOverride the resolve URL prefix outright (wins over LLM_MODEL_SOURCE).
MNN_TEST_SKIPbothComma list of exact test names to skip (also set per-stage via the JSON skip field).

Offline / no-network and mainland-China notes

LLM model provisioning is lazy: the download (or LLM_MODEL_DIR check) is deferred until the llm stage actually runs, and a provisioning failure skips only that stage. So the unit / smoke / bench stages run fine with no network.

# Already have the model on disk → no download attempt at all:
LLM_MODEL_DIR=/path/to/Qwen2.5-0.5B-Instruct-MNN ./test.sh local

# huggingface.co unreachable (e.g. mainland China) → fetch from ModelScope:
LLM_MODEL_SOURCE=modelscope ./test.sh android <serial>

For the built-in default model the ModelScope org is remapped automatically (taobao-mnn/* → MNN/*); an explicitly-set LLM_MODEL_REPO is used verbatim.

LLM backend/layout smoke

For backend or tensor-layout optimizations, do not stop at operator tests. Run an end-to-end llm_demo correctness smoke with a short prompt and another prompt long enough to cross backend prefill branch thresholds. This catches real exported-graph layout bugs where an op test covers only the output format, but the graph also changes an input tensor format.

macOS Metal answer A/B checks

For answer-level comparisons between two macOS Metal runtimes:

  • A Metal config does not prove that Metal ran. In a restricted execution context, MTLCreateSystemDefaultDevice() may return nil, after which llm_demo prints Init Metal Error / Can't Find type=1 backend, use 0 instead and silently produces a plausible CPU answer. Run in a GPU-visible context and fail the case on either fallback marker.
  • Use the same exported model, prompt bytes, backend settings and greedy sampler on both sides. Isolate each runtime's tmp_path / working directory so cache reuse cannot cross the A/B boundary.
  • Decide the multi-line prompt contract before running. llm_demo normally treats every non-empty line as a separate prompt; if one file is intended to be one long prompt, flatten or use an explicitly one-line-aware runner and record the transformed-input checksum.
  • Fixed token limits can stop in the middle of a UTF-8 token and can leave code answers incomplete. Exact matches are strong evidence, but low character similarity after an early greedy fork needs semantic review. For code prompts, use a large enough budget and compile/test the extracted code before claiming functional correctness.

Configuring stages

Editing test_stages.json is the supported way to add, drop, or retune unit / lowmem / smoke / bench stages. Every parameter (forward type, precision, gpuMode, thread count, tag, memory mode, dynamic-quant option, KleidiAI flag, per-stage skip list, smoke model list, benchmark args) lives there, and the _documentation block at the top of the file explains every field and every skip entry's rationale.

  • Add a stage that runs an existing test in a new config → add an object to android.stages (or local.stages). See docs/testing.md § "增加专门阶段".
  • Skip a known-broken test on one stage → add its exact name to that stage's skip array and document why under _documentation.skip_rationale.
  • Add a smoke model / bench entry → see docs/testing.md § "新增 smoke 模型或 bench 阶段".

Auditing stale CI/test scripts

When asked to clean up old CI or test scripts, build a usage map before recommending deletion:

  • Prefer git ls-files plus targeted rg/git grep over broad filesystem scans, so generated build directories and local experiments do not look like maintained CI surface.
  • Classify scripts by role: active CI entrypoints, declarative test driver, release/package scripts, manual benchmark helpers, third-party vendored tests, and local device/debug helpers.
  • Treat lack of in-repo references as a "review/deprecate" signal, not proof of dead code; internal CI systems can invoke tracked files by convention. Prefer a staged deprecation plan unless a script is both unreferenced and clearly superseded by test.sh / test_stages.json.
  • When renaming or consolidating test entrypoints, grep for both executable names and generated-artifact prefixes. Update CI config, .gitignore, test_stages.json self-documentation, developer docs, skill docs, and code comments in the same change so the old entrypoint disappears completely.

Adding a new test

For bugfixes, first apply the unit-test submission policy: keep development-only tests local, and commit a new test only when its necessity has been reviewed and justified.

See test-suite.md § "Adding a new test" for the full steps. Two traps worth knowing up front: test/CMakeLists.txt globs sources at configure time, so a new test file needs a cmake re-run before it exists in run_test.out; and run_test.out prints an all-passed line even when the filter matched nothing, so confirm passed:N.

For deeper work on operators themselves, see the add-new-op skill.

Read next

docs/testing.md is the authoritative deep reference — read it for the per-stage breakdown, the stage-object field table, and worked examples.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

add-new-op

FreeSummary

Add new operators to MNN through a staged workflow covering data definitions, output shapes, computation, and tests. It prioritizes combining existing operators, with CPU implementations and additional hardware backends used when needed.

  • Adding a new operator to MNN
  • Implementing output shape calculations
  • Combining existing operators for new operations
alibaba/MNN16.2KUpdated Oct 16, 2026

bugfix

FreeSummary

Triage incorrect MNN outputs and regressions by matching symptoms to focused debugging guides. Use backend comparisons, minimal reproductions, and controlled experiments to investigate memory issues, quantization, concurrency, numeric limits, caches, and inconsistent results across runs.

  • Investigating garbled or degraded MNN output
  • Comparing results across execution backends
  • Tracking regressions after optimization changes
alibaba/MNN16.2KUpdated Oct 16, 2026

cpu

FreeSummary

Find the right workflow for MNN CPU work, from investigating slow execution to implementing calculation routines and planning tests. Compare ARM, x86_64, and RISC-V backend structures before choosing the relevant guidance.

  • Choosing where to start an MNN CPU performance investigation
  • Finding guidance for CPU kernel implementation
  • Comparing ARM, x86_64, and RISC-V backend structures
alibaba/MNN16.2KUpdated Oct 16, 2026

cpu-kernel

FreeSummary

Develop or port CPU kernels, the low-level calculation routines used by MNN. Follow staged implementation guidance, check data layout agreements, register functions, and verify correctness across processor instruction sets and numerical precision settings.

  • Implementing or porting an MNN CPU kernel
  • Adding support for a processor instruction set
  • Changing packed data layouts or tile sizes
alibaba/MNN16.2KUpdated Oct 16, 2026

cpu-optimize

FreeSummary

Find why MNN CPU inference is slow by examining threads, scheduling, memory layout, and the processor instruction path actually used. Operator-level measurements and comparisons with other inference frameworks help identify which layer needs improvement across ARM, x86_64, and RISC-V.

  • Investigate slow CPU operators or LLM inference
  • Diagnose thread count and memory usage anomalies
  • Locate the cause of a performance regression
alibaba/MNN16.2KUpdated Oct 16, 2026

Optimize and troubleshoot MNN's Hexagon DSP backend, which runs computation on a dedicated processor. The workflow uses device measurements to identify bottlenecks, compare v79 and v81 architectures, verify correctness, and investigate crashes or memory usage.

  • Finding bottlenecks in Hexagon operators
  • Checking changes on v79 and v81 devices
  • Investigating cDSP crashes and device disconnects
alibaba/MNN16.2KUpdated Oct 16, 2026

See all skills by alibaba

Report a problem with this skill