Skip to content

Commit 2a5c762

Browse files
metascroyfacebook-github-bot
authored andcommitted
Add BackendOption loading to swift bindings
Differential Revision: D100710833
1 parent fe71bd4 commit 2a5c762

7 files changed

Lines changed: 407 additions & 0 deletions

File tree

extension/apple/ExecuTorch/Exported/ExecuTorch+Module.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,36 @@ public extension MethodMetadata {
4747
}
4848
}
4949

50+
public extension Module {
51+
/// Loads the module's program with per-delegate backend options.
52+
///
53+
/// - Parameters:
54+
/// - backendOptions: A dictionary mapping backend identifiers (e.g. "CoreMLBackend")
55+
/// to arrays of `BackendOption` objects configuring that backend.
56+
/// - verification: The verification level to apply when loading the program.
57+
/// - Throws: An error if loading fails.
58+
func load(
59+
backendOptions: [String: [BackendOption]],
60+
verification: ModuleVerification = .minimal
61+
) throws {
62+
try __loadWithBackendOptions(backendOptions, verification: verification)
63+
}
64+
65+
/// Loads a specific method from the program with per-delegate backend options.
66+
///
67+
/// - Parameters:
68+
/// - method: The name of the method to load.
69+
/// - backendOptions: A dictionary mapping backend identifiers (e.g. "CoreMLBackend")
70+
/// to arrays of `BackendOption` objects configuring that backend.
71+
/// - Throws: An error if loading fails.
72+
func load(
73+
_ method: String,
74+
backendOptions: [String: [BackendOption]]
75+
) throws {
76+
try __loadMethod(method, backendOptions: backendOptions)
77+
}
78+
}
79+
5080
public extension Module {
5181
/// Executes a specific method with the provided input values.
5282
/// The method is loaded on demand if not already loaded.

extension/apple/ExecuTorch/Exported/ExecuTorch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9+
#import "ExecuTorchBackendOption.h"
910
#import "ExecuTorchError.h"
1011
#import "ExecuTorchLog.h"
1112
#import "ExecuTorchModule.h"
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
#import <Foundation/Foundation.h>
10+
11+
NS_ASSUME_NONNULL_BEGIN
12+
13+
/**
14+
* Enum to define the type of a backend option value.
15+
*/
16+
typedef NS_ENUM(NSInteger, ExecuTorchBackendOptionType) {
17+
ExecuTorchBackendOptionTypeBoolean,
18+
ExecuTorchBackendOptionTypeInteger,
19+
ExecuTorchBackendOptionTypeString,
20+
} NS_SWIFT_NAME(BackendOptionType);
21+
22+
/**
23+
* Represents a single key-value configuration option for a backend.
24+
*
25+
* Backend options are used to pass per-delegate configuration (e.g., compute
26+
* unit, thread count, cache directory) when loading a module. Each option has
27+
* a string key and a typed value (boolean, integer, or string).
28+
*/
29+
NS_SWIFT_NAME(BackendOption)
30+
__attribute__((objc_subclassing_restricted))
31+
@interface ExecuTorchBackendOption : NSObject
32+
33+
/** The option key name (e.g. "compute_unit", "num_threads"). */
34+
@property (nonatomic, readonly) NSString *key;
35+
36+
/** The type of the option value. */
37+
@property (nonatomic, readonly) ExecuTorchBackendOptionType type;
38+
39+
/** The boolean value. Only valid when type is Boolean. */
40+
@property (nonatomic, readonly) BOOL boolValue;
41+
42+
/** The integer value. Only valid when type is Integer. */
43+
@property (nonatomic, readonly) NSInteger intValue;
44+
45+
/** The string value. Only valid when type is String. */
46+
@property (nullable, nonatomic, readonly) NSString *stringValue;
47+
48+
/**
49+
* Creates a backend option with a boolean value.
50+
*
51+
* @param key The option key.
52+
* @param value The boolean value.
53+
* @return A new ExecuTorchBackendOption instance.
54+
*/
55+
+ (instancetype)optionWithKey:(NSString *)key
56+
booleanValue:(BOOL)value
57+
NS_SWIFT_NAME(init(_:_:))
58+
NS_RETURNS_RETAINED;
59+
60+
/**
61+
* Creates a backend option with an integer value.
62+
*
63+
* @param key The option key.
64+
* @param value The integer value.
65+
* @return A new ExecuTorchBackendOption instance.
66+
*/
67+
+ (instancetype)optionWithKey:(NSString *)key
68+
integerValue:(NSInteger)value
69+
NS_SWIFT_NAME(init(_:_:))
70+
NS_RETURNS_RETAINED;
71+
72+
/**
73+
* Creates a backend option with a string value.
74+
*
75+
* @param key The option key.
76+
* @param value The string value.
77+
* @return A new ExecuTorchBackendOption instance.
78+
*/
79+
+ (instancetype)optionWithKey:(NSString *)key
80+
stringValue:(NSString *)value
81+
NS_SWIFT_NAME(init(_:_:))
82+
NS_RETURNS_RETAINED;
83+
84+
+ (instancetype)new NS_UNAVAILABLE;
85+
- (instancetype)init NS_UNAVAILABLE;
86+
87+
@end
88+
89+
NS_ASSUME_NONNULL_END
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
#import "ExecuTorchBackendOption.h"
10+
11+
@implementation ExecuTorchBackendOption {
12+
NSString *_key;
13+
ExecuTorchBackendOptionType _type;
14+
BOOL _boolValue;
15+
NSInteger _intValue;
16+
NSString *_stringValue;
17+
}
18+
19+
- (instancetype)initWithKey:(NSString *)key
20+
booleanValue:(BOOL)value {
21+
self = [super init];
22+
if (self) {
23+
_key = [key copy];
24+
_type = ExecuTorchBackendOptionTypeBoolean;
25+
_boolValue = value;
26+
}
27+
return self;
28+
}
29+
30+
- (instancetype)initWithKey:(NSString *)key
31+
integerValue:(NSInteger)value {
32+
self = [super init];
33+
if (self) {
34+
_key = [key copy];
35+
_type = ExecuTorchBackendOptionTypeInteger;
36+
_intValue = value;
37+
}
38+
return self;
39+
}
40+
41+
- (instancetype)initWithKey:(NSString *)key
42+
stringValue:(NSString *)value {
43+
self = [super init];
44+
if (self) {
45+
_key = [key copy];
46+
_type = ExecuTorchBackendOptionTypeString;
47+
_stringValue = [value copy];
48+
}
49+
return self;
50+
}
51+
52+
+ (instancetype)optionWithKey:(NSString *)key
53+
booleanValue:(BOOL)value {
54+
return [[self alloc] initWithKey:key booleanValue:value];
55+
}
56+
57+
+ (instancetype)optionWithKey:(NSString *)key
58+
integerValue:(NSInteger)value {
59+
return [[self alloc] initWithKey:key integerValue:value];
60+
}
61+
62+
+ (instancetype)optionWithKey:(NSString *)key
63+
stringValue:(NSString *)value {
64+
return [[self alloc] initWithKey:key stringValue:value];
65+
}
66+
67+
@end

extension/apple/ExecuTorch/Exported/ExecuTorchModule.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9+
#import "ExecuTorchBackendOption.h"
910
#import "ExecuTorchValue.h"
1011

1112
NS_ASSUME_NONNULL_BEGIN
@@ -186,6 +187,30 @@ NS_SWIFT_NAME(Module)
186187
*/
187188
- (BOOL)load:(NSError **)error;
188189

190+
/**
191+
* Loads the module's program with per-delegate backend options.
192+
*
193+
* @param backendOptions A dictionary mapping backend identifiers (e.g. "CoreMLBackend")
194+
* to arrays of ExecuTorchBackendOption objects configuring that backend.
195+
* @param verification The verification level to apply when loading the program.
196+
* @param error A pointer to an NSError pointer that will be set if an error occurs.
197+
* @return YES if the program was successfully loaded; otherwise, NO.
198+
*/
199+
- (BOOL)loadWithBackendOptions:(NSDictionary<NSString *, NSArray<ExecuTorchBackendOption *> *> *)backendOptions
200+
verification:(ExecuTorchVerification)verification
201+
error:(NSError **)error NS_REFINED_FOR_SWIFT;
202+
203+
/**
204+
* Loads the module's program with per-delegate backend options using minimal verification.
205+
*
206+
* @param backendOptions A dictionary mapping backend identifiers (e.g. "CoreMLBackend")
207+
* to arrays of ExecuTorchBackendOption objects configuring that backend.
208+
* @param error A pointer to an NSError pointer that will be set if an error occurs.
209+
* @return YES if the program was successfully loaded; otherwise, NO.
210+
*/
211+
- (BOOL)loadWithBackendOptions:(NSDictionary<NSString *, NSArray<ExecuTorchBackendOption *> *> *)backendOptions
212+
error:(NSError **)error NS_REFINED_FOR_SWIFT;
213+
189214
/**
190215
* Checks if the module is loaded.
191216
*
@@ -203,6 +228,19 @@ NS_SWIFT_NAME(Module)
203228
- (BOOL)loadMethod:(NSString *)methodName
204229
error:(NSError **)error NS_SWIFT_NAME(load(_:));
205230

231+
/**
232+
* Loads a specific method from the program with per-delegate backend options.
233+
*
234+
* @param methodName A string representing the name of the method to load.
235+
* @param backendOptions A dictionary mapping backend identifiers (e.g. "CoreMLBackend")
236+
* to arrays of ExecuTorchBackendOption objects configuring that backend.
237+
* @param error A pointer to an NSError pointer that is set if an error occurs.
238+
* @return YES if the method was successfully loaded; otherwise, NO.
239+
*/
240+
- (BOOL)loadMethod:(NSString *)methodName
241+
backendOptions:(NSDictionary<NSString *, NSArray<ExecuTorchBackendOption *> *> *)backendOptions
242+
error:(NSError **)error NS_REFINED_FOR_SWIFT;
243+
206244
/**
207245
* Checks if a specific method is loaded.
208246
*

extension/apple/ExecuTorch/Exported/ExecuTorchModule.mm

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
#import "ExecuTorchModule.h"
1010

11+
#import "ExecuTorchBackendOption.h"
1112
#import "ExecuTorchError.h"
1213
#import "ExecuTorchUtils.h"
1314

1415
#import <executorch/extension/module/module.h>
1516
#import <executorch/extension/tensor/tensor.h>
17+
#import <executorch/runtime/backend/backend_options_map.h>
18+
#import <executorch/runtime/backend/options.h>
1619

1720
using namespace executorch::extension;
1821
using namespace executorch::runtime;
@@ -324,6 +327,107 @@ - (BOOL)loadMethod:(NSString *)methodName
324327
return YES;
325328
}
326329

330+
- (BOOL)loadWithBackendOptions:(NSDictionary<NSString *, NSArray<ExecuTorchBackendOption *> *> *)backendOptions
331+
verification:(ExecuTorchVerification)verification
332+
error:(NSError **)error {
333+
std::vector<std::vector<BackendOption>> allOptions;
334+
allOptions.reserve(backendOptions.count);
335+
LoadBackendOptionsMap map;
336+
337+
for (NSString *backendId in backendOptions) {
338+
NSArray<ExecuTorchBackendOption *> *options = backendOptions[backendId];
339+
std::vector<BackendOption> opts;
340+
opts.reserve(options.count);
341+
for (ExecuTorchBackendOption *opt in options) {
342+
BackendOption bo;
343+
strncpy(bo.key, opt.key.UTF8String, kMaxOptionKeyLength - 1);
344+
bo.key[kMaxOptionKeyLength - 1] = '\0';
345+
switch (opt.type) {
346+
case ExecuTorchBackendOptionTypeBoolean:
347+
bo.value = (bool)opt.boolValue;
348+
break;
349+
case ExecuTorchBackendOptionTypeInteger:
350+
bo.value = (int)opt.intValue;
351+
break;
352+
case ExecuTorchBackendOptionTypeString: {
353+
std::array<char, kMaxOptionValueLength> arr{};
354+
strncpy(arr.data(), opt.stringValue.UTF8String, kMaxOptionValueLength - 1);
355+
arr[kMaxOptionValueLength - 1] = '\0';
356+
bo.value = arr;
357+
break;
358+
}
359+
}
360+
opts.push_back(bo);
361+
}
362+
allOptions.push_back(std::move(opts));
363+
auto &backOpts = allOptions.back();
364+
map.set_options(backendId.UTF8String, Span<BackendOption>(backOpts.data(), backOpts.size()));
365+
}
366+
367+
const auto errorCode = _module->load(map, static_cast<Program::Verification>(verification));
368+
if (errorCode != Error::Ok) {
369+
if (error) {
370+
*error = ExecuTorchErrorWithCode((ExecuTorchErrorCode)errorCode);
371+
}
372+
return NO;
373+
}
374+
return YES;
375+
}
376+
377+
- (BOOL)loadWithBackendOptions:(NSDictionary<NSString *, NSArray<ExecuTorchBackendOption *> *> *)backendOptions
378+
error:(NSError **)error {
379+
return [self loadWithBackendOptions:backendOptions
380+
verification:ExecuTorchVerificationMinimal
381+
error:error];
382+
}
383+
384+
- (BOOL)loadMethod:(NSString *)methodName
385+
backendOptions:(NSDictionary<NSString *, NSArray<ExecuTorchBackendOption *> *> *)backendOptions
386+
error:(NSError **)error {
387+
std::vector<std::vector<BackendOption>> allOptions;
388+
allOptions.reserve(backendOptions.count);
389+
LoadBackendOptionsMap map;
390+
391+
for (NSString *backendId in backendOptions) {
392+
NSArray<ExecuTorchBackendOption *> *options = backendOptions[backendId];
393+
std::vector<BackendOption> opts;
394+
opts.reserve(options.count);
395+
for (ExecuTorchBackendOption *opt in options) {
396+
BackendOption bo;
397+
strncpy(bo.key, opt.key.UTF8String, kMaxOptionKeyLength - 1);
398+
bo.key[kMaxOptionKeyLength - 1] = '\0';
399+
switch (opt.type) {
400+
case ExecuTorchBackendOptionTypeBoolean:
401+
bo.value = (bool)opt.boolValue;
402+
break;
403+
case ExecuTorchBackendOptionTypeInteger:
404+
bo.value = (int)opt.intValue;
405+
break;
406+
case ExecuTorchBackendOptionTypeString: {
407+
std::array<char, kMaxOptionValueLength> arr{};
408+
strncpy(arr.data(), opt.stringValue.UTF8String, kMaxOptionValueLength - 1);
409+
arr[kMaxOptionValueLength - 1] = '\0';
410+
bo.value = arr;
411+
break;
412+
}
413+
}
414+
opts.push_back(bo);
415+
}
416+
allOptions.push_back(std::move(opts));
417+
auto &backOpts = allOptions.back();
418+
map.set_options(backendId.UTF8String, Span<BackendOption>(backOpts.data(), backOpts.size()));
419+
}
420+
421+
const auto errorCode = _module->load_method(methodName.UTF8String, nullptr, nullptr, &map);
422+
if (errorCode != Error::Ok) {
423+
if (error) {
424+
*error = ExecuTorchErrorWithCode((ExecuTorchErrorCode)errorCode);
425+
}
426+
return NO;
427+
}
428+
return YES;
429+
}
430+
327431
- (BOOL)isMethodLoaded:(NSString *)methodName {
328432
return _module->is_method_loaded(methodName.UTF8String);
329433
}

0 commit comments

Comments
 (0)