Skip to content

Commit 686b151

Browse files
committed
[4/N] Add backend options map
Pull Request resolved: #11462 This is to manage the backend <-> BackendOptions map. Users will create the bakcend options map, and ET runtime will read the backend name, and dispatch the list of backend options to each backend. ghstack-source-id: 290371659 @exported-using-ghexport Differential Revision: [D76149466](https://our.internmc.facebook.com/intern/diff/D76149466/)
1 parent 5c9c342 commit 686b151

File tree

4 files changed

+270
-1
lines changed

4 files changed

+270
-1
lines changed

runtime/backend/backend_options_map.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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 <executorch/runtime/backend/backend_options.h>
10+
#include <executorch/runtime/core/error.h>
11+
#include <cstring>
12+
13+
#pragma once
14+
namespace executorch {
15+
namespace runtime {
16+
17+
struct Entry {
18+
const char* backend_name;
19+
ArrayRef<BackendOption> options;
20+
};
21+
22+
template <size_t MaxBackends>
23+
class BackendOptionsMap {
24+
public:
25+
// Default constructor
26+
BackendOptionsMap() : size_(0) {}
27+
28+
// Add a new backend configuration
29+
Error add(
30+
const char* backend_name,
31+
::executorch::runtime::ArrayRef<BackendOption> options) {
32+
if (size_ < MaxBackends) {
33+
entries_[size_] = {backend_name, options};
34+
++size_;
35+
return Error::Ok;
36+
} else {
37+
ET_LOG(Error, "Maximum number of backends %lu reached", MaxBackends);
38+
}
39+
return Error::InvalidArgument;
40+
}
41+
42+
// Get options for a specific backend
43+
::executorch::runtime::ArrayRef<BackendOption> get(
44+
const char* backend_name) const {
45+
for (size_t i = 0; i < size_; ++i) {
46+
if (std::strcmp(entries_[i].backend_name, backend_name) == 0) {
47+
return entries_[i].options;
48+
}
49+
}
50+
return {}; // Return empty ArrayRef if not found
51+
}
52+
53+
// Get a view of the entries (const version)
54+
::executorch::runtime::ArrayRef<const Entry> entries() const {
55+
return ::executorch::runtime::ArrayRef<const Entry>(entries_, size_);
56+
}
57+
58+
// Get a view of the entries (non-const version)
59+
::executorch::runtime::ArrayRef<Entry> entries() {
60+
return ::executorch::runtime::ArrayRef<Entry>(entries_, size_);
61+
}
62+
63+
// Get number of entries
64+
size_t size() const {
65+
return size_;
66+
}
67+
68+
private:
69+
Entry entries_[MaxBackends]; // Storage for backend entries
70+
size_t size_ = 0; // Current number of entries
71+
};
72+
73+
} // namespace runtime
74+
} // namespace executorch

runtime/backend/targets.bzl

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,25 @@ def define_common_targets():
99

1010
for aten_mode in get_aten_mode_options():
1111
aten_suffix = ("_aten" if aten_mode else "")
12+
runtime.cxx_library(
13+
name = "backend_options" + aten_suffix,
14+
exported_headers = [
15+
"backend_options.h",
16+
],
17+
preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [],
18+
visibility = [
19+
"//executorch/...",
20+
"@EXECUTORCH_CLIENTS",
21+
],
22+
exported_deps = [
23+
"//executorch/runtime/core:core",
24+
"//executorch/runtime/core:evalue" + aten_suffix,
25+
"//executorch/runtime/core:event_tracer" + aten_suffix,
26+
"//executorch/runtime/core:memory_allocator",
27+
"//executorch/runtime/core:named_data_map",
28+
],
29+
)
30+
1231
runtime.cxx_library(
1332
name = "interface" + aten_suffix,
1433
srcs = [
@@ -18,7 +37,6 @@ def define_common_targets():
1837
"backend_execution_context.h",
1938
"backend_init_context.h",
2039
"backend_update_context.h",
21-
"backend_options.h",
2240
"interface.h",
2341
],
2442
preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [],
@@ -32,5 +50,22 @@ def define_common_targets():
3250
"//executorch/runtime/core:event_tracer" + aten_suffix,
3351
"//executorch/runtime/core:memory_allocator",
3452
"//executorch/runtime/core:named_data_map",
53+
"//executorch/runtime/backend:backend_options" + aten_suffix,
54+
],
55+
)
56+
57+
runtime.cxx_library(
58+
name = "backend_options_map" + aten_suffix,
59+
exported_headers = [
60+
"backend_options_map.h",
61+
],
62+
preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [],
63+
visibility = [
64+
"//executorch/...",
65+
"@EXECUTORCH_CLIENTS",
66+
],
67+
exported_deps = [
68+
"//executorch/runtime/core:core",
69+
":backend_options" + aten_suffix,
3570
],
3671
)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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 <executorch/runtime/backend/backend_options.h>
10+
#include <executorch/runtime/backend/backend_options_map.h>
11+
#include <executorch/runtime/platform/runtime.h>
12+
13+
#include <gtest/gtest.h>
14+
15+
using namespace ::testing;
16+
using executorch::runtime::BackendOption;
17+
using executorch::runtime::BackendOptions;
18+
using executorch::runtime::BackendOptionsMap;
19+
using executorch::runtime::BoolKey;
20+
using executorch::runtime::Error;
21+
using executorch::runtime::IntKey;
22+
using executorch::runtime::OptionKey;
23+
using executorch::runtime::StrKey;
24+
25+
namespace executorch {
26+
namespace runtime {
27+
28+
class BackendOptionsMapTest : public ::testing::Test {
29+
protected:
30+
void SetUp() override {
31+
// Initialize any necessary runtime components
32+
executorch::runtime::runtime_init();
33+
}
34+
// Assume 3 backends, each with max 5 options
35+
BackendOptionsMap<3> map;
36+
};
37+
38+
TEST_F(BackendOptionsMapTest, BasicAddAndRetrieve) {
39+
BackendOptions<5> cpu_options;
40+
41+
cpu_options.set_option(BoolKey("use_fp16"), true);
42+
cpu_options.set_option(IntKey("thead"), 4);
43+
map.add("CPU", cpu_options.view());
44+
45+
auto retrieved = map.get("CPU");
46+
EXPECT_GE(retrieved.size(), 1);
47+
48+
// bool value;
49+
bool found = false;
50+
for (auto retrieved_option : retrieved) {
51+
if (strcmp(retrieved_option.key, "use_fp16") == 0) {
52+
EXPECT_EQ(std::get<bool>(retrieved_option.value), true);
53+
found = true;
54+
}
55+
}
56+
EXPECT_TRUE(found);
57+
}
58+
59+
TEST_F(BackendOptionsMapTest, CapacityLimits) {
60+
BackendOptionsMap<2> small_map; // Only 2 backends capacity
61+
62+
BackendOptions<5> options;
63+
ASSERT_EQ(small_map.add("CPU", options.view()), Error::Ok);
64+
ASSERT_EQ(small_map.add("GPU", options.view()), Error::Ok);
65+
// Return error if it exceeds capacity
66+
ASSERT_EQ(small_map.add("NPU", options.view()), Error::InvalidArgument);
67+
}
68+
69+
TEST_F(BackendOptionsMapTest, EntryIteration) {
70+
BackendOptions<2> cpu_options;
71+
BackendOptions<3> gpu_options;
72+
73+
// Add to map using ArrayRef
74+
ASSERT_EQ(map.add("CPU", cpu_options.view()), Error::Ok);
75+
ASSERT_EQ(map.add("GPU", gpu_options.view()), Error::Ok);
76+
77+
auto entries = map.entries();
78+
// Should have 2 backends (entries)
79+
ASSERT_EQ(entries.size(), 2);
80+
81+
bool found_cpu = false;
82+
bool found_gpu = false;
83+
for (const auto& entry : entries) {
84+
if (strcmp(entry.backend_name, "CPU") == 0)
85+
found_cpu = true;
86+
if (strcmp(entry.backend_name, "GPU") == 0)
87+
found_gpu = true;
88+
}
89+
// Should find CPU and GPU in the entries
90+
EXPECT_TRUE(found_cpu);
91+
EXPECT_TRUE(found_gpu);
92+
}
93+
94+
TEST_F(BackendOptionsMapTest, ConstCorrectness) {
95+
auto cpu_options = BackendOptions<5>();
96+
ASSERT_EQ(map.add("CPU", cpu_options.view()), Error::Ok);
97+
98+
const auto& const_map = map;
99+
auto options_retrived = const_map.get("CPU");
100+
EXPECT_EQ(options_retrived.size(), 0);
101+
102+
auto entries = const_map.entries();
103+
EXPECT_FALSE(entries.empty());
104+
}
105+
106+
TEST_F(BackendOptionsMapTest, EmptyMapBehavior) {
107+
EXPECT_EQ(map.get("CPU").size(), 0);
108+
EXPECT_TRUE(map.entries().empty());
109+
EXPECT_EQ(map.entries().size(), 0);
110+
}
111+
112+
TEST_F(BackendOptionsMapTest, OptionIsolation) {
113+
BackendOptions<2> cpu_options;
114+
cpu_options.set_option(BoolKey("Debug"), true);
115+
cpu_options.set_option(IntKey("NumThreads"), 3);
116+
117+
BackendOptions<3> gpu_options;
118+
gpu_options.set_option(BoolKey("Profile"), true);
119+
gpu_options.set_option(IntKey("Mem"), 1024);
120+
gpu_options.set_option(StrKey("Hardware"), "H100");
121+
122+
// Add to map using ArrayRef
123+
map.add("CPU", cpu_options.view());
124+
map.add("GPU", gpu_options.view());
125+
126+
// Test CPU options
127+
auto cpu_opts = map.get("CPU");
128+
ASSERT_FALSE(cpu_opts.empty());
129+
130+
// Verify CPU has its own option
131+
EXPECT_EQ(cpu_opts.size(), 2);
132+
EXPECT_EQ(cpu_opts[0].key, "Debug");
133+
EXPECT_EQ(std::get<bool>(cpu_opts[0].value), true);
134+
EXPECT_EQ(cpu_opts[1].key, "NumThreads");
135+
EXPECT_EQ(std::get<int>(cpu_opts[1].value), 3);
136+
137+
// Test GPU options
138+
auto gpu_opts = map.get("GPU");
139+
ASSERT_FALSE(gpu_opts.empty());
140+
141+
// Verify GPU has its own option
142+
EXPECT_EQ(gpu_opts.size(), 3);
143+
EXPECT_EQ(gpu_opts[0].key, "Profile");
144+
EXPECT_EQ(std::get<bool>(gpu_opts[0].value), true);
145+
EXPECT_EQ(gpu_opts[1].key, "Mem");
146+
EXPECT_EQ(std::get<int>(gpu_opts[1].value), 1024);
147+
EXPECT_EQ(gpu_opts[2].key, "Hardware");
148+
EXPECT_EQ(std::get<const char*>(gpu_opts[2].value), "H100");
149+
}
150+
} // namespace runtime
151+
} // namespace executorch

runtime/backend/test/targets.bzl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ def define_common_targets():
1515
],
1616
)
1717

18+
runtime.cxx_test(
19+
name = "backend_options_map_test",
20+
srcs = ["backend_options_map_test.cpp"],
21+
deps = [
22+
"//executorch/runtime/core:core",
23+
"//executorch/runtime/backend:backend_options_map",
24+
],
25+
)
26+
1827
runtime.cxx_test(
1928
name = "backend_interface_update_test",
2029
srcs = ["backend_interface_update_test.cpp"],

0 commit comments

Comments
 (0)