Qualcomm® AI Engine Direct 使用手册(4)
4.1.2 HTP (续)
QNN HTP 性能基础架构 API
客户端可以调用 QnnDevice_getInfrastruct 加载 QNN HTP 库后,然后调用可用的方法 文件 QnnHtpPerfInfrastruct.h 的程序列表。这些 API 允许客户端控制 CPU 和 HTP 加速器用于性能目的的系统设置。 一些用例是:
-
通过控制核心时钟和电压角来设置投票策略。
-
设置 DCVS 模式以实现适用于用例的不同性能设置。
-
设置每个会话的特定 RPC 控制延迟以控制 CPU 低功耗模式并减少 CPU 唤醒延迟对 FastRPC 的影响。建议对延迟关键的应用程序投票支持更大的 小于 0 且小于 200 us;中等延迟要求可以投票超过200 us或者通过 默认 0 us,无需特殊设置。
笔记
不支持设置加速器的线程数。 QNN Perf 基础设施直接映射到 CPU 端的快速 RPC 功能,而 HTP 端映射到 HAP_Power DCVS v3。 有关电压角和 DCVS 模式的详细配置,请参阅 HAP_power_set API 上的 Hexagon SDK 文档。
QNN 通过 API 和参数提供接口来设置所需的性能设置。性能参数由时钟频率角组成 cDSP 总线和内核、睡眠延迟以及 DCVS 控制参数的设置。 DCVS 是动态电压缩放,其中 cDSP 算法 确定最佳拐角设置。
性能参数表显示各种性能配置文件的设置。 使用 QNN API,我们可以设置这些性能设置。以下是性能设置所需的参数以及启用性能基础架构中的参数所需的相关 API。
时钟角设置 - 用于设置总线和核心操作角以进行性能设置。
QnnHtpPerfInfrastructure_DcvsV3_t dcvsV3Config;
总线参数 - 总线参数用于设置总线时钟参数。
dcvsV3Config.setBusParams = 1; //True to consider Bus parameter otherwise False. refer QnnHtpPerfInfrastructure.h
dcvsV3Config.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_TURBO;
dcvsV3Config.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_TURBO;
dcvsV3Config.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_TURBO;
核心参数 - 核心参数用于设置核心时钟参数。
dcvsV3Config.setCoreParams = 1; //True to consider Core parameter otherwise False. refer QnnHtpPerfInfrastructure.h
dcvsV3Config.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_TURBO;
dcvsV3Config.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_TURBO;
dcvsV3Config.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_TURBO;
DCVS 启用 - setDcvsEnable 和 dcvsEnable 参数使用户能够投票支持 DCVS 参与。
dcvsV3Config.setDcvsEnable = 1;
dcvsV3Config.dcvsEnable = 0; // zero value means to disable dcvs
睡眠延迟 - setSleepLatency 和 sleepLatency 参数可用于请求以微秒为单位的睡眠延迟。
dcvsV3Config.setSleepLatency = 1;
dcvsV3Config.sleepLatency = 100; // give sleep latency value, ranges 10-65535 us
睡眠禁用 - setSleepDisable 和 sleepDisable 参数使用户能够在 HTP 中禁用睡眠(所有 LPM 模式)。
dcvsV3Config.setSleepDisable = 1;
dcvsV3Config.sleepDisable = 1; // non zero value means disable sleep
电源模式 - 当 set_dcvs_enable 和 dcvs_enable 均设置为 TRUE 时,powerMode 参数允许用户请求特定的 DCVS 模式。
dcvsV3Config.powerMode = QNN_HTP_PERF_INFRASTRUCTURE_POWERMODE_PERFORMANCE_MODE;
QNN HTP 性能基础架构 API 为客户端提供接口来控制 QNN HTP 加速器的性能和系统设置。
创建 Power Config ID - 此 API 用于关联唯一的客户端上下文,以便后续 API 可以使用创建的 ID 引用相同的上下文。
Qnn_ErrorHandle_t createPowerConfigId(uint32_t deviceId, uint32_t coreId, uint32_t* powerConfigId);
//Usage
uint32_t powerConfigId; // Below api creates the power config id.
uint32_t deviceId = 0;
uint32_t coreId = 0;
sample_app::StatusCode sample_app::QnnSampleApp::createPowerConfigId() {
QnnDevice_Infrastructure_t deviceInfra = nullptr;
QnnInterface_t qnnInterface;
Qnn_ErrorHandle_t devErr = qnnInterface.QNN_INTERFACE_VER_NAME.deviceGetInfrastructure(&deviceInfra);
if (devErr != QNN_SUCCESS) {
QNN_ERROR("device error");
return StatusCode::FAILURE;
}
QnnHtpDevice_Infrastructure_t *htpInfra = static_cast<QnnHtpDevice_Infrastructure_t *>(deviceInfra);
QnnHtpDevice_PerfInfrastructure_t perfInfra = htpInfra->perfInfra;
Qnn_ErrorHandle_t perfInfraErr = perfInfra.createPowerConfigId(deviceId, coreId, &powerConfigId);
if (perfInfraErr != QNN_SUCCESS) {
QNN_ERROR("createPowerConfigId failed");
return StatusCode::FAILURE;
}
return StatusCode::SUCCESS;
}
设置电源配置 - 此 API 允许客户端设置系统电源配置,以启用不同的性能模式。 该API使用HAP_power_dcvs_v3_payload结构体来配置HAP电源参数。详细HAP功率参数说明请 请参阅 Hexagon SDK HAP_power_dcvs_v3_payload 文档。下面的 setPowerConfig API 具有提供高性能的设置, 用户可以根据自己的需求尝试不同的设置。
Qnn_ErrorHandle_t setPowerConfig(uint32_t powerConfigId, const QnnHtpPerfInfrastructure_PowerConfig_t** config);
//Usage
sample_app::StatusCode sample_app::QnnSampleApp::setPowerConfig() {
QnnDevice_Infrastructure_t deviceInfra = nullptr;
QnnInterface_t qnnInterface;
Qnn_ErrorHandle_t devErr = qnnInterface.QNN_INTERFACE_VER_NAME.deviceGetInfrastructure(&deviceInfra);
if (devErr != QNN_SUCCESS) {
QNN_ERROR("device error");
return StatusCode::FAILURE;
}
QnnHtpDevice_Infrastructure_t *htpInfra = static_cast<QnnHtpDevice_Infrastructure_t *>(deviceInfra);
QnnHtpDevice_PerfInfrastructure_t perfInfra = htpInfra->perfInfra;
QnnHtpPerfInfrastructure_PowerConfig_t powerConfig;
memset(&powerConfig, 0, sizeof(powerConfig));
powerConfig.option = QNN_HTP_PERF_INFRASTRUCTURE_POWER_CONFIGOPTION_DCVS_V3;
powerConfig.dcvsV3Config.dcvsEnable = 0; //True to enable Dcvs, False to disbale
powerConfig.dcvsV3Config.setDcvsEnable = 1;
powerConfig.dcvsV3Config.contextId = powerConfigId; //use the power config id created
// refer QnnHtpPerfInfrastructure.h
powerConfig.dcvsV3Config.powerMode = QNN_HTP_PERF_INFRASTRUCTURE_POWERMODE_PERFORMANCE_MODE;
powerConfig.dcvsV3Config.setSleepLatency = 1; //True to consider Latency parameter otherwise False
powerConfig.dcvsV3Config.setBusParams = 1; //True to consider Bus parameter otherwise False
powerConfig.dcvsV3Config.setCoreParams = 1; //True to consider Core parameter otherwise False
powerConfig.dcvsV3Config.sleepDisable = 1; //True to disable sleep, False to re-enable sleep
powerConfig.dcvsV3Config.setSleepDisable = 1; //True to consider sleep disable/enable parameter otherwise False
//Set Sleep latency parameter
powerConfig.dcvsV3Config.sleepLatency = 40; // set dsp sleep latency ranges 10-65535 micro sec, refer hexagon sdk
//set Bus Clock Parameters (refer QnnHtpPerfInfrastructure.h)
powerConfig.dcvsV3Config.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
powerConfig.dcvsV3Config.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
powerConfig.dcvsV3Config.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
//set Core Clock Parameters (refer QnnHtpPerfInfrastructure.h)
powerConfig.dcvsV3Config.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
powerConfig.dcvsV3Config.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
powerConfig.dcvsV3Config.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
// Set power config with different performance parameters
const QnnHtpPerfInfrastructure_PowerConfig_t *powerConfigs[] = {&powerConfig, NULL};
Qnn_ErrorHandle_t perfInfraErr = perfInfra.setPowerConfig(powerConfigId, powerConfigs);
if (perfInfraErr != QNN_SUCCESS) {
QNN_ERROR("setPowerConfig failed");
return StatusCode::FAILURE;
}
return StatusCode::SUCCESS;
}
销毁电源配置 ID - 此 API 允许客户端销毁之前创建的电源配置 ID。
Qnn_ErrorHandle_t destroyPowerConfigId(uint32_t powerConfigId);
//Usage
sample_app::StatusCode sample_app::QnnSampleApp::destroyPowerConfigId() {
QnnDevice_Infrastructure_t deviceInfra = nullptr;
QnnInterface_t qnnInterface;
Qnn_ErrorHandle_t devErr = qnnInterface.QNN_INTERFACE_VER_NAME.deviceGetInfrastructure(&deviceInfra);
if (devErr != QNN_SUCCESS) {
QNN_ERROR("device error");
return StatusCode::FAILURE;
}
QnnHtpDevice_Infrastructure_t *htpInfra = static_cast<QnnHtpDevice_Infrastructure_t *>(deviceInfra);
QnnHtpDevice_PerfInfrastructure_t perfInfra = htpInfra->perfInfra;
Qnn_ErrorHandle_t perfInfraErr = perfInfra.destroyPowerConfigId(powerConfigId);
if (perfInfraErr != QNN_SUCCESS) {
QNN_ERROR("destroyPowerConfigId failed");
return StatusCode::FAILURE;
}
return StatusCode::SUCCESS;
}
除了上述 API 之外,用户还可以使用 RPC 轮询并控制延迟,以在高性能模式下获得更好的性能。 RPC 轮询和延迟设置 - rpcPollingTimeConfig 参数可用于请求以微秒为单位的 rpc 轮询时间, rpcControlLatencyConfig 参数可用于减少 CPU 唤醒延迟。
sample_app::StatusCode sample_app::QnnSampleApp::setRpcLatencyAndPolling() {
QnnDevice_Infrastructure_t deviceInfra = nullptr;
QnnInterface_t qnnInterface;
Qnn_ErrorHandle_t devErr = qnnInterface.QNN_INTERFACE_VER_NAME.deviceGetInfrastructure(&deviceInfra);
if (devErr != QNN_SUCCESS) {
QNN_ERROR("device error");
return StatusCode::FAILURE;
}
QnnHtpDevice_Infrastructure_t *htpInfra = static_cast<QnnHtpDevice_Infrastructure_t *>(deviceInfra);
QnnHtpDevice_PerfInfrastructure_t perfInfra = htpInfra->perfInfra;
// set RPC Control Latency
QnnHtpPerfInfrastructure_PowerConfig_t rpcControlLatency; // refer QnnHtpPerfInfrastructure.h
memset(&rpcControlLatency, 0, sizeof(rpcControlLatency));
笔记
Windows 和 QNX 平台不支持 RPC 延迟和轮询
有关上述所有性能设置参数的详细信息,请参阅 hexagon sdk 文档。
这些性能 API 可用于提高性能。下面显示了使用这些 API 来提高图形执行性能的示例应用程序。
#include <HTP/QnnHtpPerfInfrastructure.h>
#include <QnnInterface.h>
#include <HTP/QnnHtpDevice.h>
void example_application () {
-----
std::unique_ptr<sample_app::QnnSampleApp> app;
-----
-----
app->createPowerConfigId(); // Create power config id before voting
app->setRpcLatencyAndPolling(); // Use RPC polling and latency for high performing modes
app->setPowerConfig(); // Set the different configurations for performance settings
-----
app->executeGraphs(); // Execute the graphs
-----
app->destroyPowerConfigId(); // Destroy the power config id
-----
-----
}
上面显示的示例应用程序纯粹出于使用目的。客户可以在这些 API 中使用自己的性能设置,并根据自己的要求使用它们。
用例示例
Voting at Every Inference- 此案例描述了设置某些性能设置(可能更高)的简单用例 性能配置)在执行推理请求之前,然后是另一个性能设置(可能较低 性能配置)。下图展示了每次推理时设置性能设置的调用流程。
Sustain Setting for Multiple Inference- 此案例描述了性能设置的维持(可能是更高的性能配置) 用于多重推论。这可以使用系统定时器来实现。客户端可以启动计时器一段时间 (高于连续推理之间的预期时间)设置性能投票后(可能更高的性能)。 当计时器到期或客户端请求更改时,此投票将被重置(可能性能较低) 性能设置。下图展示了多重推理维持性能设置的调用流程。
exhale_typedef_QnnHtpDevice_8h_1a971db463066e1f912bd98b4f74393dcf 是后端特定子组件 结构 QnnDevice_HardwareDeviceInfo_t。这些结构的信息由 用于离线操作的客户端,可以通过调用QnnDevice_getPlatformInfo()来填充
选项名称 | 选项 说明 | 默认 | 何时使用 |
---|---|---|---|
QNN_HTP_DEVICE_CONFIG_OPTION_PCIE_DEVICE_INFO_EXTENSION | 该结构提供了有关与 PCIe 总线连接的设备的信息:VTCM 大小(以 MB 为单位)、socModel、 PCIe 设备上的 NSP 数量、签名 PD 支持、DLBC 支持、设备架构 | 无效的 | 对于在线操作,调用者应从 QnnDevice_getPlatformInfo 获取这些信息。为了 离线操作,调用者需要创建这个结构并填写正确的 QnnDevice_create 的信息 |
QNN_HTP_DEVICE_CONFIG_OPTION_ON_CHIP_DEVICE_INFO_EXTENSION | 此结构提供有关 SoC 内部 NSP 设备的信息:VTCM 大小(以 MB 为单位)、socModel、签名 PD 支持、DLBC 支持、设备架构 | 无效的 | 对于在线操作,调用者应从 QnnDevice_getPlatformInfo 获取这些信息。为了 离线操作,调用者需要创建这个结构并填写正确的 QnnDevice_create 的信息 |
QNN HTP精密
QNN HTP 支持运行具有浮点和定点数据类型混合的图形。 当使用带有 FP16 操作的混合精度图时,设置“relaxed_ precision_flag”。
QNN HTP 可以支持在选定的 Qualcomm SoC 上运行 float32 图形。客户端预计设置 具有 float32 张量和 QNN HTP 加速器的 QNN 图将最终确定并执行 QNN 图 使用 float16 数学。
尝试运行 float32 图形的 QNN HTP 客户端应调用 QnnGraph_create() 带有 Struct QnnGraph_Config_t 其中将包括 Struct QnnHtpGraph_CustomConfig_t 使用配置来设置 枚举 Qnn_Precision_t。 预期设置的精度值为 QNN_PRECISION_FLOAT16。
客户端用法如下所示:
QnnHtpGraph_CustomConfig_t customConfig;
customConfig.option = QNN_HTP_GRAPH_CONFIG_OPTION_PRECISION;
customConfig.precision = QNN_PRECISION_FLOAT16;
QnnGraph_Config_t graphConfig;
graphConfig.option = QNN_GRAPH_CONFIG_OPTION_CUSTOM;
graphConfig.customConfig = &customConfig;
const QnnGraph_Config_t* pGraphConfig[] = {&graphConfig, NULL};
当精度值设置为 QNN_PRECISION_FLOAT16 时,QNN HTP 后端将转换用户提供的 float32 输入 在 QnnGraph_execute() 中转换为 float16 并 使用 float16 数学执行图形。最终输出作为 float32 输出提供给用户。
QNN HTP FP16 SM8550 和 SM8650 输出差异
SM8550 和 SM8650 之间 HTP 后端浮点模型的输出会略有不同。这可能 导致两者之间存在轻微的精度差异,尽管其中一个并不比另一个更准确。这是因为 硬件的变化改变了一些计算的关联性以实现更高的效率。
笔记
同样的观点也可以在“HTP Float16”幻灯片的 2.9.1 发行说明中找到。
QNN HTP 深度学习带宽压缩 (DLBC)
深度学习带宽压缩是一项允许压缩输入的功能,以便 处理带宽可以降低。 QNN HTP 提供了一个配置选项供用户打开 通过客户端使用打开或关闭 DLBC,如下所示:
QnnHtpGraph_CustomConfig_t customConfig;
customConfig.option = QNN_HTP_GRAPH_CONFIG_OPTION_OPTIMIZATION;
customConfig.optimizationOption.type = QNN_HTP_GRAPH_OPTIMIZATION_TYPE_ENABLE_DLBC;
customConfig.optimizationOption.floatValue = 1.0; // set to 0 to turn off
QnnGraph_Config_t graphConfig;
graphConfig.option = QNN_GRAPH_CONFIG_OPTION_CUSTOM;
graphConfig.customConfig = &customConfig;
const QnnGraph_Config_t* pGraphConfig[] = {&graphConfig, NULL};
对于 DLBC 的离线准备,后端特定的配置文件应指定以下选项以及任何其他所需的选项:
{
"graphs": {
"vtcm_mb": ...,
"graph_names": [...],
"dlbc": 1 // set to 1 to turn on
...
},
"devices": [
{
...
...
}
]
}
请注意,上述配置结构将从 SDK 2.20 版本开始弃用,支持的新配置如下所示:
{
"graphs": [
{
"vtcm_mb": ...,
"graph_names": [...],
"dlbc": 1 // set to 1 to turn on
...
}
],
"devices": [
{
...
...
}
]
}
值 0 将关闭该功能,任何大于或等于 1.0 的正浮点值将打开该功能 特征。默认情况下,DLBC 将处于禁用状态,即未提供配置选项时。
QNN HTP - 设置 HVX 线程数
此选项允许用户为特定图形设置 HVX 线程数。推论 时间取决于所使用的 HVX 线程的数量。如果使用更多线程,则执行 图表的时间会更短(即更快)。
可以为在线和离线准备情况配置 HVX 线程数。这 在二进制 blob 创建期间在配置中传递的值是写入序列化 blob 中的值。 可以通过将新配置传递到 QnnGraph_setConfig QNN 来重新配置 HVX 线程数 API。
需要注意的是,线程数无法配置/重新配置 在第一次执行该特定图之后;它必须先于它。
用户可以设置自定义选项,如下所示:
QnnHtpGraph_CustomConfig_t customConfig;
customConfig.option = QNN_HTP_GRAPH_CONFIG_OPTION_NUM_HVX_THREADS;
customConfig.numHvxThreads = 3; // set a number. MAX = number of HVX HW blocks for that SoC
QnnGraph_Config_t graphConfig;
graphConfig.option = QNN_GRAPH_CONFIG_OPTION_CUSTOM;
graphConfig.customConfig = &customConfig;
const QnnGraph_Config_t* pGraphConfig[] = {&graphConfig, NULL};
后端特定的配置文件应指定以下选项以及 任何其他所需的选项。在离线准备的情况下,如果“hvx_threads”选项 未提供时,默认值 4 会写入二进制 blob。如果是 在线准备,如果配置未设置任何数量的 hvx 线程,则支持最大数量 在推理期间使用该 SoC 的值。
Config 可用于设置 HVX 线程数,如下所示:
{
"graphs": {
"vtcm_mb":...,
"graph_names":[...],
"hvx_threads":3 // set a number. MAX = number of HVX HW blocks for that SoC
...
},
"devices": [
{
...
...
}
]
}
请注意,上述配置结构将从 SDK 2.20 版本开始弃用,支持的新配置如下所示:
{
"graphs": [
{
"vtcm_mb":...,
"graph_names":[...],
"hvx_threads":3 // set a number. MAX = number of HVX HW blocks for that SoC
...
}
],
"devices": [
{
...
...
}
]
}