Skip to content

feat(qairt): expose HTP multicore support in geniex-qairt-plugin #1312

Description

Summary

geniex-qairt never requests multiple HTP (NSP) cores, so QAIRT models always execute on a single core. There is no way — from the CLI, the SDK, or the model bundle — to ask for multicore execution.

Repro

User reported that when running Qwen3-VL-4B-Instruct through the QAIRT plugin, the QNN backend reports:

238.9ms [VERBOSE] Error code 1000 returned for property query with key = 304
...
240.8ms [VERBOSE]  <V> Multicore support is unavailable

and the model runs on one core only.

The bundle's HTP config declares a single core, and there is no documented way to add more:

{
  "devices": [
    {
      "soc_model": 77,
      "dsp_arch": "v73",
      "cores": [
        { "core_id": 0, "perf_profile": "burst", "rpc_control_latency": 100 }
      ]
    }
  ],
  "memory": { "mem_type": "shared_buffer" },
  "context": { "weight_sharing_enabled": true }
}

Slack discussion is here: https://qualcomm-ai-hub.slack.com/archives/C0BDK2Y7W6T/p1785836958145259

Where the gap is

  1. No graph config is ever set. QNN_HTP_GRAPH_CONFIG_OPTION_NUM_CORES is present in the vendored header (third-party/geniex-qairt/qnn-api/include/HTP/QnnHtpGraph.h:186) but is referenced nowhere in core/ or qnn-api/src/. Same for QNN_HTP_GRAPH_CONFIG_OPTION_PARALLEL_GRAPH_EXECUTION_CONFIG.

  2. initializeHtp is called with hardcoded arguments. core/src/model_init.cpp:98-117 passes a fixed literal for every parameter after ext_cfg (spill-fill size, mmap budget, etc.) and never builds a graph-config list. The prebuilt-context path goes through contextCreateFromBinary, so the graph inherits whatever core count the context binary was compiled with.

  3. The HTP JSON is opaque to GenieX. modelConfigFromDirectory picks up htp_backend_ext_config.json when it sits beside the bundle (core/src/llm/llm_spec_loader.cpp:547-548) and forwards the path to BackendExtensionsConfigs (model_init.cpp:96). Parsing happens inside the closed-source QnnHtpNetRunExtensions library, so there is no GenieX-side validation, no defaulting, and no diagnostic when a requested core is unavailable.

  4. The reported core count is read but unused for scheduling. qnn-api/src/QnnApi.cpp:1379 reads platformInfo->v1.hwDevices->v1.numCores solely to disable I/O memory estimation. It is never logged and never used to pick a core count.

Asks

  • Check if Genie has already implemented multicore support, if so, you can refer to its source code.
  • Plumb a core-count / multicore knob through the qairt-plugin (ModelConfig → graph configs → QNN_HTP_GRAPH_CONFIG_OPTION_NUM_CORES), rather than leaving it entirely to the prebuilt binary.
  • Log the device-reported numCores and the effective core count at init, so "1 core" is visible without a verbose QNN trace.
  • Warn (don't silently ignore) when htp_backend_ext_config.json requests cores the device doesn't expose.
  • Test on real devices or QDC to make sure multicore inference works correctly.
  • Document the multicore story for QAIRT bundles: what is fixed at context-binary generation time versus what is settable at load time, and which SoCs expose more than one NSP core. Suggested homes: third-party/geniex-qairt/docs/README.md (which lists htp_backend_ext_config.json without documenting its schema) and notes/run.md.

Notes / open questions

The Error code 1000 ... key = 304 line immediately preceding Multicore support is unavailable is the HTP backend querying a DSP property the skel doesn't answer, i.e. the runtime concluded multicore is unavailable on this device/driver — independent of the JSON contents. Worth confirming whether multicore for this class of bundle is achievable at all at load time, or whether it strictly requires regenerating the context binaries with a multicore graph config on a SoC with more than one NSP core. If it's generation-time only, the fix is primarily documentation plus a clear diagnostic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions