Skip to content

Commit 248a017

Browse files
committed
Qualcomm AI Engine Direct - Runtime Option
1 parent 478032a commit 248a017

File tree

16 files changed

+571
-33
lines changed

16 files changed

+571
-33
lines changed

backends/qualcomm/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ add_library(qcir INTERFACE qcir_schema_output)
116116
add_library(qcir_utils STATIC)
117117
add_library(qnn_backend STATIC)
118118
add_library(qnn_backend_cache STATIC)
119+
add_library(qnn_backend_options STATIC)
119120
add_library(qnn_context STATIC)
120121
add_library(qnn_custom_protocol STATIC)
121122
add_library(qnn_dlc_manager STATIC)
@@ -155,6 +156,7 @@ target_link_libraries(qnn_profiler PRIVATE qnn_executorch_logging)
155156
target_link_libraries(qnn_logger PRIVATE qnn_implementation ${android_log})
156157
target_link_libraries(qnn_backend PRIVATE qnn_implementation qnn_logger qnn_op_package_manager)
157158
target_link_libraries(qnn_custom_protocol PRIVATE qnn_logger)
159+
target_link_libraries(qnn_backend_options PRIVATE qnn_schema)
158160
target_link_libraries(
159161
qnn_device PRIVATE qnn_executorch_logging qnn_implementation qnn_logger
160162
)
@@ -185,7 +187,7 @@ target_link_libraries(
185187
)
186188
target_link_libraries(
187189
qnn_executorch_backend PRIVATE qnn_executorch_header qnn_schema qnn_manager
188-
executorch_core extension_tensor
190+
executorch_core extension_tensor qnn_backend_options
189191
)
190192
set_target_properties(
191193
qnn_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'"
@@ -245,6 +247,7 @@ if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
245247
qnn_executorch_header
246248
executorch
247249
extension_tensor
250+
qnn_backend_options
248251
)
249252
target_link_libraries(
250253
PyQnnWrapperAdaptor PRIVATE pybind11::module pybind11::lto wrappers

backends/qualcomm/runtime/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ target_sources(
2828
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/QnnManager.cpp
2929
)
3030

31+
# qnn_backend_options
32+
target_sources(
33+
qnn_backend_options
34+
INTERFACE ${CMAKE_CURRENT_LIST_DIR}/QnnBackendOptions.h
35+
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/QnnBackendOptions.cpp
36+
)
37+
3138
# logging
3239
target_sources(
3340
qnn_executorch_logging
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) Qualcomm Innovation Center, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
#include <executorch/backends/qualcomm/qc_compiler_spec_generated.h>
9+
#include <executorch/backends/qualcomm/runtime/QnnBackendOptions.h>
10+
#include <executorch/backends/qualcomm/runtime/QnnExecuTorchBackend.h>
11+
12+
namespace executorch {
13+
namespace backends {
14+
namespace qnn {
15+
16+
using namespace qnn_delegate;
17+
18+
template <typename T>
19+
T get_option(T aot_option) {
20+
executorch::runtime::Error status;
21+
executorch::runtime::BackendOption backend_option;
22+
23+
if constexpr (std::is_same_v<T, QnnExecuTorchLogLevel>) {
24+
backend_option = {QNN_RUNTIME_LOG_LEVEL, -1};
25+
} else if constexpr (std::is_same_v<T, QnnExecuTorchHtpPerformanceMode>) {
26+
backend_option = {QNN_RUNTIME_HTP_PERFORMANCE_MODE, -1};
27+
} else if constexpr (std::is_same_v<T, QnnExecuTorchProfileLevel>) {
28+
backend_option = {QNN_RUNTIME_PROFILE_LEVEL, -1};
29+
}
30+
// This will call get_option under runtime backend interface
31+
status = get_option(QNN_BACKEND, backend_option);
32+
33+
if (status != executorch::runtime::Error::Ok) {
34+
return aot_option;
35+
} else {
36+
return static_cast<T>(std::get<int>(backend_option.value));
37+
}
38+
}
39+
40+
// Explicit instantiations
41+
template QnnExecuTorchLogLevel get_option<QnnExecuTorchLogLevel>(
42+
QnnExecuTorchLogLevel);
43+
template QnnExecuTorchHtpPerformanceMode get_option<
44+
QnnExecuTorchHtpPerformanceMode>(QnnExecuTorchHtpPerformanceMode);
45+
template QnnExecuTorchProfileLevel get_option<QnnExecuTorchProfileLevel>(
46+
QnnExecuTorchProfileLevel);
47+
48+
} // namespace qnn
49+
} // namespace backends
50+
} // namespace executorch
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) Qualcomm Innovation Center, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
#pragma once
9+
10+
#include <executorch/runtime/backend/interface.h>
11+
#include <executorch/runtime/backend/options.h>
12+
13+
#define QNN_RUNTIME_LOG_LEVEL "qnn_runtime_log_level"
14+
#define QNN_RUNTIME_HTP_PERFORMANCE_MODE "qnn_runtime_htp_performance_mode"
15+
#define QNN_RUNTIME_PROFILE_LEVEL "qnn_runtime_profile_level"
16+
17+
namespace executorch {
18+
namespace backends {
19+
namespace qnn {
20+
21+
/**
22+
* @brief Storing runtime option value.
23+
* @param is_set True when user calls set_option api to set option, else False.
24+
*/
25+
struct RuntimeOption {
26+
bool is_set;
27+
executorch::runtime::OptionValue value;
28+
};
29+
30+
/**
31+
* @brief
32+
* Get the backend option.
33+
* This method checks both AOT option and runtime option.
34+
* If runtime option is provided, it will have a higher priority.
35+
*
36+
* @param aot_option The flatbuffer option under qc_compiler_spec.fbs.
37+
*/
38+
39+
template <typename T>
40+
T get_option(T aot_option);
41+
42+
} // namespace qnn
43+
} // namespace backends
44+
} // namespace executorch

backends/qualcomm/runtime/QnnExecuTorchBackend.cpp

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88

99
#include <executorch/backends/qualcomm/aot/wrappers/TensorWrapper.h>
1010
#include <executorch/backends/qualcomm/qc_compiler_spec_generated.h>
11+
#include <executorch/backends/qualcomm/runtime/QnnBackendOptions.h>
1112
#include <executorch/backends/qualcomm/runtime/QnnExecuTorchBackend.h>
1213
#include <executorch/backends/qualcomm/runtime/QnnManager.h>
1314
#include <executorch/backends/qualcomm/runtime/backends/QnnCustomProtocol.h>
14-
15+
#include <executorch/runtime/backend/interface.h>
16+
#include <executorch/runtime/backend/options.h>
1517
namespace executorch {
1618
namespace backends {
1719
namespace qnn {
@@ -189,6 +191,77 @@ void QnnExecuTorchBackend::destroy(DelegateHandle* handle) const {
189191
}
190192
}
191193

194+
executorch::runtime::Error QnnExecuTorchBackend::set_option(
195+
executorch::runtime::BackendOptionContext& context,
196+
const executorch::runtime::Span<executorch::runtime::BackendOption>&
197+
backend_options) {
198+
std::lock_guard<std::mutex> guard(runtime_option_mutex_);
199+
size_t matches = backend_options.size();
200+
for (const auto& option : backend_options) {
201+
if (strcmp(option.key, QNN_RUNTIME_LOG_LEVEL) == 0) {
202+
if (auto* val = std::get_if<int>(&option.value)) {
203+
qnn_runtime_log_level_.value = *val;
204+
qnn_runtime_log_level_.is_set = true;
205+
}
206+
} else if (strcmp(option.key, QNN_RUNTIME_HTP_PERFORMANCE_MODE) == 0) {
207+
if (auto* val = std::get_if<int>(&option.value)) {
208+
qnn_runtime_performance_mode_.value = *val;
209+
qnn_runtime_performance_mode_.is_set = true;
210+
}
211+
} else if (strcmp(option.key, QNN_RUNTIME_PROFILE_LEVEL) == 0) {
212+
if (auto* val = std::get_if<int>(&option.value)) {
213+
qnn_runtime_profile_level_.value = *val;
214+
qnn_runtime_profile_level_.is_set = true;
215+
}
216+
} else {
217+
ET_LOG(
218+
Error,
219+
"Unable to set the following runtime option for QnnExecuTorchBackend: %s.",
220+
option.key);
221+
matches--;
222+
}
223+
}
224+
225+
ET_CHECK_OR_RETURN_ERROR(
226+
matches == backend_options.size(),
227+
Internal,
228+
"Some set options are not supported by QnnExecuTorchBackend. %zu options provided but only %zu is supported.",
229+
backend_options.size(),
230+
matches);
231+
232+
return Error::Ok;
233+
}
234+
235+
executorch::runtime::Error QnnExecuTorchBackend::get_option(
236+
executorch::runtime::BackendOptionContext& context,
237+
executorch::runtime::Span<executorch::runtime::BackendOption>&
238+
backend_options) {
239+
size_t matches = backend_options.size();
240+
for (size_t i = 0; i < backend_options.size(); ++i) {
241+
// Set the value to what was stored by set_option
242+
if (strcmp(backend_options[i].key, QNN_RUNTIME_LOG_LEVEL) == 0 &&
243+
qnn_runtime_log_level_.is_set) {
244+
backend_options[i].value = qnn_runtime_log_level_.value;
245+
} else if (
246+
strcmp(backend_options[i].key, QNN_RUNTIME_HTP_PERFORMANCE_MODE) == 0 &&
247+
qnn_runtime_performance_mode_.is_set) {
248+
backend_options[i].value = qnn_runtime_performance_mode_.value;
249+
} else if (
250+
strcmp(backend_options[i].key, QNN_RUNTIME_PROFILE_LEVEL) == 0 &&
251+
qnn_runtime_profile_level_.is_set) {
252+
backend_options[i].value = qnn_runtime_profile_level_.value;
253+
} else {
254+
// either runtime never called set_option or key does not exist
255+
matches--;
256+
}
257+
}
258+
259+
if (matches != backend_options.size()) {
260+
return Error::Internal;
261+
}
262+
return Error::Ok;
263+
}
264+
192265
bool QnnExecuTorchBackend::is_available() const {
193266
return true;
194267
}
@@ -214,7 +287,7 @@ void QnnExecuTorchBackend::erase_cached_delegate(
214287

215288
namespace {
216289
auto cls = QnnExecuTorchBackend();
217-
executorch::runtime::Backend backend{"QnnBackend", &cls};
290+
executorch::runtime::Backend backend{QNN_BACKEND, &cls};
218291
static auto success_with_compiler = register_backend(backend);
219292
} // namespace
220293
} // namespace qnn

backends/qualcomm/runtime/QnnExecuTorchBackend.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
#pragma once
99

10+
#include <executorch/backends/qualcomm/runtime/QnnBackendOptions.h>
1011
#include <executorch/runtime/backend/interface.h>
1112
#include <executorch/runtime/core/error.h>
1213
#include <executorch/runtime/core/evalue.h>
@@ -18,6 +19,7 @@ namespace executorch {
1819
namespace backends {
1920
namespace qnn {
2021

22+
constexpr const char* QNN_BACKEND = "QnnBackend";
2123
class QnnExecuTorchBackend final
2224
: public ::executorch::runtime::BackendInterface {
2325
public:
@@ -34,6 +36,16 @@ class QnnExecuTorchBackend final
3436
executorch::runtime::DelegateHandle* handle,
3537
executorch::runtime::EValue** args) const override;
3638

39+
ET_NODISCARD executorch::runtime::Error set_option(
40+
executorch::runtime::BackendOptionContext& context,
41+
const executorch::runtime::Span<executorch::runtime::BackendOption>&
42+
backend_options) override;
43+
44+
executorch::runtime::Error get_option(
45+
executorch::runtime::BackendOptionContext& context,
46+
executorch::runtime::Span<executorch::runtime::BackendOption>&
47+
backend_options) override;
48+
3749
void destroy(executorch::runtime::DelegateHandle* handle) const override;
3850

3951
bool is_available() const override;
@@ -45,10 +57,15 @@ class QnnExecuTorchBackend final
4557
void erase_cached_delegate(executorch::runtime::DelegateHandle* handle) const;
4658

4759
mutable std::mutex mutex_;
60+
mutable std::mutex runtime_option_mutex_;
4861
mutable std::unordered_map<int64_t, executorch::runtime::DelegateHandle*>
4962
delegate_map_;
5063
mutable std::unordered_map<executorch::runtime::DelegateHandle*, std::int64_t>
5164
delegate_map_rev_;
65+
66+
RuntimeOption qnn_runtime_log_level_{false, 0};
67+
RuntimeOption qnn_runtime_performance_mode_{false, 0};
68+
RuntimeOption qnn_runtime_profile_level_{false, 0};
5269
};
5370

5471
} // namespace qnn

backends/qualcomm/runtime/QnnManager.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9+
#include <executorch/backends/qualcomm/runtime/QnnBackendOptions.h>
910
#include <executorch/backends/qualcomm/runtime/QnnManager.h>
1011
#include <executorch/backends/qualcomm/runtime/SharedBuffer.h>
1112
#include <executorch/backends/qualcomm/runtime/Utils.h>
@@ -63,7 +64,8 @@ QnnManager::QnnManager(
6364
options->backend_options()->backend_type();
6465
std::string library_path = options->library_path()->str();
6566

66-
if (options->log_level() >= QnnExecuTorchLogLevel::kLogLevelInfo) {
67+
if (get_option(options_->log_level()) >=
68+
QnnExecuTorchLogLevel::kLogLevelInfo) {
6769
QNN_EXECUTORCH_LOG_INFO(
6870
"soc_model in soc_info: %s",
6971
EnumNameQcomChipset(options_->soc_info()->soc_model()));
@@ -75,10 +77,12 @@ QnnManager::QnnManager(
7577
QNN_EXECUTORCH_LOG_INFO("library_path: %s", library_path.c_str());
7678
QNN_EXECUTORCH_LOG_INFO("dump intermediate outputs: %s", IsTensorDump());
7779
QNN_EXECUTORCH_LOG_INFO(
78-
"log_level: %s", EnumNameQnnExecuTorchLogLevel(options_->log_level()));
80+
"log_level: %s",
81+
EnumNameQnnExecuTorchLogLevel(get_option(options_->log_level())));
7982
QNN_EXECUTORCH_LOG_INFO(
8083
"profile_level: %s",
81-
EnumNameQnnExecuTorchProfileLevel(options_->profile_level()));
84+
EnumNameQnnExecuTorchProfileLevel(
85+
get_option(options_->profile_level())));
8286
QNN_EXECUTORCH_LOG_INFO(
8387
"the size of qnn context binary: %d",
8488
qnn_executorch_context_binary.nbytes);
@@ -202,7 +206,8 @@ Error QnnManager::RegisterIonMem(
202206
return Error::Internal;
203207
} else if (backend_params_ptr_->qnn_mem_manager_ptr_->IsRegistered(
204208
tensor_wrapper->GetMemHandle(), data_ptr)) {
205-
if (options_->log_level() >= QnnExecuTorchLogLevel::kLogLevelInfo)
209+
if (get_option(options_->log_level()) >=
210+
QnnExecuTorchLogLevel::kLogLevelInfo)
206211
QNN_EXECUTORCH_LOG_INFO(
207212
"Tensor name %s has been registered shared memory.",
208213
tensor_wrapper->GetName().c_str());
@@ -231,7 +236,8 @@ Error QnnManager::RegisterCustomMem(
231236
const std::shared_ptr<TensorWrapper>& tensor_wrapper) {
232237
if (backend_params_ptr_->qnn_mem_manager_ptr_->IsRegistered(
233238
tensor_wrapper->GetMemHandle(), data_ptr)) {
234-
if (options_->log_level() >= QnnExecuTorchLogLevel::kLogLevelInfo)
239+
if (get_option(options_->log_level()) >=
240+
QnnExecuTorchLogLevel::kLogLevelInfo)
235241
QNN_EXECUTORCH_LOG_INFO(
236242
"Tensor name %s has been registered shared memory.",
237243
tensor_wrapper->GetName().c_str());
@@ -251,7 +257,8 @@ Error QnnManager::RegisterCustomMem(
251257
Qnn_MemHandle_t pre_registered_handle =
252258
backend_params_ptr_->qnn_mem_manager_ptr_->GetPreRegisteredHandle(info);
253259
if (pre_registered_handle != nullptr) {
254-
if (options_->log_level() >= QnnExecuTorchLogLevel::kLogLevelInfo) {
260+
if (get_option(options_->log_level()) >=
261+
QnnExecuTorchLogLevel::kLogLevelInfo) {
255262
QNN_EXECUTORCH_LOG_INFO(
256263
"Tensor name %s found a pre-registered memHandle.",
257264
tensor_wrapper->GetName().c_str());
@@ -295,7 +302,7 @@ Error QnnManager::Init() {
295302
ET_CHECK_OR_RETURN_ERROR(
296303
LoadQnnLibrary() == Error::Ok, Internal, "Fail to load Qnn library");
297304
logger_ = std::make_unique<QnnLogger>(
298-
qnn_loaded_backend_, LoggingCallback, options_->log_level());
305+
qnn_loaded_backend_, LoggingCallback, get_option(options_->log_level()));
299306
std::vector<std::string> graph_names;
300307
for (auto name : *options_->graph_name()) {
301308
graph_names.emplace_back(name->str());
@@ -492,7 +499,8 @@ Error QnnManager::ProfileExecuteData(
492499
const std::string& graph_name,
493500
executorch::runtime::EventTracer* event_tracer) {
494501
Qnn_ErrorHandle_t error = QNN_SUCCESS;
495-
if (options_->profile_level() != QnnExecuTorchProfileLevel::kProfileOff) {
502+
if (get_option(options_->profile_level()) !=
503+
QnnExecuTorchProfileLevel::kProfileOff) {
496504
error = backend_params_ptr_->qnn_graph_ptr_->ProfileExecuteData(
497505
graph_name, event_tracer);
498506
if (error != QNN_SUCCESS) {

0 commit comments

Comments
 (0)