Skip to content

Commit 047587e

Browse files
authored
Qualcomm AI Engine Direct - Runtime Option (#12297)
### Summary Supporting following options that can be set during both AOT and runtime: - Log Level - Performance Mode - Profiling Level ### Test plan - Log Level: Check `debug` message prefix exists. - Performance Mode: Ensure QNN SDK prints config log for performance, and ensure burst is faster than high power saver. - Profiling Level: Turn profiling off in compile spec and add profiling flag in runtime, ensure profiler gets expected number of events.
1 parent 981119e commit 047587e

File tree

19 files changed

+570
-35
lines changed

19 files changed

+570
-35
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)
@@ -159,6 +160,7 @@ target_link_libraries(
159160
qnn_backend PRIVATE qnn_implementation qnn_logger qnn_op_package_manager
160161
)
161162
target_link_libraries(qnn_custom_protocol PRIVATE qnn_logger)
163+
target_link_libraries(qnn_backend_options PRIVATE qnn_schema)
162164
target_link_libraries(
163165
qnn_device PRIVATE qnn_executorch_logging qnn_implementation qnn_logger
164166
)
@@ -197,7 +199,7 @@ target_link_libraries(
197199
)
198200
target_link_libraries(
199201
qnn_executorch_backend PRIVATE qnn_executorch_header qnn_schema qnn_manager
200-
executorch_core extension_tensor
202+
executorch_core extension_tensor qnn_backend_options
201203
)
202204
set_target_properties(
203205
qnn_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'"
@@ -261,6 +263,7 @@ if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
261263
qnn_executorch_header
262264
executorch
263265
extension_tensor
266+
qnn_backend_options
264267
)
265268
target_link_libraries(
266269
PyQnnWrapperAdaptor PRIVATE pybind11::module pybind11::lto wrappers

backends/qualcomm/_passes/convert_conv1d_to_conv2d.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def call(self, graph_module: torch.fx.GraphModule):
105105
padding = [0] + node.args[4] if num_args > 4 else [0, 0]
106106
if node.target == torch.ops.aten.conv1d.default:
107107
dilation = [1] + node.args[5] if num_args > 5 else [1, 1]
108-
groups = node.args[6] if num_args > 5 else 1
108+
groups = node.args[6] if num_args > 6 else 1
109109
conv_args = (
110110
qdq_node_after_unsqueeze,
111111
node.args[1],

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: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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/backends/qualcomm/runtime/QnnExecuTorch.h>
11+
#include <executorch/runtime/backend/interface.h>
12+
#include <executorch/runtime/backend/options.h>
13+
14+
namespace executorch {
15+
namespace backends {
16+
namespace qnn {
17+
18+
/**
19+
* @brief Storing runtime option value.
20+
* @param is_set True when user calls set_option api to set option, else False.
21+
*/
22+
struct RuntimeOption {
23+
bool is_set;
24+
executorch::runtime::OptionValue value;
25+
};
26+
27+
/**
28+
* @brief
29+
* Get the backend option.
30+
* This method checks both AOT option and runtime option.
31+
* If runtime option is provided, it will have a higher priority.
32+
*
33+
* @param aot_option The flatbuffer option under qc_compiler_spec.fbs.
34+
*/
35+
36+
template <typename T>
37+
T get_option(T aot_option);
38+
39+
} // namespace qnn
40+
} // namespace backends
41+
} // namespace executorch

backends/qualcomm/runtime/QnnExecuTorch.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#include <stdint.h>
1717
#endif
1818

19+
#define QNN_BACKEND "QnnBackend"
20+
#define QNN_RUNTIME_LOG_LEVEL "qnn_runtime_log_level"
21+
#define QNN_RUNTIME_HTP_PERFORMANCE_MODE "qnn_runtime_htp_performance_mode"
22+
#define QNN_RUNTIME_PROFILE_LEVEL "qnn_runtime_profile_level"
23+
1924
#ifdef __cplusplus
2025
extern "C" {
2126
#endif // __cplusplus

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: 16 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>
@@ -34,6 +35,16 @@ class QnnExecuTorchBackend final
3435
executorch::runtime::DelegateHandle* handle,
3536
executorch::runtime::EValue** args) const override;
3637

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

3950
bool is_available() const override;
@@ -45,10 +56,15 @@ class QnnExecuTorchBackend final
4556
void erase_cached_delegate(executorch::runtime::DelegateHandle* handle) const;
4657

4758
mutable std::mutex mutex_;
59+
mutable std::mutex runtime_option_mutex_;
4860
mutable std::unordered_map<int64_t, executorch::runtime::DelegateHandle*>
4961
delegate_map_;
5062
mutable std::unordered_map<executorch::runtime::DelegateHandle*, std::int64_t>
5163
delegate_map_rev_;
64+
65+
RuntimeOption qnn_runtime_log_level_{false, 0};
66+
RuntimeOption qnn_runtime_performance_mode_{false, 0};
67+
RuntimeOption qnn_runtime_profile_level_{false, 0};
5268
};
5369

5470
} // 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)