# Multicore Device Creation and NSP Selection

## Overview

Some Qualcomm platforms expose multiple HTP/NSP hardware devices, each containing one or
more execution cores. By default, when no explicit device handle is provided, QNN executes
using the default device configuration reported by the backend. The mapping of operations
to cores is determined during context or binary generation. However, certain applications
require explicit control over:

- The NSP/HTP device instance used for execution
- The subset of cores enabled on a device
- Compatibility with pre-serialized binaries targeting a specific number of cores

This section demonstrates how to query platform information, select a specific NSP device
and cores, construct a custom multicore device, and create a device handle suitable for
context creation. This flow extends the example in
`_static/resources/multicore_device_create.txt` with explicit NSP selection support.

## When to Use This Flow

Use this approach if **any** of the following apply:

- Multiple NSP/HTP devices are present on the platform
- Execution must be restricted to specific cores
- A pre-serialized binary was compiled for a known core configuration
- Explicit selection of the NSP device and enabled cores is required at runtime

## Step 1: Retrieve Platform Information

The first step is to retrieve platform information from the backend. This data enumerates
all available NSP/HTP devices and their associated cores.

const QnnDevice_PlatformInfo_t* platformInfo = NULL;
    QnnDevice_getPlatformInfo(&platformInfo);
    Copy to clipboard

The returned `platformInfo` describes the hardware devices recognized by the backend.
Each device entry includes:

- `deviceId` – Identifier of the NSP device instance
- `numCores` – Number of cores available on the device
- `cores[]` – Core descriptors associated with the device

Applications should check the return status of `QnnDevice_getPlatformInfo()` and handle
errors appropriately.

## Step 2: Select Target NSP Device and Cores

Using the platform information, select the desired NSP device and specific cores. The
example below selects two cores from a single NSP device.

At runtime, the application explicitly selects which NSP device and which cores are enabled
for execution. The backend does not automatically select or remap cores.

uint32_t deviceId = <desired_device_id>;
    uint32_t coreA = <core_index_A>;
    uint32_t coreB = <core_index_B>;
    
    QnnDevice_CoreInfo_t coreInfo[2];
    coreInfo[0] =
        platformInfo->v1.hwDevices[deviceId].v1.cores[coreA];
    coreInfo[1] =
        platformInfo->v1.hwDevices[deviceId].v1.cores[coreB];
    Copy to clipboard

Only the cores copied into `coreInfo` will be visible to the QNN runtime.

## Step 3: Construct a Custom Hardware Device Descriptor

Next, populate a `QnnDevice_HardwareDeviceInfo_t` structure describing a logical NSP
device composed of the selected cores.

QnnDevice_HardwareDeviceInfo_t hwDeviceInfo;
    hwDeviceInfo.v1.deviceId =
        platformInfo->v1.hwDevices[deviceId].v1.deviceId;
    hwDeviceInfo.v1.deviceType =
        platformInfo->v1.hwDevices[deviceId].v1.deviceType;
    hwDeviceInfo.v1.numCores = 2;
    hwDeviceInfo.v1.cores    = &coreInfo[0];
    Copy to clipboard

The `deviceType` value is propagated from the backend-reported platform information and
should not be modified by the application. The logical device restricts the set of cores
visible to the QNN runtime without altering the underlying hardware topology.

## Step 4: Assemble a Custom PlatformInfo

Wrap the custom hardware device descriptor in a `QnnDevice_PlatformInfo_t` structure.
This platform info exposes **exactly one** hardware device.

QnnDevice_PlatformInfo_t customPlatformInfo;
    customPlatformInfo.v1.numHwDevices = 1;
    customPlatformInfo.v1.hwDevices    = &hwDeviceInfo;
    Copy to clipboard

## Step 5: Create the Multicore Device Handle

Pass the custom platform information to `QnnDevice_create()` using
`QNN_DEVICE_CONFIG_OPTION_PLATFORM_INFO`.

QnnDevice_Config_t deviceConfig;
    deviceConfig.option       =
        QNN_DEVICE_CONFIG_OPTION_PLATFORM_INFO;
    deviceConfig.hardwareInfo = &customPlatformInfo;
    
    QnnDevice_Config_t* configList[] = {
        &deviceConfig,
        NULL
    };
    
    Qnn_DeviceHandle_t multicoreDeviceHandle;
    QnnDevice_create(logHandle, configList,
                     &multicoreDeviceHandle);
    Copy to clipboard

The returned device handle represents a logical NSP device with the selected core
configuration.

## Step 6: Use the Device Handle During Context Creation

The custom device handle **must** be provided when creating a context, including when
loading a pre-serialized binary.

QnnContext_createFromBinary(
        backendHandle,
        multicoreDeviceHandle,
        NULL,
        binaryBuffer,
        &contextHandle);
    Copy to clipboard

This ensures execution occurs on the specified NSP device and selected cores.

## Important Notes

Warning

The number of cores (numCores) exposed by the device handle must match the number of cores
encoded in the pre-serialized binary. If these values do not match, context deserialization
will fail.

Additional considerations:

- To select a **single NSP core**, set `numCores = 1` and provide one core descriptor.
- The same flow applies for selecting a **single NSP device**.
- This mechanism allows applications to restrict execution to a subset of the
backend-reported cores available on a device.

When no device handle is provided during context creation, QNN uses the default device
configuration, which corresponds to Device 0 with Core 0 enabled.

`QnnDevice_create()` provides low-level control over NSP/HTP execution and is recommended
when explicit device or core selection is required.

Last Published: Jun 04, 2026

[Previous Topic
How to Use the Sample App](https://docs.qualcomm.com/bundle/publicresource/80-63442-10/topics/tutorial_tutorial_sample_app_linux.md) [Next Topic
Sample App Tutorial](https://docs.qualcomm.com/bundle/publicresource/80-63442-10/topics/sample_app.md)