# Profiling Models with QAIRT Visualizer This tutorial shows how to generate profiling reports on QAIRT backends. We will assume that you have followed the tutorial on [Mobilenet V2 Inference on HTP](https://docs.qualcomm.com/doc/80-87189-2/topic/on_device_inference.html#on-device-inference-android) and you already have a working environment setup. Note The expected flow of this tutorial is to execute each snippet step by step. If you would like to skip the breakdown, you can find the following full tutorials at: > > > - For basic profiling see: *<SDK>/examples/QAIRT/python/profiling\_tutorial.py* > - For performance reports see: *<SDK>/examples/QAIRT/python/op\_trace\_profiling\_tutorial.py* The parameters for this tutorial are as follows: > > > - Framework: PyTorch > - Model: [InceptionV3](https://pytorch.org/hub/pytorch_vision_inception_v3) > - Configurations: > > - Host OS: Linux (x86\_64) > - Target Devices: **Snapdragon Android Device** > - Processor: Qualcomm Neural Processing Unit (NPU) > - Backend: HTP Note This example is not compatible with Windows targets. Tip This tutorial creates some temporary files as part of the workflow. To customize the temporary file location, set this environment variable `QAIRT_TMP_DIR` to a location of your choosing. ## Step 1. Prerequisites This example uses the qairt visualizer python package. You can obtain the visualizer here: [QAIRT Visualizer](https://docs.qualcomm.com/bundle/publicresource/topics/80-87189-1/getting-started.html?product=1601111740009302#setup). Following installation, please ensure you can import the visualizer by running the following command in a shell: python -c "from qairt_visualizer import view" Copy to clipboard Optionally, if you would like to simply run the code without visualization, you can skip this breakdown and go directly to the tutorial in the SDK. You will need to disable the visualizer by setting the following flag at the top of each file: ENABLE_QAIRT_VISUALIZER = False Copy to clipboard ## Step 2. Setup import json import os import platform from pathlib import Path from typing import Any import numpy as np import torch import torchvision.models as models import qairt from qairt import CompileConfig, Device, DevicePlatformType, Profiler from qairt.api.common.backends.htp import HtpDeviceConfig, HtpGraphConfig, PerfProfile from qairt.api.configs.device import DeviceFactory, RemoteDeviceIdentifier Copy to clipboard ## Step 3. Get an InceptionV3 model Get a pretrained InceptionV3 model inceptionv3_artifacts = Path("./inceptionv3_artifacts") inceptionv3_artifacts.mkdir(exist_ok=True) # Create a directory for artifacts model = models.inception_v3(weights="Inception_V3_Weights.DEFAULT") model.eval() # Step 1b: Export the PyTorch model as an ONNX model # Prepare the dummy input dummy_input = torch.rand((1, 3, 224, 224), dtype=torch.float32) inceptionv3_model_path = str(inceptionv3_artifacts / "inceptionv3.onnx") torch.onnx.export( model, (dummy_input,), inceptionv3_model_path, input_names=["input"], output_names=["output"], opset_version=11, ) Copy to clipboard ## Step 4. Convert the model Convert the model and set `enable_framework_trace` argument to true. The argument creates a mapping from framework operations to their corresponding QAIRT operations which will be used during profiling. converted_model = qairt.convert(inceptionv3_model_path, enable_framework_trace=True) Copy to clipboard ## Step 5. Set up an Android device Reusing the android setup instructions from Step 4 in [Mobilenet V2 Inference on HTP](https://docs.qualcomm.com/doc/80-87189-2/topic/on_device_inference.html#on-device-inference-android) android_serial = os.getenv("ANDROID_SERIAL") android_hostname = os.getenv("ANDROID_HOSTNAME") device_id = RemoteDeviceIdentifier(serial_id=android_serial, hostname=android_hostname) android_device = Device(identifier=device_id, type=DevicePlatformType.ANDROID) Copy to clipboard ## Step 6. Generating Profiling Reports Profiling reports can provide insights into the performance of the model on your target device. Reports can be generated at different levels to provide finer grained details on metrics such as bandwidth and latency. The following sections will guide you through the process of generating different profiling reports for your model. ### Basic Reports To generate a profiling report, you can instantiate a [`qairt.Profiler`](https://docs.qualcomm.com/doc/80-87189-2/topic/qairt-core-api.html#qairt.Profiler) instance. The profiler acts as a context manager that gathers profiling data from compile and execution calls. You can generate basic, detailed, client or backend reports by setting the level parameter in the context manager. Generating a report is as simple as performing inference, compilation or both within a context input_array = np.random.randn(1, 3, 224, 224).astype(np.float32) # You may set the backend here: desired_backend = "HTP" with Profiler(context={"level": "basic"}) as profiler: # Execute the model directly without compiling. _ = converted_model(input_array, device=android_device, backend=desired_backend) # Generate the profiler report basic_model_report = profiler.generate_report() basic_report_path = str(inceptionv3_artifacts / "profiling_report.json") basic_model_report.dump(basic_report_path) Copy to clipboard You can view the report using the view function. This will open the report in a QAIRT Visualizer window. view(basic_report_path) Copy to clipboard Note Generating detailed reports may take slightly longer due to intermediate output tensor generation. ### Step 7. Detailed Reports # Create the data as before input_array = np.random.randn(1, 3, 224, 224).astype(np.float32) # You may set the backend here desired_backend = "HTP" # Generating a detailed report as is simple as changing the context level with Profiler(context={"level": "detailed"}) as profiler: _ = converted_model(input_array, device=android_device, backend=desired_backend) # Generate the profiler report detailed_model_report = profiler.generate_report() detailed_report_path = str(inceptionv3_artifacts / "detailed_report.json") detailed_model_report.dump(detailed_report_path) Copy to clipboard You can view the detailed report and model using the visualizer. This view enables you to interact with the model and report simultaneously. view(converted_model, reports=detailed_report_path) Copy to clipboard Note The following section is HTP specific. ### Step 8. Performance Reports In this section, we can explore the impact of applying a few HTP backend settings on generated profiling reports. We’ll specialize the compile configuration by enabling fp16 precision and adding soc-specific details to improve performance. First, we’ll retrieve the chipset of the android device and set the soc details. # Retrieve the chipset chipset = android_device.get_chipset() print(f"Device Chipset: {chipset}\n") Copy to clipboard Assuming the device is a Snapdragon 8 Elite android device, the code above will return: Device Chipset: SM8750 Copy to clipboard If you see this value: `UNKNOWN`, then your chipset could not be automatically detected. You can manually identify the chipset for your device from this table: [Chipsets](https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-50/overview.html#supported-snapdragon-devices) Next, we’ll set the soc details for the HTP backend assuming SM8750. Change the chipset below if you are using a different device. # Then set the soc details soc_details = DeviceFactory.get_device_soc_details("HTP", chipset) print(f"Device SoC Details: {soc_details.model_dump_json(indent=4)}\n") Copy to clipboard You can inspect the soc details to see additional details such as num\_of\_hvx threads and vtcm size Device SoC Details: { "chipset": "SM8750", "model": "69", "dsp_arch": 79, "vtcm_size_in_mb": 8, "num_of_hvx_threads": 6, "supports_fp16": true } Copy to clipboard We’ll use the soc details and set the graph to fp16 relaxed precision as before # Create the graph config htp_graph_config = HtpGraphConfig( name="inceptionv3", fp16_relaxed_precision=True, vtcm_size_in_mb=soc_details.vtcm_size_in_mb, hvx_threads=soc_details.num_of_hvx_threads, ) # Create the compile config compile_config = CompileConfig( backend="HTP", soc_details=f"chipset:{chipset}", graph_custom_configs=[htp_graph_config] ) # Set the HTP performance profile to burst. Defaults to HIGH_PERFORMANCE compile_config.device_custom_configs[0].cores[0].perf_profile = PerfProfile.BURST Copy to clipboard Next, we’ll compile the model and generate an Op Trace report. #### Op Trace Reports Op trace provides internal graph execution details in the form of per-operation cycle counts across each hardware thread. This information is useful for identifying performance bottlenecks at an operation level. To generate an op-trace, we need to compile and execute the model in a profiler context. The profiler gathers the report from each call to compile and execute. # Create a random input array input_array = np.random.randn(1, 3, 224, 224).astype(np.float32) with Profiler(context={"level": "detailed", "option": "optrace"}) as profiler: # Compile the model compiled_model = qairt.compile(converted_model, config=compile_config) # Execute the model _ = compiled_model(input_array, device=android_device) # Generate the op trace report op_trace_report = profiler.generate_report() # Save the profiler report as a .json file op_trace_report_path = str(inceptionv3_artifacts / "op_trace_report.json") op_trace_report.dump(op_trace_report_path) Copy to clipboard Note A compile config instance should be passed to the compile function to generate an op trace report. The op trace output is a JSON file that can be viewed with the visualizer. You can interact with the model and observe the op trace nodes graphically by viewing both in the same window. view(converted_model, reports=op_trace_report_path) Copy to clipboard Note To view in separate windows, set options=DisplayOptions(use\_same\_workspace=False) #### Qualcomm Hexagon Analysis Summary (QHAS) Report A QHAS Report includes a summary of overall HTP resource utilization, active cycles, dominant cycle path, and tracing back to the original QNN graph. To view the QHAS report, we can save the report as a .json file and then view it using the visualizer. qhas_report_path = str(inceptionv3_artifacts / "qhas_report.json") op_trace_report.summary.dump(qhas_report_path) view(reports=qhas_report_path) Copy to clipboard Last Published: Aug 19, 2026 [Previous Topic Next Steps](https://docs.qualcomm.com/bundle/publicresource/80-87189-2/topics/on_device_inference.md) [Next Topic Tuning Models](https://docs.qualcomm.com/bundle/publicresource/80-87189-2/topics/tuning_tutorial.md)