# QNN LPAI Backend FAQs **How do I create handles for QNN components?** To initialize QNN components, the following APIs must be used: - `QnnBackend_create()`: Instantiates the LPAI backend handle, which manages backend-specific operations and resources. - `QnnSystemContext_create()`: Creates the QNN system context handle, used to access serialized context binary metadata via `QnnSystemContext_getBinaryInfo()`. These handles are foundational for interacting with the QNN runtime and must be created before any graph execution or profiling. **What does it mean if ``QnnInterface\_getProviders()`` returns zero providers?** A return value of zero providers typically indicates that the backend libraries are either missing, not properly installed, or not discoverable by the runtime. To resolve this issue: - Ensure that the required backend shared libraries (e.g., `libQnnLpai.so`) are present on the target system. - Verify that the environment variable `LD_LIBRARY_PATH` includes the directory containing the QNN backend libraries. - Confirm that the backend ID `QNN_LPAI_BACKEND_ID` is correctly specified when querying providers. **Why is buffer alignment important?** Proper buffer alignment is essential to ensure correct execution and compatibility with the LPAI backend. Misaligned buffers can lead to invalid memory access and runtime errors, especially when interfacing with hardware accelerators that enforce strict alignment constraints. To determine alignment requirements: - Use `QnnBackend_getProperty()` with the property `QNN_LPAI_BACKEND_GET_PROP_ALIGNMENT_REQ`. - This query returns: - **Start Address Alignment**: Specifies the required alignment for the base address of each buffer. - **Buffer Size Alignment**: Specifies the required alignment for the total size of each buffer. **What are the consequences of not meeting alignment requirements?** Failure to comply with alignment constraints may result in: - Application crashes due to invalid or misaligned memory access. - Backend API errors during buffer registration or graph execution. - Incorrect or undefined inference results due to improper memory handling. It is strongly recommended to query and apply alignment requirements before allocating memory for input, output, or intermediate buffers. **Can multiple backends be used concurrently?** No. QNN supports only one backend per context. Each context is tightly coupled with a single backend implementation. To use multiple backends within the same application: - Create separate QNN contexts for each backend. - Ensure that each context is independently initialized and managed. **Can graphs be modified after context finalization?** No. Once a context is created from a binary using `QnnContext_createFromBinary()`, it becomes immutable. This means: - The graph structure, layers, and parameters cannot be modified. - Any changes to the model require regenerating the context binary and reinitializing the context. This immutability ensures consistency and performance optimization during inference. **Is ``QnnGraph\_execute()`` a blocking call?** By default, the LPAI backend runs asynchronously (`disable_async` defaults to `false`), so `QnnGraph_execute()` submits work and returns before execution completes. Callers must synchronize before consuming output buffers. **Synchronization options:** - **Simplest approach**: Set `disable_async: true` in the `lpai_private` backend configuration section (see below). This makes `QnnGraph_execute()` fully blocking and is recommended for most applications. - **Asynchronous operation**: When async mode is required, refer to the SampleApp (`${QNN_SDK_ROOT}/examples/QNN/SampleApp/SampleAppLPAI`) for the platform-appropriate synchronization pattern. To force fully synchronous, blocking behavior, set `disable_async: true` in the `lpai_private` section of the backend configuration file: { "lpai_private": { "disable_async": true } } Copy to clipboard With `disable_async: true`, `QnnGraph_execute()` will not return until the entire graph execution is complete. **Where is the output stored after execution?** Output data is written to the client-provided output buffers that were registered during initialization. These buffers must: - Be properly allocated and aligned according to backend requirements. - Remain valid and accessible throughout the execution lifecycle. The application is responsible for managing the lifecycle and memory of these buffers. **Is the order of deinitialization important?** Yes. Resources must be released in the reverse order of their allocation to avoid dependency violations or memory access errors. Recommended deinitialization order: 1. Release graph and context resources. 2. Destroy the system context handle. 3. Destroy the backend handle. Improper deinitialization may result in memory leaks, dangling pointers, or undefined behavior. **Can a context be reused after deinitialization?** No. Once a context is released using `QnnContext_free()`, it is no longer valid and cannot be reused. - To execute the same model again, the context must be recreated using `QnnContext_createFromBinary()`. - Ensure that all associated resources are reinitialized as needed. **What is ``platform\_config\_file`` and when should I use it?** `platform_config_file` is an optional field in the `lpai_backend` section of the LPAI configuration file. It points to a JSON file that supplies hardware- and platform-specific overrides (e.g., memory layout, clock settings) to the backend, replacing built-in defaults for that parameter. Use it when: - Your target device variant has non-default hardware settings that differ from SDK defaults. - The platform/BSP team has provided a device-specific configuration file. - You need to test different hardware configurations without recompiling the backend. If the file path is incorrect or the file is missing, the backend will fail at initialization with an error indicating the file cannot be opened. Always use absolute paths or paths relative to the working directory of the tool. **What is the difference between ``enable\_core\_selection`` and ``core\_selection``?** These are two separate parameters used at different stages: | Parameter | Section | Type | Purpose | | --- | --- | --- | --- | | `enable_core_selection` | `lpai_graph.prepare` | string
(e.g. `"0,1"`) | Restricts offline compilation to the listed
core(s). Affects the generated binary. | | `core_selection` | `lpai_graph.execute` | integer
(bitmask) | Bitmask selecting which core to use at
runtime (`0x01` = core 0, `0x02` = core 1). | Important The runtime `core_selection` must target a core that was included in `enable_core_selection` at compile time. Requesting a core at runtime that was not compiled into the binary will cause execution to fail. **What does ``disable\_async`` in ``lpai\_private`` do?** Setting `disable_async: true` forces the LPAI backend to execute graphs synchronously, making `QnnGraph_execute()` block until completion. The default is `false` (asynchronous execution). Use synchronous mode when: - Simplifying multi-threaded application logic by eliminating explicit synchronization. - Debugging execution order or timing issues. - Profiling where precise per-call timing is needed. Last Published: Sep 03, 2026 [Previous Topic LPAI](https://docs.qualcomm.com/bundle/publicresource/80-63442-10/topics/lpai_backend.md) [Next Topic QNN LPAI Backend Glossary](https://docs.qualcomm.com/bundle/publicresource/80-63442-10/topics/lpai_backend_glossary.md)