Skip to content

Commit d9f379c

Browse files
quic-calvnguyquic_calvnguy
andauthored
[QNN-EP] Disable DSPQ polling when needed (microsoft#26468)
### Description Create new class to handle HTP power config updates Only update if there are changes to power config settings On dynamic htp perf mode updates, disable DSPQ polling if perf mode is not burst ### Motivation and Context Currently, if a session has set the performance mode to burst then changed the performance mode to anything else, DSPQ polling will be enabled and never disabled. This change is to allow disabling of DSPQ polling when the performance mode is not burst, even on updates. --------- Co-authored-by: quic_calvnguy <quic_calvnguy@quic_inc.com>
1 parent 669128a commit d9f379c

7 files changed

Lines changed: 416 additions & 234 deletions

File tree

onnxruntime/core/providers/qnn/builder/qnn_backend_manager.cc

Lines changed: 20 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,192 +1384,19 @@ Status QnnBackendManager::CreateHtpPowerCfgId(uint32_t device_id, uint32_t core_
13841384
return Status::OK();
13851385
}
13861386

1387-
Status QnnBackendManager::SetHtpPowerConfig(uint32_t htp_power_config_client_id,
1388-
HtpPerformanceMode htp_performance_mode) {
1387+
Status QnnBackendManager::SetHtpPowerConfigs(uint32_t htp_power_config_client_id,
1388+
HtpPerformanceMode htp_performance_mode,
1389+
uint32_t rpc_polling_time,
1390+
uint32_t rpc_control_latency) {
13891391
// This function is called in QNN EP's OnRunStart() even if QNN backend setup failed and the model is assigned
13901392
// to a different EP. Therefore, we have to check that backend setup actually completed before trying to
13911393
// set an HTP power config ID. Otherwise, this causes a segfault because the QNN backend lib is unloaded.
13921394
ORT_RETURN_IF_NOT(backend_setup_completed_, "Cannot set HTP power config ID if backend setup is not complete.");
1393-
QnnDevice_Infrastructure_t qnn_device_infra = nullptr;
1394-
auto status = qnn_interface_.deviceGetInfrastructure(&qnn_device_infra);
1395-
ORT_RETURN_IF(QNN_SUCCESS != status, "backendGetPerfInfrastructure failed.");
1396-
1397-
auto* htp_infra = static_cast<QnnHtpDevice_Infrastructure_t*>(qnn_device_infra);
1398-
ORT_RETURN_IF(QNN_HTP_DEVICE_INFRASTRUCTURE_TYPE_PERF != htp_infra->infraType,
1399-
"HTP infra type = ", htp_infra->infraType, ", which is not perf infra type.");
1400-
QnnHtpDevice_PerfInfrastructure_t& htp_perf_infra = htp_infra->perfInfra;
14011395

1402-
constexpr const int kNumConfigs = 1;
1403-
std::vector<QnnHtpPerfInfrastructure_PowerConfig_t> power_configs(
1404-
kNumConfigs);
1405-
QnnHtpPerfInfrastructure_PowerConfig_t& dcvs_config = power_configs[0];
1406-
dcvs_config.option = QNN_HTP_PERF_INFRASTRUCTURE_POWER_CONFIGOPTION_DCVS_V3;
1407-
QnnHtpPerfInfrastructure_DcvsV3_t& dcvs_v3 = dcvs_config.dcvsV3Config;
1408-
dcvs_v3.contextId = htp_power_config_client_id;
1409-
dcvs_v3.setSleepDisable = 0;
1410-
dcvs_v3.sleepDisable = 0;
1411-
dcvs_v3.setDcvsEnable = 1;
1412-
dcvs_v3.powerMode = QNN_HTP_PERF_INFRASTRUCTURE_POWERMODE_PERFORMANCE_MODE;
1413-
// choose performance mode
1414-
switch (htp_performance_mode) {
1415-
case HtpPerformanceMode::kHtpBurst:
1416-
case HtpPerformanceMode::kHtpSustainedHighPerformance:
1417-
dcvs_v3.setSleepLatency = 1; // true
1418-
dcvs_v3.sleepLatency = kSleepMinLatency;
1419-
dcvs_v3.dcvsEnable = kDcvsDisable;
1420-
dcvs_v3.setBusParams = 1;
1421-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
1422-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
1423-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
1424-
dcvs_v3.setCoreParams = 1;
1425-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
1426-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
1427-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_MAX_VOLTAGE_CORNER;
1428-
break;
1429-
case HtpPerformanceMode::kHtpHighPerformance:
1430-
dcvs_v3.setSleepLatency = 1; // true
1431-
dcvs_v3.sleepLatency = kSleepLowLatency;
1432-
dcvs_v3.dcvsEnable = kDcvsDisable;
1433-
dcvs_v3.setBusParams = 1;
1434-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_TURBO;
1435-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_TURBO;
1436-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_TURBO;
1437-
dcvs_v3.setCoreParams = 1;
1438-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_TURBO;
1439-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_TURBO;
1440-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_TURBO;
1441-
break;
1442-
case HtpPerformanceMode::kHtpBalanced:
1443-
dcvs_v3.setSleepLatency = 1; // true
1444-
dcvs_v3.sleepLatency = kSleepMediumLatency;
1445-
dcvs_v3.dcvsEnable = kDcvsEnable;
1446-
dcvs_v3.setBusParams = 1;
1447-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_NOM_PLUS;
1448-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_NOM_PLUS;
1449-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_NOM_PLUS;
1450-
dcvs_v3.setCoreParams = 1;
1451-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_NOM_PLUS;
1452-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_NOM_PLUS;
1453-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_NOM_PLUS;
1454-
break;
1455-
case HtpPerformanceMode::kHtpLowBalanced:
1456-
dcvs_v3.setSleepLatency = 1; // true
1457-
dcvs_v3.sleepLatency = kSleepMediumLatency;
1458-
dcvs_v3.dcvsEnable = kDcvsEnable;
1459-
dcvs_v3.setBusParams = 1;
1460-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_NOM;
1461-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_NOM;
1462-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_NOM;
1463-
dcvs_v3.setCoreParams = 1;
1464-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_NOM;
1465-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_NOM;
1466-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_NOM;
1467-
break;
1468-
case HtpPerformanceMode::kHtpHighPowerSaver:
1469-
dcvs_v3.setSleepLatency = 1; // true
1470-
dcvs_v3.sleepLatency = kSleepMediumLatency;
1471-
dcvs_v3.dcvsEnable = kDcvsEnable;
1472-
dcvs_v3.setBusParams = 1;
1473-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_SVS_PLUS;
1474-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_SVS_PLUS;
1475-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_SVS_PLUS;
1476-
dcvs_v3.setCoreParams = 1;
1477-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_SVS_PLUS;
1478-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_SVS_PLUS;
1479-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_SVS_PLUS;
1480-
break;
1481-
case HtpPerformanceMode::kHtpPowerSaver:
1482-
dcvs_v3.setSleepLatency = 1; // true
1483-
dcvs_v3.sleepLatency = kSleepMediumLatency;
1484-
dcvs_v3.dcvsEnable = kDcvsEnable;
1485-
dcvs_v3.setBusParams = 1;
1486-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_SVS;
1487-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_SVS;
1488-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_SVS;
1489-
dcvs_v3.setCoreParams = 1;
1490-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_SVS;
1491-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_SVS;
1492-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_SVS;
1493-
break;
1494-
case HtpPerformanceMode::kHtpLowPowerSaver:
1495-
dcvs_v3.setSleepLatency = 1; // true
1496-
dcvs_v3.sleepLatency = kSleepMediumLatency;
1497-
dcvs_v3.dcvsEnable = kDcvsEnable;
1498-
dcvs_v3.setBusParams = 1;
1499-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_VCORNER_SVS2;
1500-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_SVS2;
1501-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_VCORNER_SVS2;
1502-
dcvs_v3.setCoreParams = 1;
1503-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_VCORNER_SVS2;
1504-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_VCORNER_SVS2;
1505-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_VCORNER_SVS2;
1506-
break;
1507-
case HtpPerformanceMode::kHtpExtremePowerSaver:
1508-
dcvs_v3.powerMode = QNN_HTP_PERF_INFRASTRUCTURE_POWERMODE_POWER_SAVER_MODE;
1509-
dcvs_v3.setSleepLatency = 1; // true
1510-
dcvs_v3.sleepLatency = kSleepMediumLatency;
1511-
dcvs_v3.dcvsEnable = kDcvsEnable;
1512-
dcvs_v3.setBusParams = 1;
1513-
dcvs_v3.busVoltageCornerMin = DCVS_VOLTAGE_CORNER_DISABLE;
1514-
dcvs_v3.busVoltageCornerTarget = DCVS_VOLTAGE_CORNER_DISABLE;
1515-
dcvs_v3.busVoltageCornerMax = DCVS_VOLTAGE_CORNER_DISABLE;
1516-
dcvs_v3.setCoreParams = 1;
1517-
dcvs_v3.coreVoltageCornerMin = DCVS_VOLTAGE_CORNER_DISABLE;
1518-
dcvs_v3.coreVoltageCornerTarget = DCVS_VOLTAGE_CORNER_DISABLE;
1519-
dcvs_v3.coreVoltageCornerMax = DCVS_VOLTAGE_CORNER_DISABLE;
1520-
break;
1521-
default:
1522-
ORT_THROW("Invalid performance profile %d", static_cast<int>(htp_performance_mode));
1523-
break;
1524-
}
1525-
std::vector<const QnnHtpPerfInfrastructure_PowerConfig_t*> perf_power_configs_ptr = ObtainNullTermPtrVector(power_configs);
1526-
status = htp_perf_infra.setPowerConfig(htp_power_config_client_id, perf_power_configs_ptr.data());
1527-
ORT_RETURN_IF(QNN_SUCCESS != status, "setPowerConfig failed for HTP performance mode.");
1528-
1529-
return Status::OK();
1530-
}
1531-
1532-
Status QnnBackendManager::SetRpcPowerConfigs(uint32_t htp_power_config_client_id,
1533-
uint32_t rpc_control_latency,
1534-
uint32_t rpc_polling_time) {
1535-
// This function is called in QNN EP's OnRunStart() even if QNN backend setup failed and the model is assigned
1536-
// to a different EP. Therefore, we have to check that backend setup actually completed before trying to
1537-
// set RPC control latency. Otherwise, this causes a segfault because the QNN backend library is unloaded.
1538-
ORT_RETURN_IF_NOT(backend_setup_completed_, "Cannot set HTP RPC control latency if backend setup is not complete.");
1539-
1540-
constexpr int kNumRpcPollingPowerConfigs = 2;
1541-
std::vector<QnnHtpPerfInfrastructure_PowerConfig_t> rpc_power_configs;
1542-
rpc_power_configs.reserve(kNumRpcPollingPowerConfigs);
1543-
1544-
// Set rpc control latency here
1545-
if (rpc_control_latency != 0) {
1546-
auto& rpc_control_latency_cfg = rpc_power_configs.emplace_back();
1547-
rpc_control_latency_cfg.option = QNN_HTP_PERF_INFRASTRUCTURE_POWER_CONFIGOPTION_RPC_CONTROL_LATENCY;
1548-
rpc_control_latency_cfg.rpcControlLatencyConfig = rpc_control_latency;
1549-
}
1550-
1551-
// Note: v68 does not support rpc polling mode
1552-
if (rpc_polling_time != 0) {
1553-
auto& rpc_polling_time_cfg = rpc_power_configs.emplace_back();
1554-
rpc_polling_time_cfg.option = QNN_HTP_PERF_INFRASTRUCTURE_POWER_CONFIGOPTION_RPC_POLLING_TIME;
1555-
rpc_polling_time_cfg.rpcPollingTimeConfig = rpc_polling_time;
1556-
}
1557-
1558-
if (rpc_power_configs.size() > 0) {
1559-
QnnDevice_Infrastructure_t qnn_device_infra = nullptr;
1560-
auto status = qnn_interface_.deviceGetInfrastructure(&qnn_device_infra);
1561-
ORT_RETURN_IF(QNN_SUCCESS != status, "backendGetPerfInfrastructure failed.");
1562-
1563-
auto* htp_infra = static_cast<QnnHtpDevice_Infrastructure_t*>(qnn_device_infra);
1564-
ORT_RETURN_IF(QNN_HTP_DEVICE_INFRASTRUCTURE_TYPE_PERF != htp_infra->infraType,
1565-
"HTP infra type = ", htp_infra->infraType, ", which is not perf infra type.");
1566-
QnnHtpDevice_PerfInfrastructure_t& htp_perf_infra = htp_infra->perfInfra;
1567-
1568-
std::vector<const QnnHtpPerfInfrastructure_PowerConfig_t*> perf_power_configs_ptr =
1569-
ObtainNullTermPtrVector(rpc_power_configs);
1570-
status = htp_perf_infra.setPowerConfig(htp_power_config_client_id, perf_power_configs_ptr.data());
1571-
ORT_RETURN_IF(QNN_SUCCESS != status, "setPowerConfig failed for RPC control latency.");
1572-
}
1396+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddRpcPollingTime(rpc_polling_time));
1397+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddRpcControlLatency(rpc_control_latency));
1398+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddHtpPerformanceMode(htp_performance_mode, htp_power_config_client_id));
1399+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.SetPowerConfig(htp_power_config_client_id, GetQnnInterface()));
15731400

15741401
return Status::OK();
15751402
}
@@ -1583,18 +1410,24 @@ Status QnnBackendManager::SetPerThreadHtpPowerConfigs(const std::thread::id& thr
15831410
auto htp_power_config_id = htp_power_configs.power_config_id;
15841411
if (pre_run) {
15851412
if (htp_power_configs.pre_run_perf_mode.has_value()) {
1586-
ORT_RETURN_IF_ERROR(SetHtpPowerConfig(htp_power_config_id, *htp_power_configs.pre_run_perf_mode));
1413+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddHtpPerformanceMode(*htp_power_configs.pre_run_perf_mode,
1414+
htp_power_config_id));
1415+
}
1416+
1417+
if (htp_power_configs.rpc_control_latency.has_value()) {
1418+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddRpcControlLatency(*htp_power_configs.rpc_control_latency));
15871419
}
15881420

1589-
if (htp_power_configs.rpc_configs.has_value()) {
1590-
ORT_RETURN_IF_ERROR(SetRpcPowerConfigs(htp_power_config_id,
1591-
htp_power_configs.rpc_configs->rpc_control_latency,
1592-
htp_power_configs.rpc_configs->rpc_polling_time));
1421+
if (htp_power_configs.rpc_polling_time.has_value()) {
1422+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddRpcPollingTime(*htp_power_configs.rpc_polling_time));
15931423
}
15941424
} else if (htp_power_configs.post_run_perf_mode.has_value()) {
1595-
ORT_RETURN_IF_ERROR(SetHtpPowerConfig(htp_power_config_id, *htp_power_configs.post_run_perf_mode));
1425+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.AddHtpPerformanceMode(*htp_power_configs.post_run_perf_mode,
1426+
htp_power_config_id));
15961427
}
15971428

1429+
ORT_RETURN_IF_ERROR(htp_power_config_manager_.SetPowerConfig(htp_power_config_id, GetQnnInterface()));
1430+
15981431
return Status::OK();
15991432
}
16001433

onnxruntime/core/providers/qnn/builder/qnn_backend_manager.h

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "core/providers/qnn/builder/op_builder_factory.h"
2929
#include "core/providers/qnn/builder/qnn_context_mem_handle_manager.h"
3030
#include "core/providers/qnn/builder/qnn_def.h"
31+
#include "core/providers/qnn/builder/qnn_htp_power_config_manager.h"
3132
#include "core/providers/qnn/builder/qnn_profile_serializer.h"
3233
#include "core/providers/qnn/builder/qnn_node_group/qnn_node_group.h"
3334

@@ -166,12 +167,10 @@ class QnnBackendManager : public std::enable_shared_from_this<QnnBackendManager>
166167

167168
Status CreateHtpPowerCfgId(uint32_t deviceId, uint32_t coreId, uint32_t& htp_power_config_id);
168169

169-
Status SetHtpPowerConfig(uint32_t htp_power_config_client_id,
170-
HtpPerformanceMode htp_performance_mode);
171-
172-
Status SetRpcPowerConfigs(uint32_t htp_power_config_client_id,
173-
uint32_t rpc_control_latency,
174-
uint32_t rpc_polling_time);
170+
Status SetHtpPowerConfigs(uint32_t htp_power_config_client_id,
171+
HtpPerformanceMode htp_performance_mode,
172+
uint32_t rpc_polling_time,
173+
uint32_t rpc_control_latency);
175174

176175
Status SetPerThreadHtpPowerConfigs(const std::thread::id& thread_id, bool pre_run);
177176

@@ -310,16 +309,6 @@ class QnnBackendManager : public std::enable_shared_from_this<QnnBackendManager>
310309

311310
bool IsDevicePropertySupported();
312311

313-
template <typename T>
314-
std::vector<std::add_pointer_t<std::add_const_t<T>>> ObtainNullTermPtrVector(const std::vector<T>& vec) {
315-
std::vector<std::add_pointer_t<std::add_const_t<T>>> ret;
316-
for (auto& elem : vec) {
317-
ret.push_back(&elem);
318-
}
319-
ret.push_back(nullptr);
320-
return ret;
321-
}
322-
323312
std::string GetBackendBuildId() {
324313
char* backend_build_id{nullptr};
325314
if (QNN_SUCCESS != qnn_interface_.backendGetBuildId((const char**)&backend_build_id)) {
@@ -432,6 +421,7 @@ class QnnBackendManager : public std::enable_shared_from_this<QnnBackendManager>
432421
QnnBackend_Config_t** backend_config_ = nullptr;
433422
Qnn_LogHandle_t log_handle_ = nullptr;
434423
Qnn_DeviceHandle_t device_handle_ = nullptr;
424+
power::HtpPowerConfigManager htp_power_config_manager_;
435425

436426
// Map of Qnn_ContextHandle_t to QnnContextHandleRecord.
437427
// The QnnContextHandleRecord has ownership of the Qnn_ContextHandle_t.

onnxruntime/core/providers/qnn/builder/qnn_def.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,11 @@ enum class HtpPerformanceMode : uint8_t {
7171
kHtpExtremePowerSaver,
7272
};
7373

74-
typedef struct RpcPowerConfigs {
75-
uint32_t rpc_control_latency = 0;
76-
uint32_t rpc_polling_time = 0;
77-
} RpcPowerConfigs_t;
78-
7974
typedef struct PerThreadHtpPowerConfigs {
8075
std::optional<HtpPerformanceMode> pre_run_perf_mode;
8176
std::optional<HtpPerformanceMode> post_run_perf_mode;
82-
std::optional<RpcPowerConfigs_t> rpc_configs;
77+
std::optional<uint32_t> rpc_control_latency;
78+
std::optional<uint32_t> rpc_polling_time;
8379

8480
uint32_t power_config_id = 0;
8581
} PerThreadHtpPowerConfigs_t;
@@ -126,6 +122,9 @@ constexpr const int kSleepMediumLatency = 1000;
126122
constexpr const int kSleepHighLatency = 2000;
127123
constexpr const int kDcvsDisable = 0;
128124
constexpr const int kDcvsEnable = 1;
125+
constexpr const uint32_t kDisableRpcPolling = 0;
126+
constexpr const uint32_t kDisableRpcControlLatency = 0;
127+
constexpr const uint32_t kMaxRpcPolling = 9999;
129128

130129
struct OnnxTensorInfo {
131130
ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(OnnxTensorInfo);

0 commit comments

Comments
 (0)