pytorch / pytorch/executorch

QNN LLM Compilation Pipeline — Profiling & Optimization

Open
#17,784 1 comment 0 reactions 1 assignee View on GitHub

@abhinaykukkadapu is already working on this.

Since Mar 2, 2026.

  • #17805 by @haowhsu-quic — merged
module: qnn module: quantization partner: qualcomm
Dominant language
Python
Stars
5k
Forks
1.2k
Avg merge
2d 10h
Merged PRs (30d)
581

Description

TLDR

Compiling quantized LLMs for the QNN HTP backend takes 5 to 12+ hours end-to-end. This blocks iteration on model quality, quantization recipes, and on-device evaluation. The pipeline has three major bottlenecks:

  1. Wasted autoregressive generation during calibration: After prefilling a short prompt into the KV cache, the calibration loop runs _generate to produce hundreds of tokens auto-regressively. These generated tokens are concat to the prompt and we run calibration with prompt + generated token, i don't think this improves quantization observer statistics since we use generated data by the model.

  2. Slow per-iteration DECODE calibration: The DECODE model processes tokens one at a time (ar_len=1), requiring 1023 sequential forward passes per wikitext chunk. Each pass takes 2-5s on CPU, making task calibration alone ~90 min. This needs deep dive into the torchao/ pytorch/ QNN quantization to find any optimizations to improve the per iteration speed.

  3. QNN SDK HTP compilation: qnn_manager.Compile (specifically GraphFinalize) runs the HTP compiler's optimization passes at level 3 (most aggressive). This takes 102-190 min depending on model size.

Baseline Profiling

Model: qwen2_5-1_5b (hybrid, max_seq_len=1024, prefill_ar_len=128)
python examples/qualcomm/oss_scripts/llama/llama.py -b build-android --compile_only -m SM8750 \
  --temperature 0 --model_mode hybrid --max_seq_len 1024 --prefill_ar_len 128 \
  --decoder_model qwen2_5-1_5b \
  --prompt "I would like to learn python, could you teach me with a simple example?" \
  --tasks wikitext --limit 1
Phase Time (min) % of Total
DECODE quantization
torch.export.export 0.4 0.1%
prepare_pt2e 0.5 0.1%
calibration (tasks) — 2 _model_calls, 1023 prefill fwd each 122.6 25.3%
calibration (prompts) — 16-token prefill + 546 _generate fwd 37.1 7.7%
convert_pt2e 1.2 0.2%
save QDQ EP 4.5 0.9%
PREFILL quantization
torch.export.export 0.4 0.1%
prepare_pt2e 0.7 0.1%
calibration (tasks) — 2 _model_calls, 8 prefill fwd each 5.8 1.2%
calibration (prompts) — 16-token prefill + 546 _generate fwd 152.0 31.4%
convert_pt2e 2.2 0.5%
Lowering + compilation
to_edge_transform_and_lower_to_qnn (total) 156.7 32.4%
    _build_op_wrappers (kv_forward) 7.5
    _build_op_wrappers (prefill_forward) 9.7
    qnn_manager.Compile 113.3
to_executorch + write_to_file 0.4 0.1%
Total ~484 (8.1h) 100%
Model: qwen3-1_7b (hybrid, max_seq_len=1024, prefill_ar_len=128)
Phase Time (min) % of Total
DECODE quantization
calibration (tasks) 86.5 13.3%
calibration (prompts) — 24-token prefill + 947 _generate fwd 40.3 6.2%
PREFILL quantization
calibration (tasks) 5.4 0.8%
calibration (prompts) — 24-token prefill + 947 _generate fwd 280.5 43.0%
Lowering + compilation
qnn_manager.Compile 190.1 29.1%
Total ~653 (10.9h) 100%
Bottleneck Summary
Bottleneck qwen2_5-1_5b
_generate during prompt calibration 189.1 min (39.1%)
DECODE task calibration (ar_len=1) 122.6 min (25.3%)
qnn_manager.Compile 113.3 min (23.4%)

Flame graph

Image

Notes:

  1. I couldn't run multiple runs per model due to long running nature and hence the percentages might have inherent overall and sub-category variance.
  2. I haven't verified ppl on-device, to get fast feedback created the issue with data and approaches first, to check if there is missing context.

cc @cccclai @winskuo-quic @shewu-quic @haowhsu-quic @DannyYuyang-quic @cbilgin @kimishpatel @jerryzh168

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.