Skip to content

Commit 8808b3e

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

File tree

6 files changed

+255
-0
lines changed

6 files changed

+255
-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: 10 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,15 @@ class Method final {
240241
/// DEPRECATED: Use `reset_execution()` instead.
241242
ET_DEPRECATED ET_NODISCARD Error experimental_reset_execution();
242243

244+
/**
245+
* EXPERIMENTAL: Advances/executes a single instruction in the method.
246+
*
247+
* @retval Error::Ok step succeeded
248+
* @retval non-Ok step failed
249+
* @retval Error::EndOfMethod method finished executing successfully
250+
*/
251+
ET_EXPERIMENTAL ET_NODISCARD Error update(executorch::runtime::ArrayRef<executorch::runtime::Entry> backend_option);
252+
243253
/**
244254
* Returns the MethodMeta that corresponds to the calling Method.
245255
*/

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: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
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::OptionType;
48+
using executorch::runtime::CompileSpec;
49+
using executorch::runtime::DataLoader;
50+
using executorch::runtime::DelegateHandle;
51+
using executorch::runtime::FreeableBuffer;
52+
53+
constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U;
54+
constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U;
55+
56+
/**
57+
* A backend class whose methods can be overridden individually.
58+
*/
59+
class StubBackend final : public BackendInterface {
60+
public:
61+
62+
// Default name that this backend is registered as.
63+
static constexpr char kName[] = "StubBackend";
64+
65+
bool is_available() const override {
66+
return true;
67+
}
68+
69+
Result<DelegateHandle*> init(
70+
BackendInitContext& context,
71+
FreeableBuffer* processed,
72+
ArrayRef<CompileSpec> compile_specs) const override {
73+
return nullptr;
74+
}
75+
76+
Error execute(
77+
BackendExecutionContext& context,
78+
DelegateHandle* handle,
79+
EValue** args) const override {
80+
return Error::Ok;
81+
}
82+
83+
int num_threads() const {
84+
return num_threads_;
85+
}
86+
87+
Error update(
88+
BackendUpdateContext& context,
89+
const executorch::runtime::ArrayRef<BackendOption>& backend_options) const override {
90+
int success_update = 0;
91+
for (const auto& backend_option : backend_options) {
92+
if (strcmp(backend_option.key, "NumberOfThreads") == 0) {
93+
if (backend_option.type == OptionType::INT) {
94+
num_threads_ = backend_option.value.int_value;
95+
success_update++;
96+
}
97+
}
98+
}
99+
if (success_update == backend_options.size()) {
100+
return Error::Ok;
101+
}
102+
return Error::InvalidArgument;
103+
}
104+
105+
/**
106+
* Registers the singleton instance if not already registered.
107+
*
108+
* Note that this can be used to install the stub as the implementation for
109+
* any export-time backend by passing in the right name, as long as no other
110+
* backend with that name has been registered yet.
111+
*/
112+
static Error register_singleton(const char* name = kName) {
113+
if (!registered_) {
114+
registered_ = true;
115+
return executorch::runtime::register_backend({name, &singleton_});
116+
}
117+
return Error::Ok;
118+
}
119+
120+
/**
121+
* Returns the instance that was added to the backend registry.
122+
*/
123+
static StubBackend& singleton() {
124+
return singleton_;
125+
}
126+
127+
private:
128+
static bool registered_;
129+
static StubBackend singleton_;
130+
mutable int num_threads_ = 1;
131+
};
132+
133+
bool StubBackend::registered_ = false;
134+
StubBackend StubBackend::singleton_;
135+
136+
class MethodUpdateTest : public ::testing::Test {
137+
protected:
138+
void load_program() {
139+
// Since these tests cause ET_LOG to be called, the PAL must be initialized
140+
// first.
141+
executorch::runtime::runtime_init();
142+
143+
// Create a loader for the serialized program.
144+
ASSERT_EQ(StubBackend::register_singleton(), Error::Ok);
145+
146+
auto loader_res = FileDataLoader::from(std::getenv("ET_MODULE_ADD_MUL_DELEGATED_PATH"));
147+
ASSERT_EQ(loader_res.error(), Error::Ok);
148+
loader_ = std::make_unique<FileDataLoader>(std::move(loader_res.get()));
149+
150+
// Use it to load the program.
151+
auto program_res = Program::load(loader_.get());
152+
ASSERT_EQ(program_res.error(), Error::Ok);
153+
program_ = std::make_unique<Program>(std::move(program_res.get()));
154+
}
155+
156+
void SetUp() override {
157+
executorch::runtime::runtime_init();
158+
159+
load_program();
160+
}
161+
162+
private:
163+
std::unique_ptr<FileDataLoader> loader_;
164+
165+
protected:
166+
std::unique_ptr<Program> program_;
167+
};
168+
169+
TEST_F(MethodUpdateTest, MoveTest) {
170+
BackendInterface* backend =
171+
executorch::runtime::get_backend_class(StubBackend::kName);
172+
ASSERT_EQ(backend, &StubBackend::singleton());
173+
174+
ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes);
175+
Result<Method> method = program_->load_method("forward", &mmm.get());
176+
// Check that the default number of threads is 1.
177+
ASSERT_EQ(StubBackend::singleton().num_threads(), 1);
178+
ASSERT_EQ(method.error(), Error::Ok);
179+
180+
BackendOptionsMap<3> map;
181+
BackendOptions<1> backend_options;
182+
int new_num_threads = 4;
183+
backend_options.set_option(IntKey("NumberOfThreads"), new_num_threads);
184+
map.add("StubBackend", backend_options.view());
185+
Error update_result = method->update(map.entries());
186+
ASSERT_EQ(update_result, Error::Ok);
187+
ASSERT_EQ(StubBackend::singleton().num_threads(), new_num_threads);
188+
}

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)