mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-30 20:18:08 +00:00
[QNN EP]: Clean up QNN logging resources if an error occurs during initialization (#23435)
### Description Re-implementation of https://github.com/microsoft/onnxruntime/pull/23320 (which was reverted). - Cleans up QNN logging resources if an error occurs during initialization. - Updates `QnnLogging()`, which is a logging callback called by QNN libs, to handle situations in which ORT logging is unavailable, thus avoiding a segmentation fault. - Updates `QnnBackendManager::CreateHtpPowerCfgId()` and `QnnBackendManager::SetHtpPowerConfig()` to check that backend setup is complete. These functions get called in QNN EP's `OnRunStart()` even if QNN backend setup failed and the model is assigned to a different EP. This prevents a segmentation fault. Our Android tests ran into this issue because the QNN backend setup failed, the model was then assigned to CPU EP, and the QNN EP's `OnRunStart()` was still called with an invalid backend. ### Motivation and Context If QNN initialization fails at any point, we have to properly clean up the logging resources so that QNN does not call our `QnnLogging()` callback after the EP has been destroyed.
This commit is contained in:
parent
997ab24c08
commit
c7f764c941
1 changed files with 27 additions and 10 deletions
|
|
@ -251,6 +251,12 @@ void QnnLogging(const char* format,
|
|||
ORT_UNUSED_PARAMETER(level);
|
||||
ORT_UNUSED_PARAMETER(timestamp);
|
||||
|
||||
if (!::onnxruntime::logging::LoggingManager::HasDefaultLogger()) {
|
||||
// QNN may call this logging callback at any point, which means that we need to explicitly check
|
||||
// that the default logger has been initialized before trying to use it (otherwise get segfault).
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& logger = ::onnxruntime::logging::LoggingManager::DefaultLogger();
|
||||
const auto severity = ::onnxruntime::logging::Severity::kVERBOSE;
|
||||
const auto data_type = ::onnxruntime::logging::DataType::SYSTEM;
|
||||
|
|
@ -273,6 +279,9 @@ Status QnnBackendManager::InitializeQnnLog(const logging::Logger& logger) {
|
|||
QnnLog_Level_t qnn_log_level = MapOrtSeverityToQNNLogLevel(ort_log_level);
|
||||
LOGS(*logger_, VERBOSE) << "Set Qnn log level: " << qnn_log_level;
|
||||
|
||||
// NOTE: Even if logCreate() fails and QNN does not return a valid log_handle_, QNN may still
|
||||
// call the QnnLogging() callback. So, we have to make sure that QnnLogging() can handle calls
|
||||
// in which ORT logging is not available.
|
||||
Qnn_ErrorHandle_t result = qnn_interface_.logCreate(QnnLogging, qnn_log_level, &log_handle_);
|
||||
|
||||
if (result != QNN_SUCCESS) {
|
||||
|
|
@ -879,6 +888,10 @@ Status QnnBackendManager::SetupBackend(const logging::Logger& logger,
|
|||
}
|
||||
|
||||
Status QnnBackendManager::CreateHtpPowerCfgId(uint32_t device_id, uint32_t core_id, uint32_t& htp_power_config_id) {
|
||||
// This function is called in QNN EP's OnRunStart() even if QNN backend setup failed and the model is assigned
|
||||
// to a different EP. Therefore, we have to check that backend setup actually completed before trying to
|
||||
// create an HTP power config ID. Otherwise, this causes a segfault because the QNN backend lib is unloaded.
|
||||
ORT_RETURN_IF_NOT(backend_setup_completed_, "Cannot create HTP power config ID if backend setup is not complete.");
|
||||
QnnDevice_Infrastructure_t qnn_device_infra = nullptr;
|
||||
auto status = qnn_interface_.deviceGetInfrastructure(&qnn_device_infra);
|
||||
ORT_RETURN_IF(QNN_SUCCESS != status, "backendGetPerfInfrastructure failed.");
|
||||
|
|
@ -896,6 +909,10 @@ Status QnnBackendManager::CreateHtpPowerCfgId(uint32_t device_id, uint32_t core_
|
|||
|
||||
Status QnnBackendManager::SetHtpPowerConfig(uint32_t htp_power_config_client_id,
|
||||
HtpPerformanceMode htp_performance_mode) {
|
||||
// This function is called in QNN EP's OnRunStart() even if QNN backend setup failed and the model is assigned
|
||||
// to a different EP. Therefore, we have to check that backend setup actually completed before trying to
|
||||
// set an HTP power config ID. Otherwise, this causes a segfault because the QNN backend lib is unloaded.
|
||||
ORT_RETURN_IF_NOT(backend_setup_completed_, "Cannot set HTP power config ID if backend setup is not complete.");
|
||||
QnnDevice_Infrastructure_t qnn_device_infra = nullptr;
|
||||
auto status = qnn_interface_.deviceGetInfrastructure(&qnn_device_infra);
|
||||
ORT_RETURN_IF(QNN_SUCCESS != status, "backendGetPerfInfrastructure failed.");
|
||||
|
|
@ -1037,6 +1054,10 @@ Status QnnBackendManager::SetHtpPowerConfig(uint32_t htp_power_config_client_id,
|
|||
|
||||
Status QnnBackendManager::SetRpcControlLatency(uint32_t htp_power_config_client_id,
|
||||
uint32_t rpc_control_latency) {
|
||||
// This function is called in QNN EP's OnRunStart() even if QNN backend setup failed and the model is assigned
|
||||
// to a different EP. Therefore, we have to check that backend setup actually completed before trying to
|
||||
// set RPC control latency. Otherwise, this causes a segfault because the QNN backend library is unloaded.
|
||||
ORT_RETURN_IF_NOT(backend_setup_completed_, "Cannot set HTP RPC control latency if backend setup is not complete.");
|
||||
if (rpc_control_latency != 0) {
|
||||
QnnDevice_Infrastructure_t qnn_device_infra = nullptr;
|
||||
auto status = qnn_interface_.deviceGetInfrastructure(&qnn_device_infra);
|
||||
|
|
@ -1099,39 +1120,35 @@ Status QnnBackendManager::TerminateQnnLog() {
|
|||
}
|
||||
|
||||
void QnnBackendManager::ReleaseResources() {
|
||||
if (!backend_setup_completed_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = ReleaseContext();
|
||||
if (Status::OK() != result) {
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ReleaseContext.";
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ReleaseContext: " << result.ErrorMessage();
|
||||
}
|
||||
|
||||
result = ReleaseProfilehandle();
|
||||
if (Status::OK() != result) {
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ReleaseProfilehandle.";
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ReleaseProfilehandle: " << result.ErrorMessage();
|
||||
}
|
||||
|
||||
result = ReleaseDevice();
|
||||
if (Status::OK() != result) {
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ReleaseDevice.";
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ReleaseDevice: " << result.ErrorMessage();
|
||||
}
|
||||
|
||||
result = ShutdownBackend();
|
||||
if (Status::OK() != result) {
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ShutdownBackend.";
|
||||
LOGS_DEFAULT(ERROR) << "Failed to ShutdownBackend: " << result.ErrorMessage();
|
||||
}
|
||||
|
||||
result = TerminateQnnLog();
|
||||
if (Status::OK() != result) {
|
||||
LOGS_DEFAULT(ERROR) << "Failed to TerminateQnnLog.";
|
||||
LOGS_DEFAULT(ERROR) << "Failed to TerminateQnnLog: " << result.ErrorMessage();
|
||||
}
|
||||
|
||||
if (backend_lib_handle_) {
|
||||
result = UnloadLib(backend_lib_handle_);
|
||||
if (Status::OK() != result) {
|
||||
LOGS_DEFAULT(ERROR) << "Failed to unload backend library.";
|
||||
LOGS_DEFAULT(ERROR) << "Failed to unload backend library: " << result.ErrorMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue