1010#import < ETCoreMLModel.h>
1111#import < ETCoreMLModelManager.h>
1212#import < ETCoreMLStrings.h>
13- #import < atomic>
1413#import < backend_delegate.h>
1514#import < model_event_logger.h>
1615#import < multiarray.h>
@@ -88,6 +87,153 @@ MLComputeUnits get_compute_units(const Buffer& buffer) {
8887}
8988} // namespace
9089
90+ @interface ETCoreMLModelManagerDelegate : NSObject
91+
92+ - (instancetype )init NS_UNAVAILABLE;
93+
94+ + (instancetype )new NS_UNAVAILABLE;
95+
96+ - (instancetype )initWithConfig : (BackendDelegate::Config)config NS_DESIGNATED_INITIALIZER;
97+
98+ - (BOOL )loadAndReturnError : (NSError * _Nullable __autoreleasing *)error ;
99+
100+ - (void )loadAsynchronously ;
101+
102+ - (ModelHandle*)loadModelFromAOTData : (NSData *)data
103+ configuration : (MLModelConfiguration*)configuration
104+ error : (NSError * __autoreleasing*)error ;
105+
106+ - (BOOL )executeModelWithHandle : (ModelHandle*)handle
107+ argsVec : (const std::vector<executorchcoreml::MultiArray>&)argsVec
108+ loggingOptions : (const executorchcoreml::ModelLoggingOptions&)loggingOptions
109+ eventLogger : (const executorchcoreml::ModelEventLogger* _Nullable)eventLogger
110+ error : (NSError * __autoreleasing*)error ;
111+
112+ - (BOOL )unloadModelWithHandle : (ModelHandle*)handle ;
113+
114+ - (BOOL )purgeModelsCacheAndReturnError : (NSError * _Nullable __autoreleasing *)error ;
115+
116+ @property (assign , readonly , nonatomic ) BackendDelegate::Config config;
117+ @property (strong , readonly , nonatomic ) dispatch_queue_t syncQueue;
118+ @property (strong , nonatomic , nullable ) ETCoreMLModelManager *impl;
119+ @property (assign , readonly , nonatomic ) BOOL isAvailable;
120+
121+ @end
122+
123+ @implementation ETCoreMLModelManagerDelegate
124+
125+ - (instancetype )initWithConfig : (BackendDelegate::Config)config {
126+ self = [super init ];
127+ if (self) {
128+ _config = std::move (config);
129+ _syncQueue = dispatch_queue_create (" com.executorchcoreml.modelmanagerdelegate.sync" , DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
130+ }
131+
132+ return self;
133+ }
134+
135+ - (BOOL )_loadAndReturnError : (NSError * _Nullable __autoreleasing *)error {
136+ if (self.impl != nil ) {
137+ return YES ;
138+ }
139+
140+ ETCoreMLAssetManager *assetManager = create_asset_manager (ETCoreMLStrings.assetsDirectoryPath ,
141+ ETCoreMLStrings.trashDirectoryPath ,
142+ ETCoreMLStrings.databaseDirectoryPath ,
143+ ETCoreMLStrings.databaseName ,
144+ self.config .max_models_cache_size ,
145+ error);
146+ if (!assetManager) {
147+ return NO ;
148+ }
149+
150+ ETCoreMLModelManager *modelManager = [[ETCoreMLModelManager alloc ] initWithAssetManager: assetManager];
151+ if (!modelManager) {
152+ return NO ;
153+ }
154+
155+ self.impl = modelManager;
156+
157+ if (self.config .should_prewarm_asset ) {
158+ [modelManager prewarmRecentlyUsedAssetsWithMaxCount: 1 ];
159+ }
160+
161+ return YES ;
162+ }
163+
164+ - (BOOL )loadAndReturnError : (NSError * _Nullable __autoreleasing *)error {
165+ __block NSError *localError = nil ;
166+ __block BOOL result = NO ;
167+ dispatch_sync (self.syncQueue , ^{
168+ result = [self _loadAndReturnError: &localError];
169+ });
170+
171+ if (error) {
172+ *error = localError;
173+ }
174+
175+ return result;
176+ }
177+
178+ - (void )loadAsynchronously {
179+ dispatch_async (self.syncQueue , ^{
180+ (void )[self _loadAndReturnError: nil ];
181+ });
182+ }
183+
184+ - (ModelHandle*)loadModelFromAOTData : (NSData *)data
185+ configuration : (MLModelConfiguration*)configuration
186+ error : (NSError * __autoreleasing*)error {
187+ if (![self loadAndReturnError: error]) {
188+ return nil ;
189+ }
190+
191+ return [self .impl loadModelFromAOTData: data
192+ configuration: configuration
193+ error: error];
194+ }
195+
196+ - (BOOL )executeModelWithHandle : (ModelHandle*)handle
197+ argsVec : (const std::vector<executorchcoreml::MultiArray>&)argsVec
198+ loggingOptions : (const executorchcoreml::ModelLoggingOptions&)loggingOptions
199+ eventLogger : (const executorchcoreml::ModelEventLogger* _Nullable)eventLogger
200+ error : (NSError * __autoreleasing*)error {
201+ assert (self.impl != nil && " Impl must not be nil" );
202+ return [self .impl executeModelWithHandle: handle
203+ argsVec: argsVec
204+ loggingOptions: loggingOptions
205+ eventLogger: eventLogger
206+ error: error];
207+ }
208+
209+ - (nullable ETCoreMLModel*)modelWithHandle : (ModelHandle*)handle {
210+ assert (self.impl != nil && " Impl must not be nil" );
211+ return [self .impl modelWithHandle: handle];
212+ }
213+
214+ - (BOOL )unloadModelWithHandle : (ModelHandle*)handle {
215+ assert (self.impl != nil && " Impl must not be nil" );
216+ return [self .impl unloadModelWithHandle: handle];
217+ }
218+
219+ - (BOOL )purgeModelsCacheAndReturnError : (NSError * _Nullable __autoreleasing *)error {
220+ if (![self loadAndReturnError: error]) {
221+ return NO ;
222+ }
223+
224+ return [self .impl purgeModelsCacheAndReturnError: error];;
225+ }
226+
227+ - (BOOL )isAvailable {
228+ if (![self loadAndReturnError: nil ]) {
229+ return NO ;
230+ }
231+
232+ return YES ;
233+ }
234+
235+ @end
236+
91237namespace executorchcoreml {
92238
93239std::string BackendDelegate::ErrorCategory::message (int code) const {
@@ -114,20 +260,9 @@ MLComputeUnits get_compute_units(const Buffer& buffer) {
114260class BackendDelegateImpl : public BackendDelegate {
115261public:
116262 explicit BackendDelegateImpl (const Config& config) noexcept
117- :BackendDelegate(), config_(config) {
118- NSError *localError = nil ;
119- ETCoreMLAssetManager *asset_manager = create_asset_manager (ETCoreMLStrings.assetsDirectoryPath ,
120- ETCoreMLStrings.trashDirectoryPath ,
121- ETCoreMLStrings.databaseDirectoryPath ,
122- ETCoreMLStrings.databaseName ,
123- config.max_models_cache_size ,
124- &localError);
125-
126- model_manager_ = (asset_manager != nil ) ? [[ETCoreMLModelManager alloc ] initWithAssetManager: asset_manager] : nil ;
127- if (model_manager_ != nil && config_.should_prewarm_asset ) {
128- [model_manager_ prewarmRecentlyUsedAssetsWithMaxCount: 1 ];
129- }
130- available_.store (model_manager_ != nil , std::memory_order_seq_cst);
263+ :BackendDelegate(), model_manager_([[ETCoreMLModelManagerDelegate alloc ] initWithConfig: config])
264+ {
265+ [model_manager_ loadAsynchronously ];
131266 }
132267
133268 BackendDelegateImpl (BackendDelegateImpl const &) = delete ;
@@ -142,11 +277,6 @@ explicit BackendDelegateImpl(const Config& config) noexcept
142277 ModelHandle *modelHandle = [model_manager_ loadModelFromAOTData: data
143278 configuration: configuration
144279 error: &localError];
145- if (modelHandle && config_.should_prewarm_model ) {
146- NSError *localError = nil ;
147- [model_manager_ prewarmModelWithHandle: modelHandle error: &localError];
148- }
149-
150280 return modelHandle;
151281 }
152282
@@ -158,7 +288,7 @@ bool execute(Handle* handle,
158288 NSError *error = nil ;
159289 if (![model_manager_ executeModelWithHandle: handle
160290 argsVec: args
161- loggingOptions: logging_options
291+ loggingOptions: logging_options
162292 eventLogger: event_logger
163293 error: &error]) {
164294 ec = static_cast <ErrorCode>(error.code );
@@ -173,7 +303,7 @@ bool is_valid_handle(Handle* handle) const noexcept override {
173303 }
174304
175305 bool is_available () const noexcept override {
176- return available_. load (std::memory_order_acquire );
306+ return static_cast < bool >(model_manager_. isAvailable );
177307 }
178308
179309 std::pair<size_t , size_t > get_num_arguments (Handle* handle) const noexcept override {
@@ -187,12 +317,11 @@ void destroy(Handle* handle) const noexcept override {
187317
188318 bool purge_models_cache () const noexcept override {
189319 NSError *localError = nil ;
190- bool result = static_cast <bool >([model_manager_.assetManager purge : &localError]);
320+ bool result = static_cast <bool >([model_manager_ purgeModelsCacheAndReturnError : &localError]);
191321 return result;
192322 }
193323
194- ETCoreMLModelManager *model_manager_;
195- std::atomic<bool > available_;
324+ ETCoreMLModelManagerDelegate *model_manager_;
196325 Config config_;
197326};
198327
0 commit comments