diff --git a/runtime/backend/backend_init_context.h b/runtime/backend/backend_init_context.h index 0f649b3733f..4c1a5ca2bfb 100644 --- a/runtime/backend/backend_init_context.h +++ b/runtime/backend/backend_init_context.h @@ -25,6 +25,9 @@ namespace executorch { namespace ET_RUNTIME_NAMESPACE { + +class MethodMeta; + /** * BackendInitContext will be used to inject runtime info for to initialize * delegate. @@ -36,7 +39,8 @@ class BackendInitContext final { EventTracer* event_tracer = nullptr, const char* method_name = nullptr, const NamedDataMap* named_data_map = nullptr, - Span runtime_specs = {}) + Span runtime_specs = {}, + const MethodMeta* method_meta = nullptr) : runtime_allocator_(runtime_allocator), #ifdef ET_EVENT_TRACER_ENABLED event_tracer_(event_tracer), @@ -45,7 +49,8 @@ class BackendInitContext final { #endif method_name_(method_name), named_data_map_(named_data_map), - runtime_specs_(runtime_specs) { + runtime_specs_(runtime_specs), + method_meta_(method_meta) { } /** Get the runtime allocator passed from Method. It's the same runtime @@ -94,6 +99,16 @@ class BackendInitContext final { return runtime_specs_; } + /** + * Returns metadata for the enclosing method, or nullptr if not supplied. + * The runtime provides a borrowed view valid during backend initialization. + * Other callers must keep the view and its backing program alive for the + * lifetime of this context. + */ + const MethodMeta* method_meta() const { + return method_meta_; + } + /** * Get a runtime spec value by key and type. * @@ -135,6 +150,7 @@ class BackendInitContext final { const char* method_name_ = nullptr; const NamedDataMap* named_data_map_ = nullptr; Span runtime_specs_; + const MethodMeta* method_meta_ = nullptr; }; } // namespace ET_RUNTIME_NAMESPACE diff --git a/runtime/backend/test/backend_init_context_test.cpp b/runtime/backend/test/backend_init_context_test.cpp index 8d74b9361fc..25e6c5f055e 100644 --- a/runtime/backend/test/backend_init_context_test.cpp +++ b/runtime/backend/test/backend_init_context_test.cpp @@ -8,7 +8,12 @@ #include #include +#include #include +#include + +#include +#include #include @@ -17,6 +22,7 @@ using executorch::runtime::BackendInitContext; using executorch::runtime::BackendOption; using executorch::runtime::BackendOptions; using executorch::runtime::Error; +using executorch::runtime::MethodMeta; using executorch::runtime::Span; class BackendInitContextTest : public ::testing::Test { @@ -32,6 +38,32 @@ TEST_F(BackendInitContextTest, DefaultConstructorNoRuntimeSpecs) { auto specs = context.runtime_specs(); EXPECT_EQ(specs.size(), 0); + EXPECT_EQ(context.method_meta(), nullptr); +} + +TEST_F(BackendInitContextTest, ConstructorPreservesMethodMeta) { + namespace fb = executorch_flatbuffer; + flatbuffers::FlatBufferBuilder builder; + const auto plan = fb::CreateExecutionPlan( + builder, + builder.CreateString("forward"), + /*container_meta_type=*/0, + builder.CreateVector(std::vector>{}), + builder.CreateVector(std::vector{}), + builder.CreateVector(std::vector{}), + /*chains=*/0, + /*operators=*/0, + builder.CreateVector( + std::vector>{})); + builder.Finish(plan); + const auto meta = MethodMeta::from_serialized_execution_plan( + builder.GetBufferPointer(), builder.GetSize()); + ASSERT_TRUE(meta.ok()); + + BackendInitContext context( + nullptr, nullptr, "forward", nullptr, {}, &meta.get()); + + EXPECT_EQ(context.method_meta(), &meta.get()); } // Test constructor with runtime specs diff --git a/runtime/backend/test/targets.bzl b/runtime/backend/test/targets.bzl index 5ce89cba9d0..0859cdddc86 100644 --- a/runtime/backend/test/targets.bzl +++ b/runtime/backend/test/targets.bzl @@ -31,6 +31,8 @@ def define_common_targets(): deps = [ "//executorch/runtime/core:core", "//executorch/runtime/backend:interface", + "//executorch/runtime/executor:program", + "//executorch/schema:program", ], ) diff --git a/runtime/executor/method.cpp b/runtime/executor/method.cpp index 9b8b9e34008..5f6d75d13a6 100644 --- a/runtime/executor/method.cpp +++ b/runtime/executor/method.cpp @@ -1019,6 +1019,7 @@ Error Method::init( // makes it safe for errors to return without updating any state. n_delegate_ = 0; + const auto method_meta = this->method_meta(); for (size_t i = 0; i < n_delegate; ++i) { const auto& delegate = *delegates->Get(i); @@ -1035,7 +1036,8 @@ Error Method::init( /*event_tracer=*/event_tracer_, /*method_name=*/serialization_plan_->name()->c_str(), /*named_data_map=*/named_data_map, - /*runtime_specs=*/delegate_runtime_specs); + /*runtime_specs=*/delegate_runtime_specs, + /*method_meta=*/&method_meta); Error err = BackendDelegate::Init( delegate, program_, backend_init_context, &delegates_[i]); if (err != Error::Ok) { diff --git a/runtime/executor/test/backend_integration_test.cpp b/runtime/executor/test/backend_integration_test.cpp index e395b23bf2d..594f7070120 100644 --- a/runtime/executor/test/backend_integration_test.cpp +++ b/runtime/executor/test/backend_integration_test.cpp @@ -610,6 +610,34 @@ TEST_P(BackendIntegrationTest, GetMethodNameDuringInitSuccess) { ASSERT_EQ(program.error(), Error::Ok); } +TEST_P(BackendIntegrationTest, MethodMetaPassedToBackendInitContext) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + Result program = Program::load(&loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + bool init_called = false; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + BackendInitContext& context) -> Result { + init_called = true; + const auto* meta = context.method_meta(); + EXPECT_NE(meta, nullptr); + if (meta != nullptr) { + EXPECT_STREQ(meta->name(), "forward"); + EXPECT_TRUE(meta->uses_backend(StubBackend::kName)); + } + processed->Free(); + return nullptr; + }); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + EXPECT_TRUE(init_called); +} + TEST_P(BackendIntegrationTest, GetMethodNameDuringExecuteSuccess) { Result loader = FileDataLoader::from(program_path()); ASSERT_EQ(loader.error(), Error::Ok); diff --git a/schema/targets.bzl b/schema/targets.bzl index 0528f54536d..7f8d66f7a42 100644 --- a/schema/targets.bzl +++ b/schema/targets.bzl @@ -80,9 +80,10 @@ def define_common_targets(): "//executorch/runtime/executor/...", "//executorch/backends/native/extension/module/...", # Tests have a set up which uses raw flatbuffer. - # TODO will refactor these setup steps into + # TODO will refactor these setup steps into # testing utils in runtime/executor/... path "//executorch/backends/xnnpack/test/...", + "//executorch/runtime/backend/test/...", ], exported_headers = { OUTPUT_PROGRAM_HEADER: ":{}[{}]".format(PROGRAM_GEN_RULE_NAME, OUTPUT_PROGRAM_HEADER),