Skip to content

Is SM8845 (Snapdragon 8s Gen 4, Hexagon v81) supported? If not, what does it take to add it? #7516

Description

@Feng-Yang-github

Summary

SM8845 doesn't appear in any of LiteRT's Qualcomm SoC lists, but it ships in real consumer devices (Snapdragon 8s Gen 4 — kernel soc_id=685, QNN SDK socModel=97, Hexagon v81). I'm trying to run a LiteRT-compiled NPU graph on one, and the only workable target in SocModel is SM8850 (same v81 arch). That path runs into err = 1002 (QNN_CONTEXT_ERROR_MEM_ALLOC_FAIL) / Skel failed to process context binary on all 4 PDs at runtime, even with very small cache_length.

I'd like to confirm:

  1. Is SM8845 intentionally unsupported, or just not added yet?
  2. If a user wants to add it locally, what is the complete list of places that need to change?
  3. Beyond the enum/table edits, does the AOT compiler bake any per-SoC PerfSetting / cluster-topology info into the context binary that would make compiling-for-SM8850-and-running-on-SM8845 fundamentally incompatible?

Environment

LiteRT main branch, snapshot ~2026-05-19
QAIRT SDK 2.46.0.260424
Host Linux x86_64, NDK r28b cross-compile
Device ro.product.model=PLR110, ro.soc.model=SM8845, kernel /sys/devices/soc0/soc_id=685, Hexagon v81
Build cmake --preset android-arm64 for the runtime, aot_compile(target=SocModel.SM8850) for the model
Model Gemma 4 E2B, dynamic_wi4_afp32 recipe (W4 weights), various cache_length

What's in the codebase today

SM8845 is absent from every list I could find:

  • litert/python/aot/vendors/qualcomm/target.pySocModel enum stops at SM8850:

    class SocModel(StrEnum):
      ALL = "ALL"
      SA8255 = "SA8255"
      SA8295 = "SA8295"
      SM8350 = "SM8350"
      SM8450 = "SM8450"
      SM8550 = "SM8550"
      SM8650 = "SM8650"
      SM8750 = "SM8750"
      SM8850 = "SM8850"
    # TODO(weiyiw): Generate this from supported_soc.csv.
  • litert/vendors/qualcomm/core/schema/soc_table.h — C++ SnapdragonModel enum has SM8850 = 87 but no SM8845.

  • litert/vendors/qualcomm/core/schema/soc_table.cckSocInfos[] has no SM8845 entry.

  • litert/vendors/qualcomm/supported_soc.csv — no SM8845 row.

  • litert/vendors/qualcomm/compiler/qnn_compiler_plugin_test.cc and litert/vendors/qualcomm/qnn_backend_test/test_utils.h — test fixtures hardcode {"SM8650", "SM8750", "SM8850"}.

For reference, SM8845's QNN SDK socModel enum value is 97. It isn't in the QAIRT 2.46 QnnTypes.h header, but the SDK runtime recognizes it — the QAIRT Python utility qti/aisw/tools/core/utilities/devices/android/android_device_constants.py has the kernel-id-to-name mapping "685": "SM8845", and ExecuTorch PR pytorch/executorch#16500 explicitly defines SM8845 = 97 # v81.

What I tried, and what fails

1. Compile for SocModel.SM8850, runtime-patch the binary

Since SM8845 isn't in the enum, I picked the closest v81 target:

aot_lib.aot_compile(
    'extracted/Section2_prefill_decode.tflite',
    output_dir='compiled_sm8850',
    target=[qnn_target.Target(qnn_target.SocModel.SM8850)],
)

I then ASCII-replaced SM8850SM8845 in the resulting .tflite (works for the SoC name string, but obviously can't change SDK enum values that are stored as integers in the QNN context binary).

I also locally added SM8845 = 97 to SnapdragonModel, and added a kSocInfos[] entry with DspArch::V81 and vtcm_size_in_mb = 8, so that runtime FindSocInfo() succeeds. After this, dispatch correctly logs:

INFO: [Qnn] Initializing QNN backend for SoC model: SM8845

2. PD context allocation fails

The DSP skel then rejects the context binary on all 4 protection domains:

QnnDsp <E> Skel failed to process context binary.
QnnDsp <E> Context create from binary failed for deviceId 0 coreId 0 pdId 0 for context 1, err 5005
QnnDsp <E> Context 1 failed on pd 0
... (same for pdId 2, 3, 1) ...
QnnDsp <E> Failed to find available PD for contextId 1 on deviceId 0 coreId 0
            with context size estimate 2159091712
QnnDsp <E> context create from binary failed on contextId 1, err = 1002
ERROR: [qnn_manager.cc:600] Failed to create QNN context: 1002

3. Shrinking the model does not help

I suspected this was pure context-size pressure, so I rebuilt the model with progressively smaller cache_length:

cache_length Quantization Disk size (compiled .tflite) Runtime context size Result
4096 W4 (dynamic_wi4_afp32) 1.13 GB 4.00 GB err 1002 on all 4 PDs
1280 W4 1.13 GB 2.47 GB err 1002 on all 4 PDs
512 W4 1.13 GB 2.06 GB err 1002 on all 4 PDs

Even cache_length=512 (smallest realistic LLM context) fails identically with 5005 / 1002 on all PDs. That makes me suspect this isn't just memory size — the skel may be rejecting the binary because the PerfSetting / cluster-topology baked at compile time (for SM8850) doesn't match the SM8845 hardware.

Questions

  1. Is SM8845 planned to be added? It's a shipping consumer device (Snapdragon 8s Gen 4). Skipping it while supporting both the older SM8750 and the newer flagship SM8850 feels intentional but unexplained — is it gated on QAIRT 2.50+ exposing enum 97 in QnnTypes.h?

  2. What is the complete set of places to add an SoC? Beyond the four files listed above (target.py, soc_table.{h,cc}, supported_soc.csv), does the aot_compile flow generate or consume any per-SoC PerfSetting / .conf artifacts (cluster topology, HVX thread count, PMU template) that need updates? Is there any hidden hardcoding inside qnn-context-binary-generator invocation paths that depends on the SoC?

  3. # TODO(weiyiw): Generate this from supported_soc.csv. — what's the planned single-source-of-truth design here? Right now supported_soc.csv is hand-curated but the Python SocModel enum and C++ SnapdragonModel enum are independent and hand-edited, which makes user-side additions error-prone.

  4. Is 5005 / 1002 on all 4 PDs most likely (a) SoC PerfSetting mismatch from compiling for SM8850, (b) actual PD memory pressure where the SM8845 PD limit really is below ~2 GB, or (c) something else? Any diagnostic guidance (e.g. how to extract the embedded PerfSetting from a compiled context binary to confirm cluster topology) would be very helpful.

Repro

# 1. Build LiteRT runtime for android-arm64
cmake --preset android-arm64
cmake --build cmake_build_android_arm64 -j

# 2. Export Gemma 4 E2B with W4 at any cache_length
python -m litert_torch.generative.export_hf.export \
  --model=google/gemma-4-E2B \
  --output_dir=./out \
  --prefill_lengths=[128] \
  --cache_length=512 \
  --externalize_embedder=True \
  --quantization_recipe=dynamic_wi4_afp32

# 3. AOT-compile for SM8850 (closest available v81 target)
python -c "
from ai_edge_litert.aot import aot_compile as aot_lib
from ai_edge_litert.aot.vendors.qualcomm import target as qnn_target
aot_lib.aot_compile('Section2_prefill_decode.tflite',
    output_dir='compiled_sm8850',
    target=[qnn_target.Target(qnn_target.SocModel.SM8850)])
"

# 4. Push to an SM8845 device with QAIRT 2.46 v81 runtime libs and run_model
# 5. Observe err 1002 on all 4 PDs even with cache_length=512.

What would unblock me

A concrete answer to whether (a) SM8845 is a one-line-per-file addition I can do myself, or (b) it needs deeper compiler-side support that only the LiteRT maintainers can add. If (b), even a rough pointer to the relevant files / commits would let me plan around it.

Thanks!

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions