Skip to content

Commit 42d0740

Browse files
authored
Qualcomm AI Engine Direct - Enabling On-host profiling estimation for Executorch QNN HTP (pytorch#22143)
### **User description** ## Summary Introduce two officially supported HTP profiling workflows — on-device **OpTrace** and host-only **Hextimate** — behind a small public Python API returning `QnnHtpProfileArtifacts`. Split the demo into three workflow-named example scripts and rewrite the README around the three routes. ## Motivation Profiling QNN-delegated `.pte`s used to be a single demo with a hidden `--online_prepare` switch that silently picked between `.dlc` vs `.bin`, host-side vs on-device tools, and set (or didn't set) `profile_level=3` behind the user's back. This PR replaces that with **three named routes, one public API, and a self-contained `.pte`**. ## What each topic changes ### Public HTP profiling API (`backends/qualcomm/debugger/utils.py`) Two workflow-specific entry points instead of one mode-flag function. Each returns a `QnnHtpProfileArtifacts` per compiled binary in the `.pte`, carrying `binary_path`, `profile_mode`, `prepare_mode`, `qhas_html`, `qhas_json`, `chrometrace_json`, and HTP graph JSONs. - `generate_htp_profile_result()` — on-device OpTrace (both prepare modes). - Validates offline-prepare inputs by decoding the `.pte`'s compile spec and rejecting anything without `profile_level=3` at the Python boundary, rather than producing an unusable output later. - For online-prepare, no `profile_level` is required — the QNN CLI attaches instrumentation at host-side context-binary-generation time. - `estimate_htp_profile_result()` — host-only Hextimate. - Enforces `online_prepare=True` (Hextimate requires a `.dlc`, not a `.bin`). - Enforces supported-SoC allowlist (`SA8540`, `SA8255`, `QCS9100`, `SA8797`) fail with a legible error. - Enforces minimum QNN SDK version support for Hextimate. - **Design rationale**: two functions, not one function with a mode enum. Each route has genuinely different constraints (device vs host, prepare-mode requirements, SoC allowlist) — a shared entry point would push all four validation matrices into the caller. Two functions with clear names is cheaper than one function with four flags. ### Compile-spec plumbing (`backends/qualcomm/serialization/qc_compiler_spec.fbs`, `qc_schema.py`, `utils/utils.py`) - Adds `SA8540 = 62` to `QcomChipset` and the host-side `get_soc_to_chipset_map()`. The other three Hextimate-supported SoCs (`SA8255`, `QCS9100`, `SA8797`) already existed. - Wire value `62` matches the QNN SDK's internal SoC ID for SA8540 — the enum wire values are load-bearing, so the addition is at a specific numeric slot, not the tail of the enum. - Purely additive; no existing entries are renumbered. ### Example scripts (`examples/qualcomm/util_scripts/`) One script per route, with the route encoded in the filename so a reader picks the right file without reading code: - `htp_profiling_on_device_op_trace_online.py` — on-device OpTrace, `online_prepare=True`, `.dlc` path. - Asserts `qnn_config.online_prepare` at entry. - No `profile_level` handling — QNN CLI attaches instrumentation host-side. - `htp_profiling_on_device_op_trace_offline.py` — on-device OpTrace, `online_prepare=False` + `profile_level=3`, `.bin` path. - Asserts `qnn_config.profile_level == 3 and not qnn_config.online_prepare` at entry. - Exercises the new self-contained schematic packaging. - `htp_profiling_on_host_hextimate.py` — host-only Hextimate (renamed from the old merged demo, not net-new). - Requires `--enable_x86_64`; no adb involved. **`qairt-visualizer` is optional in all three scripts**: - If installed: reports open automatically after generation. - If not installed: `qhas_html` paths are printed to stdout so users can view them however they want. - Removes a soft dependency without losing the happy path. **Design rationale**: three short files (~90 lines each) beat one file with `if args.mode == "..."` branches. The old merged demo had a bug where `--profile_level 3` was passed under `--online_prepare` even though online-prepare doesn't need it — the kind of bug you get when one file quietly handles multiple pipelines. Naming a file after its pipeline eliminates the class. ### Documentation (`backends/qualcomm/debugger/README.md` + `examples/qualcomm/util_scripts/README.md`) - README rewritten around the **five user tasks** rather than around the toolchain: 1. Select a `.pte` prepare mode (decision table: online-prepare needs Hextimate/graph view; offline-prepare when you already have a `profile_level=3` `.pte`). 2. Run on-device OpTrace generation. 3. Run host-only Hextimate estimation. 4. Inspect the returned `QnnHtpProfileArtifacts`. 5. View QHAS reports with QAIRT Visualizer. - Hextimate limitations and the supported-SoC list are documented in place, next to the code path that enforces them. - README quick-start snippets link directly to the three renamed example scripts. - `examples/qualcomm/util_scripts/README.md` indexes each of the three profiling example scripts by filename. ### Tests (`backends/qualcomm/tests/test_qnn_delegate.py`) - New public-API test covering **unsupported-SoC rejection for Hextimate before reading `.pte` inputs** — this is a defensive-order check (validate first, then touch inputs), not just an error-message check. Catches regressions where validation gets reordered behind expensive `.pte` parsing. - `test_qnn_backend_generate_optrace` refactored in both `TestQNNFloatingPointUtils` and `TestQNNQuantizedUtils`: - Exercises both prepare modes in one test (online-prepare, then offline-prepare with `profile_level=3`). - Consumes the new `QnnHtpProfileArtifacts` return shape (`.qhas_json`, `.chrometrace_json`). - Skip when `enable_x86_64` (OpTrace requires on-device execution) or LPAI backend (unsupported). - `test_qnn_backend_generate_hextimate` refactored in `TestQNNQuantizedUtils`: - Skip when `not enable_x86_64` (Hextimate is host-only; needs `--enable_x86_64`). - Asserts `qhas_json is None` — Hextimate QHAS JSON is truncated by an upstream SDK bug (division by zero on `time_us=0`); we surface this by returning `None` from the API rather than papering over it. The HTML report and chrometrace remain usable. - Skip logic is **complementary**: OpTrace ⇒ on-device (`enable_x86_64` skips), Hextimate ⇒ host-only (`not enable_x86_64` skips). Users run them in two separate test invocations with different `--build_folder` / `--enable_x86_64` combinations. ## Verification ### Script syntax ```bash python -m py_compile \ examples/qualcomm/util_scripts/htp_profiling_on_device_op_trace_online.py \ examples/qualcomm/util_scripts/htp_profiling_on_device_op_trace_offline.py \ examples/qualcomm/util_scripts/htp_profiling_on_host_hextimate.py ``` ### End-to-end example scripts (three routes, matched flags) ```bash python -m examples.qualcomm.util_scripts.htp_profiling_on_device_op_trace_online \ --host <HOST> --device <DEVICE_SERIAL> --soc_model <SOC_MODEL> \ --build_folder build-android --online_prepare -a <ARTIFACT_DIR> python -m examples.qualcomm.util_scripts.htp_profiling_on_device_op_trace_offline \ --host <HOST> --device <DEVICE_SERIAL> --soc_model <SOC_MODEL> \ --build_folder build-android --profile_level 3 -a <ARTIFACT_DIR> python -m examples.qualcomm.util_scripts.htp_profiling_on_host_hextimate \ --soc_model SA8797 --build_folder build-x86 --enable_x86_64 --online_prepare -a <ARTIFACT_DIR> ``` ### Targeted profiling tests (existing framework, no CLI shape change) ```bash python -m backends.qualcomm.tests.test_qnn_delegate \ TestQNNQuantizedUtils.test_qnn_backend_generate_optrace \ --host <HOST> --device <DEVICE_SERIAL> --soc_model <SOC_MODEL> --build_folder build-android python -m backends.qualcomm.tests.test_qnn_delegate \ TestQNNFloatingPointUtils.test_qnn_backend_generate_optrace \ --host <HOST> --device <DEVICE_SERIAL> --soc_model <SOC_MODEL> --build_folder build-android python -m backends.qualcomm.tests.test_qnn_delegate \ TestQNNQuantizedUtils.test_qnn_backend_generate_hextimate \ --soc_model SA8797 --build_folder build-x86 --enable_x86_64 ```
1 parent 8734b06 commit 42d0740

10 files changed

Lines changed: 1099 additions & 358 deletions

File tree

‎backends/qualcomm/debugger/README.md‎

Lines changed: 170 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,210 @@
1-
# QAIRT Visualizer
1+
# ExecuTorch QNN Debugger & Profiler
22

3-
[QAIRT Visualizer](https://pypi.org/project/qairt-visualizer/) is a Python package designed to help you visualize and analyze data from Qualcomm AI Engine Direct (QNN) models. It provides tools to generate and interpret op traces (`optrace`) and QNN HTP Analysis Summary (`QHAS`), enabling detailed insights into your model's performance and behavior.
3+
This directory bundles three independent debugging and profiling flows for the ExecuTorch QNN backend. They are independent and address different failure modes — jump directly to the section you need.
44

5-
## Installation
5+
**Table of contents**
66

7-
You can install the QAIRT Visualizer package directly from [QAIRT Visualizer](https://pypi.org/project/qairt-visualizer/):
7+
- [Executorch QNN HTP Profiling](#executorch-qnn-htp-profiling)
8+
- [ExecuTorch QNN Intermediate Output Debugger](#executorch-qnn-intermediate-output-debugger)
9+
- [ExecuTorch QNN HTP Heap Profiling](#executorch-qnn-htp-heap-profiling)
810

11+
12+
---
13+
# Executorch QNN HTP Profiling
14+
15+
This section covers two complementary HTP profiling workflows.
16+
17+
| Workflow | API | Measurement source | Device | Prepare modes | Output and accuracy |
18+
|:--|:--|:--|:--|:--|:--|
19+
| On-device OpTrace | `generate_htp_profile_result()` | Hardware trace and counters from an actual execution | Required through ADB | `online_prepare` and `offline_prepare` | `QnnHtpProfileArtifacts` including QHAS and Chrome trace; microsecond and cycle units; representative of the measured device run. |
20+
| Host-only Hextimate | `estimate_htp_profile_result()` | QNN compile-time performance model | Not required | `online_prepare` only | `QnnHtpProfileArtifacts` including QHAS and Chrome trace; cycle estimates only, which can differ from device measurements. |
21+
22+
Use on-device OpTrace for accurate runtime analysis. Use host-only Hextimate for early cycle estimates when hardware is unavailable.
23+
24+
Prepare mode controls which QNN internal graph format is stored in the `.pte`:
25+
26+
- On-device OpTrace supports both `online_prepare` and `offline_prepare`.
27+
- Host-only Hextimate requires `online_prepare`.
28+
29+
30+
**Profile level**
31+
32+
| `profile_level` | QNN configuration | Use |
33+
|:----------------|:------------------|:----|
34+
| `0` | Profiling disabled | Default inference. |
35+
| `2` | `QNN_PROFILE_LEVEL_DETAILED` | Collect QNN graph and per-node timing through the ExecuTorch profiler. |
36+
| `3` | Detailed + `QNN_PROFILE_CONFIG_OPTION_ENABLE_OPTRACE` | Enable HTP Optrace hardware-trace artifacts for `qnn-profile-viewer`; required at export for offline-prepare Optrace. |
37+
38+
The rest of the guide is arranged here:
39+
1. **`.pte` generation prepare mode:**
40+
We introduce how to trigger each preparation mode in section 1.1 and 1.2:
41+
- 1.1 `online_prepare`: controlled by `QnnConfig.online_prepare=True`.
42+
- 1.2 `offline_prepare`: controlled by `QnnConfig.online_prepare=False`.
43+
44+
3. **Public Functions for Generating Profiling Results**
45+
+ 2.1 `generate_htp_profile_result()`: generates device-based profiling results (Optrace in QNN SDK).
46+
+ 2.2 `estimate_htp_profile_result()`: estimates host-based profiling results (Hextimate in QNN SDK).
47+
48+
4. **HTP Profile Output Format:** `QnnHtpProfileArtifacts` contains genrated HTML, JSON and chrometrace files.
49+
50+
5. **Qairt-Visualizer:** QAIRT Visualizer can open the QHAS result from `qhas_json` and `chrometrace_json`. Use `QnnHtpProfileArtifacts.visualizer_reports()` to pass related reports.
51+
## 1. Select AOT Prepare modes for `.pte` Generation
52+
Users choose one prepare mode before exporting the `.pte`:
53+
54+
| Prepare mode | QNN config | User-facing behavior |
55+
|:-------------|:-----------|:---------------------|
56+
| **online_prepare** | `QnnConfig.online_prepare=True` | Export stores a graph description; profiling tools finish preparation later. |
57+
| **offline_prepare** | `QnnConfig.online_prepare=False` | Export stores the finalized executable form; on-device profiling requires `profile_level=3`. |
58+
59+
Internal detail: online prepare carries a `.dlc`, and offline prepare carries a finalized QNN context binary (`.bin`). Offline prepare must set `profile_level=3` because OpTrace instrumentation has to be baked into that context binary during export. The schematic file used by `qnn-profile-viewer` is generated or unpacked beside the dumped profiling artifacts.
60+
61+
The example demos keep the profiling route explicit:
62+
63+
- `examples/qualcomm/util_scripts/htp_profiling_on_device_op_trace_online.py`: on-device OpTrace with `online_prepare`.
64+
- `examples/qualcomm/util_scripts/htp_profiling_on_device_op_trace_offline.py`: on-device OpTrace with `offline_prepare`.
65+
- `examples/qualcomm/util_scripts/htp_profiling_on_host_hextimate.py`: host-only Hextimate with `online_prepare`.
66+
67+
### 1.1 Online Prepare Mode `.pte`
68+
69+
**Demo script**:
970
```bash
10-
pip install qairt-visualizer
71+
python -m examples.qualcomm.util_scripts.htp_profiling_on_device_op_trace_online \
72+
--host ${host} --device ${device} --soc_model ${SOC_MODEL} --build_folder build-android \
73+
-a ${path_to_output_folder} --online_prepare
1174
```
1275

13-
## Quick start
14-
This command launches an interactive GUI interface to visualize the `optrace` and `QHAS` results.
76+
**Export call**:
77+
The export step does not need to set `profile_level`:
78+
```python
79+
build_executorch_binary(
80+
model=model,
81+
qnn_config=qnn_config, # online_prepare=True; profile_level not required
82+
file_name=f"{args.artifact}/{pte_filename}",
83+
dataset=[example_input],
84+
quant_dtype=QuantDtype.use_8a8w,
85+
)
1586
```
16-
python -m examples.qualcomm.util_scripts.qairt_visualizer_demo --host ${host} --device {device} --soc_model ${SOC_MODEL} --build_folder build-android -a ${path_to_output_folder} --online_prepare
87+
88+
### 1.2 Offline Prepare Mode `.pte`
89+
**Demo script**:
90+
```bash
91+
python -m examples.qualcomm.util_scripts.htp_profiling_on_device_op_trace_offline \
92+
--host ${host} --device ${device} --soc_model ${SOC_MODEL} --build_folder build-android \
93+
-a ${path_to_output_folder} --profile_level 3
1794
```
18-
- If online prepare mode is `enabled`, the following artifacts will be generated:
19-
- `model`.dlc
20-
- `optrace`.json
21-
- `QHAS`.json
22-
- If online prepare mode is `disabled`, the following artifacts will be generated:
23-
- `model`.bin
24-
- `optrace`.json
25-
- `QHAS`.json
26-
27-
Note: Model visualization is supported only in online prepare mode.
28-
The `.bin` format is not compatible with the QAIRT visualizer.
29-
To enable model visualization, please add the `--online_prepare` flag.
30-
31-
## Details
32-
### 1. Lower to QNN backend
33-
Generate an ExecuTorch binary for Qualcomm platforms.
34-
Ensure that qnn_config.profile_level is set to 3, which will generate op_trace.
95+
96+
**Export call**:
97+
The export step **must** set `profile_level=3`:
3598
```python
3699
qnn_config.profile_level = 3
37100
build_executorch_binary(
38101
model=model,
39-
qnn_config=qnn_config,
102+
qnn_config=qnn_config, # online_prepare=False (default)
40103
file_name=f"{args.artifact}/{pte_filename}",
41104
dataset=[example_input],
42105
quant_dtype=QuantDtype.use_8a8w,
43-
online_prepare=args.online_prepare,
44-
optrace=True,
45106
)
46107
```
47-
### 2. Generate optrace and QHAS
48-
Generate optrace and QHAS files using QNN tools under $QNN_SDK_ROOT. After finishing, you will get a `binaries_trace` dictionary.
49-
``` python
50-
adb = SimpleADB(
51-
qnn_config=qnn_config,
108+
109+
## 2.1 Generate HTP Profile Result (OpTrace) `generate_htp_profile_result()`
110+
111+
Use `generate_htp_profile_result()` when you want real on-device hardware-counter profiling. This path requires sample inputs and `adb`.
112+
```python
113+
from executorch.backends.qualcomm.debugger.utils import generate_htp_profile_result
114+
115+
artifacts = generate_htp_profile_result(
116+
artifact_dir=args.artifact,
117+
soc_id=get_soc_to_chipset_map()[args.soc_model],
52118
pte_path=f"{args.artifact}/{pte_filename}.pte",
53-
workspace=f"/data/local/tmp/executorch/{pte_filename}",
54-
)
55-
binaries_trace = generate_optrace(
56-
args, adb, f"{args.artifact}/{pte_filename}.pte", example_input
119+
inputs=example_inputs,
120+
adb=adb,
57121
)
58122
```
59-
- **`binaries_trace`**: A dictionary where keys are the dumped file paths and values are tuples containing the paths to the generated optrace and QHAS JSON files.
60123

61-
- Example 1: {"forward_0.dlc": (optrace.json, optrace_qnn_htp_analysis_summary.json)}
62-
- Example 2: {"forward_0.bin": (optrace.json, optrace_qnn_htp_analysis_summary.json)}
124+
## 2.2 Estimation of HTP profiling on Host (Hextimate) `estimate_htp_profile_result()`
125+
126+
Use `estimate_htp_profile_result()` when you want host-only compile-time performance estimation. This path does not use sample inputs or `adb`.
63127

64-
### 3. Visualizing and Analyzing optrace and QHAS
128+
> [!WARNING]
129+
> `estimate_htp_profile_result()` hard-errors on SDKs below 2.41 and on unsupported SoCs.
65130
66-
Once you have the optrace and QHAS files, you can leverage the QAIRT Visualizer to visualize the model graph, optrace and QHAS data. Here's how you can do it:
131+
**Demo script**:
132+
```bash
133+
python -m examples.qualcomm.util_scripts.htp_profiling_on_host_hextimate \
134+
--soc_model QCS9100 -a ${path_to_output_folder} --online_prepare
135+
```
67136

68137
```python
69-
import qairt_visualizer
70-
qairt_visualizer.view(f"{args.artifact}/forward_0.dlc", reports=[optrace, qhas])
138+
from executorch.backends.qualcomm.debugger.utils import estimate_htp_profile_result
139+
140+
estimates = estimate_htp_profile_result(
141+
artifact_dir=args.artifact,
142+
soc_id=get_soc_to_chipset_map()[args.soc_model],
143+
pte_path=f"{args.artifact}/{pte_filename}.pte",
144+
)
145+
```
146+
147+
Limitations:
148+
- Requires `QnnConfig.online_prepare=True`.
149+
- Requires QNN SDK >= 2.41.
150+
- Currently supports only the following soc_model:
151+
- SA8540
152+
- SA8255
153+
- QCS9100
154+
- SA8797
155+
156+
## 3. HTP Profiling Output `QnnHtpProfileArtifacts`
157+
Both public functions `estimate_htp_profile_result()` and `generate_htp_profile_result()` return one `QnnHtpProfileArtifacts` per compiled binary in the `.pte` (partitioned graphs yield multiple entries).
158+
159+
Important fields:
160+
161+
- `qhas_html`: QHAS HTML report. This is the most convenient artifact for viewing the QNN HTP Analysis Summary.
162+
- `qhas_json`: QHAS JSON report.
163+
- `chrometrace_json`: Chrome trace JSON. Open it with `chrome://tracing` or Perfetto.
164+
- `htp_graph_json`: HTP graph JSON after optimization.
165+
- `htp_graph_before_json`: HTP graph JSON before optimization.
166+
- `runtrace_json`: runtrace JSON for device profiling, or `None` when not emitted.
167+
168+
Other context fields:
169+
170+
- `binary_path`: dumped internal `.dlc` or `.bin` used by `qnn-profile-viewer`.
171+
- `mode`: `"optrace"` or `"hextimate"`.
172+
- `prepare_mode`: `"online"` or `"offline"`.
173+
174+
175+
## 4. Viewing HTP Analysis Summary (QHAS) with QAIRT Visualizer
176+
177+
**Install**
178+
179+
```bash
180+
pip install qairt-visualizer
71181
```
72-
or
182+
183+
**Usage**
184+
185+
QAIRT Visualizer can open the QHAS result from `qhas_json` and `chrometrace_json`. Use `QnnHtpProfileArtifacts.visualizer_reports()` to pass related reports.
186+
73187
```python
74188
import qairt_visualizer
75-
qairt_visualizer.view(reports=[optrace, qhas])
76-
```
77189

78-
- `model`: Path to your QNN model file (e.g., `path_to_your_model.dlc`).
79-
- **`reports`**: List of report file paths, including the optrace (`optrace.json`) and QHAS (`optrace_qnn_htp_analysis_summary.json`).
190+
for artifact in artifacts:
191+
qairt_visualizer.view(reports=artifact.visualizer_reports())
192+
print(f"QHAS HTML: {artifact.qhas_html}")
193+
```
194+
**Example**
195+
The example scripts already call QAIRT Visualizer after producing artifacts when `qairt-visualizer` is installed. If it is not installed, they still print the generated `qhas_html` path:
80196

81-
Note: Files ending with `.bin` do not support graph visualization in qairt_visualizer.
197+
- `examples/qualcomm/util_scripts/htp_profiling_on_device_op_trace_online.py`
198+
- `examples/qualcomm/util_scripts/htp_profiling_on_device_op_trace_offline.py`
199+
- `examples/qualcomm/util_scripts/htp_profiling_on_host_hextimate.py`
82200

83-
## Demo
84201

85202
<figure>
86-
<img src="assets/qairt_visualizer_demo.png" alt="QAIRT visualizer demo"> <figcaption>
203+
<img src="assets/qairt_visualizer_demo.png" alt="QAIRT Visualizer showing HTP profiling results"> <figcaption>
87204
</figcaption>
88205
</figure>
89206

90-
For more details, visit the [QAIRT Visualizer](https://pypi.org/project/qairt-visualizer/).
207+
For the viewer package, see [QAIRT Visualizer](https://pypi.org/project/qairt-visualizer/).
91208

92209

93210
# ExecuTorch QNN Intermediate Output Debugger

0 commit comments

Comments
 (0)