diff --git a/onnxruntime/core/providers/qnn/qnn_execution_provider.cc b/onnxruntime/core/providers/qnn/qnn_execution_provider.cc index 2606ace8127d3..f045dae7b4e6a 100644 --- a/onnxruntime/core/providers/qnn/qnn_execution_provider.cc +++ b/onnxruntime/core/providers/qnn/qnn_execution_provider.cc @@ -910,14 +910,14 @@ Status QNNExecutionProvider::CompileFromOrtGraph(const std::vectorvalue.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) { diff --git a/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc b/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc index e39102a21dd1c..afb49d9d0a0c6 100644 --- a/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc +++ b/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc @@ -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); } @@ -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"); @@ -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 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