Skip to content

Commit cb9236d

Browse files
authored
Merge branch 'main' into use-quantize_
2 parents 93e5e9f + 124758e commit cb9236d

File tree

7 files changed

+221
-23
lines changed

7 files changed

+221
-23
lines changed

.ci/scripts/benchmark_tooling/README.md

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ python3 .ci/scripts/benchmark_tooling/analyze_benchmark_stability.py \
7777

7878
##### Filtering Options:
7979

80-
- `--device-pools`: Filter by private device pool names (e.g., "samsung-galaxy-s22-5g", "samsung-galaxy-s22plus-5g")
80+
- `--device-pools`: Filter by device pool names (e.g., "apple_iphone_15_private", "samsung_s22_private")
8181
- `--backends`: Filter by specific backend names (e.g.,"xnnpack_q8")
82-
- `--models`: Filter by specific model names (e.g., "mv3", "meta-llama-llama-3.2-1b-instruct-qlora-int4-eo8")
82+
- `--models`: Filter by specific model names (e.g., "mv3", "meta-llama/Llama-3.2-1B-Instruct-SpinQuant_INT4_EO8")
8383

8484
#### Example Usage
8585

8686
Filter by multiple private device pools and models:
8787
```bash
8888
# This fetches all private table data for models 'llama-3.2-1B' and 'mv3'
89-
python3 get_benchmark_analysis_data.py \
89+
python3 .ci/scripts/benchmark_tooling/get_benchmark_analysis_data.py \
9090
--startTime "2025-06-01T00:00:00" \
9191
--endTime "2025-06-11T00:00:00" \
9292
--device-pools 'apple_iphone_15_private' 'samsung_s22_private' \
@@ -97,7 +97,7 @@ Filter by specific device pool and models:
9797
```bash
9898
# This fetches all private iPhone table data for models 'llama-3.2-1B' and 'mv3',
9999
# and associated public iPhone data
100-
python3 get_benchmark_analysis_data.py \
100+
python3 .ci/scripts/benchmark_tooling/get_benchmark_analysis_data.py \
101101
--startTime "2025-06-01T00:00:00" \
102102
--endTime "2025-06-11T00:00:00" \
103103
--device-pools 'apple_iphone_15_private' \
@@ -140,22 +140,6 @@ fetcher.run(
140140
end_time="2025-06-17T18:00:00"
141141
)
142142

143-
# Get results in different formats
144-
# As DataFrames
145-
df_results = fetcher.to_df()
146-
147-
# Export to Excel
148-
fetcher.to_excel(output_dir="./results")
149-
150-
# Export to CSV
151-
fetcher.to_csv(output_dir="./results")
152-
153-
# Export to JSON
154-
json_path = fetcher.to_json(output_dir="./results")
155-
156-
# Get raw dictionary results
157-
dict_results = fetcher.to_dict()
158-
159143
# Use the output_data method for flexible output
160144
results = fetcher.output_data(output_type="excel", output_dir="./results")
161145
```

backends/xnnpack/partition/config/generic_node_configs.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ def __init__(self, **kwargs):
107107
def supported_precision_types(self) -> List[ConfigPrecisionType]:
108108
return [ConfigPrecisionType.FP32, ConfigPrecisionType.STATIC_QUANT]
109109

110+
def check_constraints(self, node: torch.fx.Node, ep: ExportedProgram) -> bool:
111+
if not self.check_common_constraints(node, ep):
112+
return False
113+
# No support for add nodes with alpha != 1
114+
if "alpha" in node.kwargs and not np.isclose(
115+
node.kwargs["alpha"], 1.0, atol=1e-9, rtol=1e-9
116+
):
117+
why(node, reason="Add node doesn't support alpha != 1")
118+
return False
119+
return True
120+
110121

111122
class ReLUConfig(GenericNodePartitionerConfig):
112123
target_name = "relu.default"

backends/xnnpack/test/ops/test_add.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,27 @@ def forward(self, x, z):
240240
.serialize()
241241
.run_method_and_compare_outputs()
242242
)
243+
244+
class AddWithAlpha(torch.nn.Module):
245+
def forward(self, x, y):
246+
# node with alpha = 1.0 will be partitioned
247+
out1 = torch.add(x, y, alpha=1)
248+
# node with alpha != 1.0 will not be partitioned
249+
out2 = torch.add(x, y, alpha=2)
250+
return out1, out2
251+
252+
def test_add_with_alpha(self):
253+
inputs = (torch.randn(1, 1, 4, 4), torch.randn(1, 1, 4, 4))
254+
(
255+
Tester(self.AddWithAlpha(), inputs)
256+
.export()
257+
.check_count({"torch.ops.aten.add.Tensor": 2})
258+
.to_edge_transform_and_lower()
259+
# unpartitioned node
260+
.check_count({"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1})
261+
# partitioned node
262+
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
263+
.to_executorch()
264+
.serialize()
265+
.run_method_and_compare_outputs()
266+
)

examples/models/llama/config/llm_config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,9 @@ class ExportConfig:
227227
export_only: bool = False
228228

229229
def __post_init__(self):
230-
if self.max_context_length > self.max_seq_length:
230+
if self.max_context_length < self.max_seq_length:
231231
raise ValueError(
232-
f"max_context_length of {self.max_context_length} cannot be greater than max_seq_length of {self.max_seq_length}"
232+
f"max_context_length of {self.max_context_length} cannot be shorter than max_seq_length of {self.max_seq_length}"
233233
)
234234

235235

runtime/backend/interface.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,42 @@ Result<const char*> get_backend_name(size_t index) {
6666
return registered_backends[index].name;
6767
}
6868

69+
Error set_option(
70+
const char* backend_name,
71+
const executorch::runtime::Span<executorch::runtime::BackendOption>
72+
backend_options) {
73+
auto backend_class = get_backend_class(backend_name);
74+
if (!backend_class) {
75+
return Error::NotFound;
76+
}
77+
78+
BackendOptionContext backend_option_context;
79+
Error result =
80+
backend_class->set_option(backend_option_context, backend_options);
81+
if (result != Error::Ok) {
82+
return result;
83+
}
84+
return Error::Ok;
85+
}
86+
87+
Error get_option(
88+
const char* backend_name,
89+
executorch::runtime::Span<executorch::runtime::BackendOption>
90+
backend_options) {
91+
auto backend_class = get_backend_class(backend_name);
92+
if (!backend_class) {
93+
return Error::NotFound;
94+
}
95+
BackendOptionContext backend_option_context;
96+
executorch::runtime::Span<BackendOption> backend_options_ref(
97+
backend_options.data(), backend_options.size());
98+
auto result =
99+
backend_class->get_option(backend_option_context, backend_options_ref);
100+
if (result != Error::Ok) {
101+
return result;
102+
}
103+
return Error::Ok;
104+
}
105+
69106
} // namespace ET_RUNTIME_NAMESPACE
70107
} // namespace executorch

runtime/backend/interface.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,34 @@ size_t get_num_registered_backends();
183183
*/
184184
Result<const char*> get_backend_name(size_t index);
185185

186+
/**
187+
* Sets backend options for a specific backend.
188+
*
189+
* @param backend_name The name of the backend to set options for
190+
* @param backend_options The backend option list containing the options
191+
* to set
192+
* @return Error::Ok on success, Error::NotFound if backend is not found, or
193+
* other error codes on failure
194+
*/
195+
Error set_option(
196+
const char* backend_name,
197+
const executorch::runtime::Span<executorch::runtime::BackendOption>
198+
backend_options);
199+
200+
/**
201+
* Retrieves backend options for a specific backend.
202+
*
203+
* @param backend_name The name of the backend to get options from
204+
* @param backend_options The backend option objects that will be filled with
205+
* the populated values from the backend
206+
* @return Error::Ok on success, Error::NotFound if backend is not found, or
207+
* other error codes on failure
208+
*/
209+
Error get_option(
210+
const char* backend_name,
211+
executorch::runtime::Span<executorch::runtime::BackendOption>
212+
backend_options);
213+
186214
} // namespace ET_RUNTIME_NAMESPACE
187215
} // namespace executorch
188216

runtime/backend/test/backend_interface_update_test.cpp

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
*/
88

99
#include <executorch/runtime/backend/interface.h>
10+
#include <executorch/runtime/backend/options.h>
1011
#include <executorch/runtime/platform/runtime.h>
1112

1213
#include <gtest/gtest.h>
14+
#include <memory>
1315

1416
using namespace ::testing;
1517
using executorch::runtime::ArrayRef;
@@ -61,7 +63,8 @@ class MockBackend : public BackendInterface {
6163
int success_update = 0;
6264
for (const auto& backend_option : backend_options) {
6365
if (strcmp(backend_option.key, "Backend") == 0) {
64-
if (std::holds_alternative<std::array<char, 256>>(
66+
if (std::holds_alternative<
67+
std::array<char, executorch::runtime::kMaxOptionValueLength>>(
6568
backend_option.value)) {
6669
// Store the value in our member variable
6770
const auto& arr =
@@ -285,3 +288,114 @@ TEST_F(BackendInterfaceUpdateTest, UpdateBetweenExecutes) {
285288
ASSERT_TRUE(mock_backend->target_backend.has_value());
286289
EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "NPU");
287290
}
291+
292+
// Mock backend for testing
293+
class StubBackend : public BackendInterface {
294+
public:
295+
~StubBackend() override = default;
296+
297+
bool is_available() const override {
298+
return true;
299+
}
300+
301+
Result<DelegateHandle*> init(
302+
BackendInitContext& context,
303+
FreeableBuffer* processed,
304+
ArrayRef<CompileSpec> compile_specs) const override {
305+
return nullptr;
306+
}
307+
308+
Error execute(
309+
BackendExecutionContext& context,
310+
DelegateHandle* handle,
311+
EValue** args) const override {
312+
return Error::Ok;
313+
}
314+
315+
Error get_option(
316+
BackendOptionContext& context,
317+
executorch::runtime::Span<executorch::runtime::BackendOption>&
318+
backend_options) override {
319+
// For testing purposes, just record that get_option was called
320+
// and verify the input parameters
321+
get_option_called = true;
322+
get_option_call_count++;
323+
last_get_option_size = backend_options.size();
324+
325+
// Verify that the expected option key is present and modify the value
326+
for (size_t i = 0; i < backend_options.size(); ++i) {
327+
if (strcmp(backend_options[i].key, "NumberOfThreads") == 0) {
328+
// Set the value to what was stored by set_option
329+
backend_options[i].value = last_num_threads;
330+
found_expected_key = true;
331+
break;
332+
}
333+
}
334+
335+
return Error::Ok;
336+
}
337+
338+
Error set_option(
339+
BackendOptionContext& context,
340+
const executorch::runtime::Span<executorch::runtime::BackendOption>&
341+
backend_options) override {
342+
// Store the options for verification
343+
last_options_size = backend_options.size();
344+
if (backend_options.size() > 0) {
345+
for (const auto& option : backend_options) {
346+
if (strcmp(option.key, "NumberOfThreads") == 0) {
347+
if (auto* val = std::get_if<int>(&option.value)) {
348+
last_num_threads = *val;
349+
}
350+
}
351+
}
352+
}
353+
return Error::Ok;
354+
}
355+
356+
// Mutable for testing verification
357+
size_t last_options_size = 0;
358+
int last_num_threads = 0;
359+
bool get_option_called = false;
360+
int get_option_call_count = 0;
361+
size_t last_get_option_size = 0;
362+
bool found_expected_key = false;
363+
};
364+
365+
class BackendUpdateTest : public ::testing::Test {
366+
protected:
367+
void SetUp() override {
368+
// Since these tests cause ET_LOG to be called, the PAL must be initialized
369+
// first.
370+
executorch::runtime::runtime_init();
371+
372+
// Register the stub backend
373+
stub_backend = std::make_unique<StubBackend>();
374+
Backend backend_config{"StubBackend", stub_backend.get()};
375+
auto register_result = register_backend(backend_config);
376+
ASSERT_EQ(register_result, Error::Ok);
377+
}
378+
379+
std::unique_ptr<StubBackend> stub_backend;
380+
};
381+
382+
// Test basic string functionality
383+
TEST_F(BackendUpdateTest, TestSetGetOption) {
384+
BackendOptions<1> backend_options;
385+
int new_num_threads = 4;
386+
backend_options.set_option("NumberOfThreads", new_num_threads);
387+
388+
auto status = set_option("StubBackend", backend_options.view());
389+
ASSERT_EQ(status, Error::Ok);
390+
391+
// Set up the default option, which will be populuated by the get_option call
392+
BackendOption ref_backend_option{"NumberOfThreads", 0};
393+
status = get_option("StubBackend", ref_backend_option);
394+
395+
// Verify that the backend actually received the options
396+
ASSERT_TRUE(std::get<int>(ref_backend_option.value) == new_num_threads);
397+
398+
// Verify that the backend actually update the options
399+
ASSERT_EQ(stub_backend->last_options_size, 1);
400+
ASSERT_EQ(stub_backend->last_num_threads, new_num_threads);
401+
}

0 commit comments

Comments
 (0)