Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions onnxruntime/core/providers/qnn/qnn_execution_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -910,14 +910,14 @@ Status QNNExecutionProvider::CompileFromOrtGraph(const std::vector<FusedNodeAndG
}

// Figure out the context cache Onnx file path to decide the folder location
static void GetContextOnnxModelFilePath(const std::string& customer_context_cache_path,
static void GetContextOnnxModelFilePath(const std::string& user_context_cache_path,
const onnxruntime::PathString& model_path_string,
onnxruntime::PathString& context_cache_binary_path) {
onnxruntime::PathString& context_model_path) {
// always try the path set by user first, it's the only way to set it if load model from memory
if (!customer_context_cache_path.empty()) {
context_cache_binary_path = ToPathString(customer_context_cache_path);
if (!user_context_cache_path.empty()) {
context_model_path = ToPathString(user_context_cache_path);
} else if (!model_path_string.empty()) { // model loaded from file
context_cache_binary_path = model_path_string;
context_model_path = model_path_string;
}
}

Expand Down
13 changes: 13 additions & 0 deletions onnxruntime/core/session/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "core/session/onnxruntime_c_api.h"
#include "core/session/ort_apis.h"
#include "core/session/ort_env.h"
#include "core/session/onnxruntime_session_options_config_keys.h"

using namespace onnxruntime;

Expand Down Expand Up @@ -49,6 +50,18 @@ OrtStatus* CreateSessionAndLoadModel(_In_ const OrtSessionOptions* options,
bool load_config_from_model =
os_env.GetEnvironmentVar(inference_session_utils::kOrtLoadConfigFromModelEnvVar) == "1";

// If ep.context_enable is set, then ep.context_file_path is expected, otherwise ORT don't know where to generate the _ctx.onnx file
if (options && model_path == nullptr) {
auto ep_context_enable = options->value.config_options.GetConfigEntry(kOrtSessionOptionEpContextEnable);
auto ep_context_file_path = options->value.config_options.GetConfigEntry(kOrtSessionOptionEpContextFilePath);
if (ep_context_enable.has_value() && ep_context_enable.value() == "1" && (!ep_context_file_path.has_value() || (ep_context_file_path.has_value() && ep_context_file_path.value().empty()))) {
return OrtApis::CreateStatus(ORT_FAIL,
"CreateSessionFromArray is called with ep.context_enable enabled but an \
empty ep.context_file_path. The system does not know where to generate the \
EP context model. Please specify a valid ep.context_file_path.");
}
}

if (load_config_from_model) {
#if !defined(ORT_MINIMAL_BUILD)
if (model_path != nullptr) {
Expand Down
64 changes: 62 additions & 2 deletions onnxruntime/test/providers/qnn/qnn_ep_context_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ void CleanUpCtxFile(std::string context_file_path) {
GetContextBinaryFileName(context_file_path, qnn_ctx_binary_file_name,
DefaultLoggingManager().DefaultLogger());

ASSERT_EQ(std::remove(qnn_ctx_binary_file_name.c_str()), 0);
std::filesystem::path ctx_model_path(context_file_path);

std::string qnn_ctx_binary_file_path = (ctx_model_path.remove_filename().string() + qnn_ctx_binary_file_name);
ASSERT_EQ(std::remove(qnn_ctx_binary_file_path.c_str()), 0);
ASSERT_EQ(std::remove(context_file_path.c_str()), 0);
}

Expand Down Expand Up @@ -152,7 +155,7 @@ void QnnContextBinaryMultiPartitionTestBody(bool single_ep_node = true) {

const auto model_data_span = AsByteSpan(model_data.data(), model_data.size());

const std::string context_model_file = "./qnn_context_binary_multi_partition_test.onnx";
const std::string context_model_file = "./testdata/qnn_context_binary_multi_partition_test.onnx";
std::remove(context_model_file.c_str());
Ort::SessionOptions so;
so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1");
Expand Down Expand Up @@ -1309,6 +1312,63 @@ TEST_F(QnnHTPBackendTests, QnnContextGenWeightSharingSessionAPI) {
}
ASSERT_EQ(std::remove(qnn_ctx_binary_file_name1.c_str()), 0);
}

// Session created from array wth ep.context_enable enabled without ep.context_file_path
// Error message expected
TEST_F(QnnHTPBackendTests, LoadFromArrayWithQnnEpContextGenPathValidation) {
ProviderOptions provider_options;
#if defined(_WIN32)
provider_options["backend_path"] = "QnnHtp.dll";
#else
provider_options["backend_path"] = "libQnnHtp.so";
#endif
const std::unordered_map<std::string, int> domain_to_version = {{"", 13}, {kMSDomain, 1}};

auto& logging_manager = DefaultLoggingManager();
logging_manager.SetDefaultLoggerSeverity(logging::Severity::kERROR);
onnxruntime::Model model("QNN_EP_TestModel", false, ModelMetaData(), PathString(),
IOnnxRuntimeOpSchemaRegistryList(), domain_to_version, {},
logging_manager.DefaultLogger());
Graph& graph = model.MainGraph();
ModelTestBuilder helper(graph);
bool single_ep_node = true;
BuildGraphWithQAndNonQ(single_ep_node)(helper);
helper.SetGraphOutputs();
ASSERT_STATUS_OK(model.MainGraph().Resolve());

// Serialize the model to a string.
std::string model_data;
model.ToProto().SerializeToString(&model_data);

const auto model_data_span = AsByteSpan(model_data.data(), model_data.size());

const std::string context_model_file = "./qnn_context_binary_multi_partition_test.onnx";
std::remove(context_model_file.c_str());
Ort::SessionOptions so;
so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1");
so.AppendExecutionProvider("QNN", provider_options);

ORT_TRY {
Ort::Session session1(*ort_env, model_data_span.data(), model_data_span.size(), so);
}
ORT_CATCH(const std::exception& e) {
ORT_HANDLE_EXCEPTION([&e]() {
std::string e_message1(std::string(e.what()));
ASSERT_TRUE(e_message1.find("Please specify a valid ep.context_file_path.") != std::string::npos);
});
}

ORT_TRY {
so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, "");
Ort::Session session2(*ort_env, model_data_span.data(), model_data_span.size(), so);
}
ORT_CATCH(const std::exception& ex) {
ORT_HANDLE_EXCEPTION([&ex]() {
std::string e_message2(std::string(ex.what()));
ASSERT_TRUE(e_message2.find("Please specify a valid ep.context_file_path.") != std::string::npos);
});
}
}
#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__)

} // namespace test
Expand Down