Skip to content

Commit 694185b

Browse files
committed
[5/N] Add update in method
Pull Request resolved: #11463 Expose the update API in method. This API will take BackendOptionMap as input and call backend_interface->update under the hood. ghstack-source-id: 290372282 @exported-using-ghexport Differential Revision: [D76149467](https://our.internmc.facebook.com/intern/diff/D76149467/)
1 parent 686b151 commit 694185b

File tree

6 files changed

+253
-0
lines changed

6 files changed

+253
-0
lines changed

runtime/executor/method.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <cstdint>
1515
#include <cstdio>
1616

17+
#include <executorch/runtime/backend/backend_options_map.h>
1718
#include <executorch/runtime/backend/interface.h>
1819
#include <executorch/runtime/core/event_tracer_hooks.h>
1920
#include <executorch/runtime/core/exec_aten/util/tensor_util.h>
@@ -1512,6 +1513,26 @@ Error Method::experimental_step() {
15121513
return step();
15131514
}
15141515

1516+
Error Method::update(executorch::runtime::ArrayRef<executorch::runtime::Entry> backend_option) {
1517+
for (const auto& entry : backend_option) {
1518+
const char* backend_name = entry.backend_name;
1519+
auto backend_options = entry.options;
1520+
1521+
auto backend_class = get_backend_class(backend_name);
1522+
if (!backend_class) {
1523+
return Error::NotFound;
1524+
}
1525+
1526+
BackendUpdateContext backend_update_context;
1527+
auto update_result =
1528+
backend_class->update(backend_update_context, backend_options);
1529+
if (update_result != Error::Ok) {
1530+
return update_result;
1531+
}
1532+
}
1533+
return Error::Ok;
1534+
}
1535+
15151536
Error Method::execute() {
15161537
internal::event_tracer_create_event_block(event_tracer_, "Execute");
15171538
EventTracerEntry event_tracer_entry =

runtime/executor/method.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1515
#endif
1616

17+
#include <executorch/runtime/backend/backend_options_map.h>
1718
#include <executorch/runtime/core/evalue.h>
1819
#include <executorch/runtime/core/event_tracer.h>
1920
#include <executorch/runtime/core/exec_aten/exec_aten.h>
@@ -240,6 +241,14 @@ class Method final {
240241
/// DEPRECATED: Use `reset_execution()` instead.
241242
ET_DEPRECATED ET_NODISCARD Error experimental_reset_execution();
242243

244+
/**
245+
* EXPERIMENTAL: Update backend options, which will be dispatched to different backends.
246+
*
247+
* @retval Error::Ok step succeeded
248+
* @retval non-Ok Method update fails
249+
*/
250+
ET_EXPERIMENTAL ET_NODISCARD Error update(executorch::runtime::ArrayRef<executorch::runtime::Entry> backend_option);
251+
243252
/**
244253
* Returns the MethodMeta that corresponds to the calling Method.
245254
*/

runtime/executor/targets.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def define_common_targets():
108108
":memory_manager",
109109
":pte_data_map" + aten_suffix,
110110
"//executorch/runtime/backend:interface" + aten_suffix,
111+
"//executorch/runtime/backend:backend_options_map" + aten_suffix,
111112
"//executorch/runtime/core:core",
112113
"//executorch/runtime/core:named_data_map" + aten_suffix,
113114
"//executorch/runtime/core:evalue" + aten_suffix,
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
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+
9+
#include <cstdlib>
10+
#include <filesystem>
11+
12+
#include <executorch/extension/data_loader/file_data_loader.h>
13+
#include <executorch/runtime/core/exec_aten/exec_aten.h>
14+
#include <executorch/runtime/executor/method.h>
15+
#include <executorch/runtime/executor/program.h>
16+
#include <executorch/runtime/executor/test/managed_memory_manager.h>
17+
#include <executorch/runtime/platform/runtime.h>
18+
#include <executorch/test/utils/DeathTest.h>
19+
#include <gtest/gtest.h>
20+
#include <executorch/runtime/backend/interface.h>
21+
#include <executorch/runtime/backend/backend_update_context.h>
22+
#include <executorch/runtime/backend/backend_options.h>
23+
#include <executorch/runtime/backend/backend_options_map.h>
24+
#include <executorch/runtime/core/error.h>
25+
#include <executorch/runtime/core/result.h>
26+
27+
28+
using namespace ::testing;
29+
using executorch::aten::ArrayRef;
30+
using executorch::runtime::Error;
31+
using executorch::runtime::EValue;
32+
using executorch::runtime::Method;
33+
using executorch::runtime::Program;
34+
using executorch::runtime::Result;
35+
using executorch::runtime::testing::ManagedMemoryManager;
36+
using torch::executor::util::FileDataLoader;
37+
using executorch::runtime::BackendExecutionContext;
38+
using executorch::runtime::BackendInitContext;
39+
using executorch::runtime::BackendInterface;
40+
using executorch::runtime::BackendUpdateContext;
41+
using executorch::runtime::BackendOption;
42+
using executorch::runtime::BackendOptions;
43+
using executorch::runtime::BackendOptionsMap;
44+
using executorch::runtime::BoolKey;
45+
using executorch::runtime::IntKey;
46+
using executorch::runtime::Entry;
47+
using executorch::runtime::CompileSpec;
48+
using executorch::runtime::DataLoader;
49+
using executorch::runtime::DelegateHandle;
50+
using executorch::runtime::FreeableBuffer;
51+
52+
constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U;
53+
constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U;
54+
55+
/**
56+
* A backend class whose methods can be overridden individually.
57+
*/
58+
class StubBackend final : public BackendInterface {
59+
public:
60+
61+
// Default name that this backend is registered as.
62+
static constexpr char kName[] = "StubBackend";
63+
64+
bool is_available() const override {
65+
return true;
66+
}
67+
68+
Result<DelegateHandle*> init(
69+
BackendInitContext& context,
70+
FreeableBuffer* processed,
71+
ArrayRef<CompileSpec> compile_specs) const override {
72+
return nullptr;
73+
}
74+
75+
Error execute(
76+
BackendExecutionContext& context,
77+
DelegateHandle* handle,
78+
EValue** args) const override {
79+
return Error::Ok;
80+
}
81+
82+
int num_threads() const {
83+
return num_threads_;
84+
}
85+
86+
Error update(
87+
BackendUpdateContext& context,
88+
const executorch::runtime::ArrayRef<BackendOption>& backend_options) const override {
89+
int success_update = 0;
90+
for (const auto& backend_option : backend_options) {
91+
if (strcmp(backend_option.key, "NumberOfThreads") == 0) {
92+
if (std::holds_alternative<int>(backend_option.value)) {
93+
num_threads_ = std::get<int>(backend_option.value);
94+
success_update++;
95+
}
96+
}
97+
}
98+
if (success_update == backend_options.size()) {
99+
return Error::Ok;
100+
}
101+
return Error::InvalidArgument;
102+
}
103+
104+
/**
105+
* Registers the singleton instance if not already registered.
106+
*
107+
* Note that this can be used to install the stub as the implementation for
108+
* any export-time backend by passing in the right name, as long as no other
109+
* backend with that name has been registered yet.
110+
*/
111+
static Error register_singleton(const char* name = kName) {
112+
if (!registered_) {
113+
registered_ = true;
114+
return executorch::runtime::register_backend({name, &singleton_});
115+
}
116+
return Error::Ok;
117+
}
118+
119+
/**
120+
* Returns the instance that was added to the backend registry.
121+
*/
122+
static StubBackend& singleton() {
123+
return singleton_;
124+
}
125+
126+
private:
127+
static bool registered_;
128+
static StubBackend singleton_;
129+
mutable int num_threads_ = 1;
130+
};
131+
132+
bool StubBackend::registered_ = false;
133+
StubBackend StubBackend::singleton_;
134+
135+
class MethodUpdateTest : public ::testing::Test {
136+
protected:
137+
void load_program() {
138+
// Since these tests cause ET_LOG to be called, the PAL must be initialized
139+
// first.
140+
executorch::runtime::runtime_init();
141+
142+
// Create a loader for the serialized program.
143+
ASSERT_EQ(StubBackend::register_singleton(), Error::Ok);
144+
145+
auto loader_res = FileDataLoader::from(std::getenv("ET_MODULE_ADD_MUL_DELEGATED_PATH"));
146+
ASSERT_EQ(loader_res.error(), Error::Ok);
147+
loader_ = std::make_unique<FileDataLoader>(std::move(loader_res.get()));
148+
149+
// Use it to load the program.
150+
auto program_res = Program::load(loader_.get());
151+
ASSERT_EQ(program_res.error(), Error::Ok);
152+
program_ = std::make_unique<Program>(std::move(program_res.get()));
153+
}
154+
155+
void SetUp() override {
156+
executorch::runtime::runtime_init();
157+
158+
load_program();
159+
}
160+
161+
private:
162+
std::unique_ptr<FileDataLoader> loader_;
163+
164+
protected:
165+
std::unique_ptr<Program> program_;
166+
};
167+
168+
TEST_F(MethodUpdateTest, MoveTest) {
169+
BackendInterface* backend =
170+
executorch::runtime::get_backend_class(StubBackend::kName);
171+
ASSERT_EQ(backend, &StubBackend::singleton());
172+
173+
ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes);
174+
Result<Method> method = program_->load_method("forward", &mmm.get());
175+
// Check that the default number of threads is 1.
176+
ASSERT_EQ(StubBackend::singleton().num_threads(), 1);
177+
ASSERT_EQ(method.error(), Error::Ok);
178+
179+
BackendOptionsMap<3> map;
180+
BackendOptions<1> backend_options;
181+
int new_num_threads = 4;
182+
backend_options.set_option(IntKey("NumberOfThreads"), new_num_threads);
183+
map.add("StubBackend", backend_options.view());
184+
Error update_result = method->update(map.entries());
185+
ASSERT_EQ(update_result, Error::Ok);
186+
ASSERT_EQ(StubBackend::singleton().num_threads(), new_num_threads);
187+
}

runtime/executor/test/targets.bzl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,23 @@ def define_common_targets(is_fbcode = False):
170170
env = modules_env,
171171
)
172172

173+
174+
runtime.cxx_test(
175+
name = "method_update_test",
176+
srcs = [
177+
"method_update_test.cpp",
178+
],
179+
deps = [
180+
":managed_memory_manager",
181+
"//executorch/runtime/backend:interface",
182+
"//executorch/runtime/executor:program",
183+
"//executorch/extension/data_loader:buffer_data_loader",
184+
"//executorch/extension/data_loader:file_data_loader",
185+
],
186+
env = {
187+
"ET_MODULE_ADD_MUL_DELEGATED_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul.pte])",
188+
}, )
189+
173190
runtime.cxx_test(
174191
name = "program_test",
175192
srcs = [

test/models/targets.bzl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,21 @@ def define_common_targets():
248248
"//executorch/test/...",
249249
],
250250
)
251+
252+
runtime.genrule(
253+
name = "exported_executor_backend_program_linear",
254+
cmd = "$(exe :export_delegated_program)" +
255+
" --modules ModuleLinear" +
256+
" --backend_id ExecutorBackend" +
257+
" --outdir $OUT",
258+
259+
outs = {
260+
"ExcuTorchBackendLinear.pte": ["ExcuTorchBackendLinear.pte"],
261+
},
262+
default_outs = ["."],
263+
visibility = [
264+
"//executorch/runtime/executor/test/...",
265+
"//executorch/extension/flat_tensor/test/...",
266+
"//executorch/test/...",
267+
],
268+
)

0 commit comments

Comments
 (0)