Skip to content

Commit 5c53807

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 8e21f20 commit 5c53807

File tree

4 files changed

+279
-1
lines changed

4 files changed

+279
-1
lines changed

runtime/backend/options_map.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
#pragma once
10+
11+
#include <executorch/runtime/backend/options.h>
12+
#include <executorch/runtime/core/error.h>
13+
#include <executorch/runtime/core/span.h>
14+
#include <cstring>
15+
namespace executorch {
16+
namespace runtime {
17+
18+
struct Entry {
19+
const char* backend_name;
20+
Span<BackendOption> options;
21+
};
22+
23+
template <size_t MaxBackends>
24+
class BackendOptionsMap {
25+
public:
26+
// Default constructor
27+
BackendOptionsMap() : size_(0) {}
28+
29+
// Add a new backend configuration
30+
Error add(
31+
const char* backend_name,
32+
::executorch::runtime::Span<BackendOption> options) {
33+
if (size_ < MaxBackends) {
34+
entries_[size_] = {backend_name, options};
35+
++size_;
36+
return Error::Ok;
37+
} else {
38+
ET_LOG(Error, "Maximum number of backends %lu reached", MaxBackends);
39+
}
40+
return Error::InvalidArgument;
41+
}
42+
43+
// Get options for a specific backend (const version)
44+
::executorch::runtime::Span<const BackendOption> get(
45+
const char* backend_name) const {
46+
for (size_t i = 0; i < size_; ++i) {
47+
if (std::strcmp(entries_[i].backend_name, backend_name) == 0) {
48+
return ::executorch::runtime::Span<const BackendOption>(
49+
entries_[i].options.data(), entries_[i].options.size());
50+
}
51+
}
52+
return {}; // Return empty Span if not found
53+
}
54+
55+
// Get options for a specific backend (non-const version)
56+
::executorch::runtime::Span<BackendOption> get(const char* backend_name) {
57+
for (size_t i = 0; i < size_; ++i) {
58+
if (std::strcmp(entries_[i].backend_name, backend_name) == 0) {
59+
return entries_[i].options;
60+
}
61+
}
62+
return {}; // Return empty Span if not found
63+
}
64+
65+
// Get a view of the entries (const version)
66+
::executorch::runtime::Span<const Entry> entries() const {
67+
return ::executorch::runtime::Span<const Entry>(entries_, size_);
68+
}
69+
70+
// Get a view of the entries (non-const version)
71+
::executorch::runtime::Span<Entry> entries() {
72+
return ::executorch::runtime::Span<Entry>(entries_, size_);
73+
}
74+
75+
// Get number of entries
76+
size_t size() const {
77+
return size_;
78+
}
79+
80+
private:
81+
Entry entries_[MaxBackends]; // Storage for backend entries
82+
size_t size_ = 0; // Current number of entries
83+
};
84+
85+
} // namespace runtime
86+
} // 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 = "options" + aten_suffix,
14+
exported_headers = [
15+
"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_option_context.h",
21-
"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:options" + aten_suffix,
54+
],
55+
)
56+
57+
runtime.cxx_library(
58+
name = "options_map" + aten_suffix,
59+
exported_headers = [
60+
"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+
":options" + aten_suffix,
3570
],
3671
)
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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/options.h>
10+
#include <executorch/runtime/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::Error;
20+
using executorch::runtime::OptionKey;
21+
22+
namespace executorch {
23+
namespace runtime {
24+
25+
class BackendOptionsMapTest : public ::testing::Test {
26+
protected:
27+
void SetUp() override {
28+
// Initialize any necessary runtime components
29+
executorch::runtime::runtime_init();
30+
}
31+
// Assume 3 backends, each with max 5 options
32+
BackendOptionsMap<3> map;
33+
};
34+
35+
TEST_F(BackendOptionsMapTest, BasicAddAndRetrieve) {
36+
BackendOptions<5> cpu_options;
37+
38+
cpu_options.set_option("use_fp16", true);
39+
cpu_options.set_option("thead", 4);
40+
map.add("CPU", cpu_options.view());
41+
42+
auto retrieved = map.get("CPU");
43+
EXPECT_GE(retrieved.size(), 1);
44+
45+
// bool value;
46+
bool found = false;
47+
for (auto retrieved_option : retrieved) {
48+
if (strcmp(retrieved_option.key, "use_fp16") == 0) {
49+
EXPECT_EQ(std::get<bool>(retrieved_option.value), true);
50+
found = true;
51+
}
52+
}
53+
EXPECT_TRUE(found);
54+
}
55+
56+
TEST_F(BackendOptionsMapTest, CapacityLimits) {
57+
BackendOptionsMap<2> small_map; // Only 2 backends capacity
58+
59+
BackendOptions<5> options;
60+
ASSERT_EQ(small_map.add("CPU", options.view()), Error::Ok);
61+
ASSERT_EQ(small_map.add("GPU", options.view()), Error::Ok);
62+
// Return error if it exceeds capacity
63+
ASSERT_EQ(small_map.add("NPU", options.view()), Error::InvalidArgument);
64+
}
65+
66+
TEST_F(BackendOptionsMapTest, EntryIteration) {
67+
BackendOptions<2> cpu_options;
68+
BackendOptions<3> gpu_options;
69+
70+
// Add to map using Span
71+
ASSERT_EQ(map.add("CPU", cpu_options.view()), Error::Ok);
72+
ASSERT_EQ(map.add("GPU", gpu_options.view()), Error::Ok);
73+
74+
auto entries = map.entries();
75+
// Should have 2 backends (entries)
76+
ASSERT_EQ(entries.size(), 2);
77+
78+
bool found_cpu = false;
79+
bool found_gpu = false;
80+
for (const auto& entry : entries) {
81+
if (strcmp(entry.backend_name, "CPU") == 0)
82+
found_cpu = true;
83+
if (strcmp(entry.backend_name, "GPU") == 0)
84+
found_gpu = true;
85+
}
86+
// Should find CPU and GPU in the entries
87+
EXPECT_TRUE(found_cpu);
88+
EXPECT_TRUE(found_gpu);
89+
}
90+
91+
TEST_F(BackendOptionsMapTest, ConstCorrectness) {
92+
auto cpu_options = BackendOptions<5>();
93+
ASSERT_EQ(map.add("CPU", cpu_options.view()), Error::Ok);
94+
95+
const auto& const_map = map;
96+
auto options_retrived = const_map.get("CPU");
97+
EXPECT_EQ(options_retrived.size(), 0);
98+
99+
auto entries = const_map.entries();
100+
EXPECT_FALSE(entries.empty());
101+
}
102+
103+
TEST_F(BackendOptionsMapTest, EmptyMapBehavior) {
104+
EXPECT_EQ(map.get("CPU").size(), 0);
105+
EXPECT_TRUE(map.entries().empty());
106+
EXPECT_EQ(map.entries().size(), 0);
107+
}
108+
109+
TEST_F(BackendOptionsMapTest, OptionIsolation) {
110+
BackendOptions<2> cpu_options;
111+
cpu_options.set_option("Debug", true);
112+
cpu_options.set_option("NumThreads", 3);
113+
114+
BackendOptions<3> gpu_options;
115+
gpu_options.set_option("Profile", true);
116+
gpu_options.set_option("Mem", 1024);
117+
gpu_options.set_option("Hardware", "H100");
118+
119+
// Add to map using Span
120+
map.add("CPU", cpu_options.view());
121+
map.add("GPU", gpu_options.view());
122+
123+
// Test CPU options
124+
auto cpu_opts = map.get("CPU");
125+
ASSERT_FALSE(cpu_opts.empty());
126+
127+
// Verify CPU has its own option
128+
EXPECT_EQ(cpu_opts.size(), 2);
129+
EXPECT_STREQ(cpu_opts[0].key, "Debug");
130+
EXPECT_EQ(std::get<bool>(cpu_opts[0].value), true);
131+
EXPECT_STREQ(cpu_opts[1].key, "NumThreads");
132+
EXPECT_EQ(std::get<int>(cpu_opts[1].value), 3);
133+
134+
// Test GPU options
135+
auto gpu_opts = map.get("GPU");
136+
ASSERT_FALSE(gpu_opts.empty());
137+
138+
// Verify GPU has its own option
139+
EXPECT_EQ(gpu_opts.size(), 3);
140+
EXPECT_STREQ(gpu_opts[0].key, "Profile");
141+
EXPECT_EQ(std::get<bool>(gpu_opts[0].value), true);
142+
EXPECT_STREQ(gpu_opts[1].key, "Mem");
143+
EXPECT_EQ(std::get<int>(gpu_opts[1].value), 1024);
144+
EXPECT_STREQ(gpu_opts[2].key, "Hardware");
145+
EXPECT_STREQ(std::get<const char*>(gpu_opts[2].value), "H100");
146+
}
147+
} // namespace runtime
148+
} // 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: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)