diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.h b/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.h index d97b3cf9b76..01655ca06c1 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.h +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.h @@ -7,7 +7,7 @@ #import -#import +#import "asset.h" NS_ASSUME_NONNULL_BEGIN diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.mm index 6b1723f7113..455edf89480 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLAsset.mm @@ -5,15 +5,15 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "ETCoreMLAsset.h" + +#import "ETCoreMLLogging.h" +#import "objc_safe_cast.h" #import #import #import #import - -#import - namespace { using namespace executorchcoreml; @@ -85,6 +85,10 @@ - (void)dealloc { - (BOOL)_keepAliveAndReturnError:(NSError * __autoreleasing *)error { if (!_isValid) { + ETCoreMLLogErrorAndSetNSError(error, + ETCoreMLErrorCorruptedModel, + "The asset with identifier = %@ is invalid. Some required asset files appear to be missing.", + _identifier); return NO; } diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.h b/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.h index 04fef204e1a..11d957044e9 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.h +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.h @@ -7,7 +7,7 @@ #import -#import +#import "database.hpp" @class ETCoreMLAsset; diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.mm index 73e9cc0f33b..256026e1f09 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.mm @@ -6,12 +6,14 @@ // Please refer to the license found in the LICENSE file in the root directory of the source tree. #import "ETCoreMLAssetManager.h" -#import -#import -#import + +#import "ETCoreMLAsset.h" +#import "ETCoreMLLogging.h" +#import "database.hpp" +#import "json_key_value_store.hpp" +#import "serde_json.h" + #import -#import -#import #import namespace { @@ -365,8 +367,7 @@ - (void)cleanupAssetIfNeeded:(ETCoreMLAsset *)asset { NSError *cleanupError = nil; if (![self _removeAssetWithIdentifier:asset.identifier error:&cleanupError]) { ETCoreMLLogError(cleanupError, - "%@: Failed to remove asset with identifier = %@", - NSStringFromClass(ETCoreMLAssetManager.class), + "Failed to remove asset with identifier = %@", identifier); } }); @@ -440,9 +441,7 @@ - (void)triggerCompaction { dispatch_async(self.syncQueue, ^{ NSError *localError = nil; if (![weakSelf _compact:self.maxAssetsSizeInBytes error:&localError]) { - ETCoreMLLogError(localError, - "%@: Failed to compact asset store.", - NSStringFromClass(ETCoreMLAssetManager.class)); + ETCoreMLLogError(localError, "Failed to compact asset store."); } }); } @@ -486,11 +485,11 @@ - (nullable ETCoreMLAsset *)assetWithIdentifier:(NSString *)identifier if ([result keepAliveAndReturnError:error]) { [self.assetsInUseMap setObject:result forKey:identifier]; - } else { - [self cleanupAssetIfNeeded:result]; - } + return result; + } - return result; + [self cleanupAssetIfNeeded:result]; + return nil; } - (BOOL)_containsAssetWithIdentifier:(NSString *)identifier @@ -587,8 +586,7 @@ - (BOOL)removeAssetWithIdentifier:(NSString *)identifier [assets addObject:asset]; } else if (localError) { ETCoreMLLogError(localError, - "%@: Failed to retrieve asset with identifier = %@", - NSStringFromClass(ETCoreMLAssetManager.class), + "Failed to retrieve asset with identifier = %@.", identifier); } @@ -647,8 +645,7 @@ - (NSUInteger)_compact:(NSUInteger)sizeInBytes error:(NSError * __autoreleasing NSString *identifier = @(asset.identifier.c_str()); if (![self _removeAssetWithIdentifier:identifier error:&cleanupError] && cleanupError) { ETCoreMLLogError(cleanupError, - "%@: Failed to remove asset with identifier = %@", - NSStringFromClass(ETCoreMLAssetManager.class), + "Failed to remove asset with identifier = %@.", identifier); } } @@ -689,8 +686,7 @@ - (void)removeFilesInTrashDirectory { for (NSURL *itemURL in enumerator) { if (![fileManager removeItemAtURL:itemURL error:&localError]) { ETCoreMLLogError(localError, - "%@: Failed to remove item in trash directory with name = %@", - NSStringFromClass(ETCoreMLAssetManager.class), + "Failed to remove item in trash directory with name = %@", itemURL.lastPathComponent); } } @@ -720,9 +716,7 @@ - (BOOL)_purge:(NSError * __autoreleasing *)error { NSError *localError = nil; // Create the assets directory, if we fail here it's okay. if (![self.fileManager createDirectoryAtURL:self.assetsDirectoryURL withIntermediateDirectories:NO attributes:@{} error:&localError]) { - ETCoreMLLogError(localError, - "%@: Failed to create assets directory", - NSStringFromClass(ETCoreMLAssetManager.class)); + ETCoreMLLogError(localError, "Failed to create assets directory."); } return true; diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.h b/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.h index 13b1023bcbc..3cf9e3df5f4 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.h +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.h @@ -1,13 +1,13 @@ // -// ETCoreMLDefaultModelExecutor.h -// executorchcoreml_tests +// ETCoreMLDefaultModelExecutor.h // -// Created by Gyan Sinha on 2/25/24. +// Copyright © 2024 Apple Inc. All rights reserved. // +// Please refer to the license found in the LICENSE file in the root directory of the source tree. #import -#import +#import "ETCoreMLModelExecutor.h" @class ETCoreMLModel; diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.mm index 226307f3c8f..63bc60695ce 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLDefaultModelExecutor.mm @@ -1,14 +1,14 @@ // -// ETCoreMLDefaultModelExecutor.m -// executorchcoreml_tests +// ETCoreMLDefaultModelExecutor.mm // -// Created by Gyan Sinha on 2/25/24. +// Copyright © 2024 Apple Inc. All rights reserved. // +// Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import -#import -#import -#import +#import "ETCoreMLAsset.h" +#import "ETCoreMLDefaultModelExecutor.h" +#import "ETCoreMLLogging.h" +#import "ETCoreMLModel.h" @implementation ETCoreMLDefaultModelExecutor @@ -27,7 +27,9 @@ - (instancetype)initWithModel:(ETCoreMLModel *)model { eventLogger:(const executorchcoreml::ModelEventLogger* _Nullable __unused)eventLogger error:(NSError * __autoreleasing *)error { if (self.ignoreOutputBackings) { - predictionOptions.outputBackings = @{}; + if (@available(macOS 11.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)) { + predictionOptions.outputBackings = @{}; + } } id outputs = [self.model predictionFromFeatures:inputs @@ -44,8 +46,7 @@ - (instancetype)initWithModel:(ETCoreMLModel *)model { if (!featureValue.multiArrayValue) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorBrokenModel, - "%@: Model is broken, expected multiarray for output=%@.", - NSStringFromClass(self.class), + "Model is broken, expected multiarray for output=%@.", outputName); return nil; } diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.h b/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.h index d9c4d4ef638..d1bb7c2caa5 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.h +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.h @@ -6,9 +6,9 @@ // Please refer to the license found in the LICENSE file in the root directory of the source tree. #import +#import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -18,15 +18,15 @@ extern NSErrorDomain const ETCoreMLErrorDomain; /// The error codes that are exposed publicly. typedef NS_ERROR_ENUM(ETCoreMLErrorDomain, ETCoreMLError) { ETCoreMLErrorCorruptedData = 1, // AOT blob can't be parsed. - ETCoreMLErrorCorruptedMetadata, // AOT blob has incorrect or missing metadata. - ETCoreMLErrorCorruptedModel, // AOT blob has incorrect or missing CoreML model. - ETCoreMLErrorBrokenModel, // CoreML model doesn't match the input and output specification. - ETCoreMLErrorCompilationFailed, // CoreML model failed to compile. - ETCoreMLErrorModelCompilationNotSupported, // CoreML model compilation is not supported by the target. - ETCoreMLErrorModelProfilingNotSupported, // Model profiling is not supported by the target. - ETCoreMLErrorModelSaveFailed, // Failed to save CoreML model to disk. - ETCoreMLErrorModelCacheCreationFailed, // Failed to create model cache. - ETCoreMLErrorInternalError, // Internal error. + ETCoreMLErrorCorruptedMetadata = 2, // AOT blob has incorrect or missing metadata. + ETCoreMLErrorCorruptedModel = 3, // AOT blob has incorrect or missing CoreML model. + ETCoreMLErrorBrokenModel = 4, // CoreML model doesn't match the input and output specification. + ETCoreMLErrorCompilationFailed = 5, // CoreML model failed to compile. + ETCoreMLErrorModelCompilationNotSupported = 6, // CoreML model compilation is not supported by the target. + ETCoreMLErrorModelProfilingNotSupported = 7, // Model profiling is not supported by the target. + ETCoreMLErrorModelSaveFailed = 8, // Failed to save CoreML model to disk. + ETCoreMLErrorModelCacheCreationFailed = 9, // Failed to create model cache. + ETCoreMLErrorInternalError = 10, // Internal error. }; @interface ETCoreMLErrorUtils : NSObject @@ -47,47 +47,47 @@ typedef NS_ERROR_ENUM(ETCoreMLErrorDomain, ETCoreMLError) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#if ET_LOG_ENABLED +#define ETCoreMLLogError(error, formatString, ...) \ + do { \ + NSString* message = error.localizedDescription; \ + message = [NSString stringWithFormat:@"[Core ML] " formatString " %@", ##__VA_ARGS__, message]; \ + ET_LOG(Error, "%s", message.UTF8String); \ + } while (0) +#else +#define ETCoreMLLogError(error, formatString, ...) \ + os_log_error(ETCoreMLErrorUtils.loggingChannel, formatString " %@", ##__VA_ARGS__, error.localizedDescription) +#endif + +#if ET_LOG_ENABLED +#define ETCoreMLLogInfo(formatString, ...) \ + ET_LOG(Info, "%s", [NSString stringWithFormat:@formatString, ##__VA_ARGS__].UTF8String) +#else +#define ETCoreMLLogInfo(formatString, ...) os_log_info(ETCoreMLErrorUtils.loggingChannel, formatString, ##__VA_ARGS__) +#endif + /// Record the error with `os_log_error` and fills `*errorOut` with `NSError`. -#define ETCoreMLLogErrorAndSetNSError(errorOut, errorCode, formatString, ...) \ - if (ET_LOG_ENABLED) { \ - ET_LOG(Error, "%s", [NSString stringWithFormat:@formatString, ##__VA_ARGS__].UTF8String); \ - } else { \ - os_log_error(ETCoreMLErrorUtils.loggingChannel, formatString, ##__VA_ARGS__); \ - } \ - if (errorOut) { \ - *errorOut = \ - [NSError errorWithDomain:ETCoreMLErrorDomain \ - code:errorCode \ - userInfo:@{ \ - NSLocalizedDescriptionKey : [NSString stringWithFormat:@formatString, ##__VA_ARGS__] \ - }]; \ - } +#define ETCoreMLLogErrorAndSetNSError(errorOut, errorCode, formatString, ...) \ + do { \ + NSDictionary* userInfo = \ + @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@formatString, ##__VA_ARGS__] }; \ + NSError* localError = [NSError errorWithDomain:ETCoreMLErrorDomain code:errorCode userInfo:userInfo]; \ + ETCoreMLLogError(localError, ""); \ + if (errorOut) { \ + *errorOut = localError; \ + } \ + } while (0) /// Record the error and its underlying error with `os_log_error` and fills `*errorOut` with `NSError`. #define ETCoreMLLogUnderlyingErrorAndSetNSError(errorOut, errorCode, underlyingNSError, formatString, ...) \ - if (ET_LOG_ENABLED) { \ - ET_LOG(Error, "%s", [NSString stringWithFormat:@formatString, ##__VA_ARGS__].UTF8String); \ - } else { \ - os_log_error(ETCoreMLErrorUtils.loggingChannel, \ - formatString ", with underlying error= %@.", \ - ##__VA_ARGS__, \ - (underlyingNSError).localizedDescription); \ - } \ - if (errorOut) { \ - *errorOut = [ETCoreMLErrorUtils errorWithCode:errorCode \ - underlyingError:underlyingNSError \ - format:@formatString, ##__VA_ARGS__]; \ - } - -#define ETCoreMLLogError(error, formatString, ...) \ - if (ET_LOG_ENABLED) { \ - ET_LOG(Error, "%s", [NSString stringWithFormat:@formatString, ##__VA_ARGS__].UTF8String); \ - } else { \ - os_log_error(ETCoreMLErrorUtils.loggingChannel, \ - formatString ", with error= %@.", \ - ##__VA_ARGS__, \ - (error).localizedDescription); \ - } + do { \ + ETCoreMLLogError(underlyingNSError, formatString, ##__VA_ARGS__); \ + if (errorOut) { \ + *errorOut = [ETCoreMLErrorUtils errorWithCode:errorCode \ + underlyingError:underlyingNSError \ + format:@formatString, ##__VA_ARGS__]; \ + } \ + } while (0) #pragma clang diagnostic pop diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.mm index 15d60d35704..f76b86a36b3 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLLogging.mm @@ -5,9 +5,9 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "ETCoreMLLogging.h" -#import +#import "ETCoreMLStrings.h" const NSErrorDomain ETCoreMLErrorDomain = @"com.apple.executorchcoreml"; diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLModel.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLModel.mm index 6b39ae5f920..4201293d1c5 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLModel.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLModel.mm @@ -5,7 +5,7 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "ETCoreMLModel.h" #import "ETCoreMLAsset.h" #import "ETCoreMLLogging.h" @@ -256,14 +256,23 @@ - (NSString *)identifier { } if (multiArrayArg && lCopyData) { - [multiArrayArg getMutableBytesWithHandler:^(void *_Nonnull mutableBytes, - NSInteger __unused size, - NSArray *strides) { - MultiArray buffer(mutableBytes, MultiArray::MemoryLayout(to_multiarray_data_type(constraint.dataType).value(), + void (^copy_data)(void *, NSArray *) = ^(void *bytes, NSArray *strides) { + MultiArray buffer(bytes, MultiArray::MemoryLayout(to_multiarray_data_type(constraint.dataType).value(), layout.shape(), to_vector(strides))); arg.copy(buffer); - }]; + }; + + + if (@available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *)) { + [multiArrayArg getMutableBytesWithHandler:^(void *_Nonnull mutableBytes, + NSInteger __unused size, + NSArray *strides) { + copy_data(mutableBytes, strides); + }]; + } else { + copy_data(multiArrayArg.dataPointer, multiArrayArg.strides); + } } [result addObject:multiArrayArg]; @@ -318,8 +327,7 @@ - (BOOL)prewarmAndReturnError:(NSError* __autoreleasing*)error { BOOL result = [self.mlModel prewarmUsingState:self.state error:error]; if (!result) { ETCoreMLLogError(localError, - "%@: Failed to prewarm model with identifier = %@", - NSStringFromClass(self.class), + "Failed to prewarm model with identifier = %@", self.identifier); } diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLModelCompiler.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLModelCompiler.mm index c50bf3002fa..5b2c5a225a3 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLModelCompiler.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLModelCompiler.mm @@ -5,8 +5,10 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import -#import +#import "ETCoreMLModelCompiler.h" + +#import "ETCoreMLLogging.h" + #import @implementation ETCoreMLModelCompiler @@ -20,8 +22,7 @@ + (nullable NSURL *)compileModelAtURL:(NSURL *)modelURL (void)error; ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorModelCompilationNotSupported, - "%@: Model compilation is not supported on the target, please make sure to export a compiled model.", - NSStringFromClass(ETCoreMLModelCompiler.class)); + "Model compilation is not supported on the target, please make sure to export a compiled model."); return nil; #else __block NSError *localError = nil; @@ -37,11 +38,10 @@ + (nullable NSURL *)compileModelAtURL:(NSURL *)modelURL long status = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(maxWaitTimeInSeconds * NSEC_PER_SEC))); if (status != 0) { - ETCoreMLLogErrorAndSetNSError(error, - ETCoreMLErrorCompilationFailed, - "%@: Failed to compile model in %f seconds.", - NSStringFromClass(ETCoreMLModelCompiler.class), - maxWaitTimeInSeconds); + ETCoreMLLogErrorAndSetNSError(error, + ETCoreMLErrorCompilationFailed, + "Failed to compile model in %f seconds.", + maxWaitTimeInSeconds); return nil; } } else { @@ -50,10 +50,9 @@ + (nullable NSURL *)compileModelAtURL:(NSURL *)modelURL if (localError) { ETCoreMLLogErrorAndSetNSError(error, - ETCoreMLErrorCompilationFailed, - "%@: Failed to compile model, error: %@", - NSStringFromClass(ETCoreMLModelCompiler.class), - localError); + ETCoreMLErrorCompilationFailed, + "Failed to compile model, error = %@.", + localError); return nil; } else { return result; diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLModelLoader.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLModelLoader.mm index 11690793baa..05aa910d954 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLModelLoader.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLModelLoader.mm @@ -5,14 +5,15 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import -#import -#import -#import -#import -#import -#import -#import +#import "ETCoreMLModelLoader.h" + +#import "asset.h" +#import "ETCoreMLAsset.h" +#import "ETCoreMLAssetManager.h" +#import "ETCoreMLDefaultModelExecutor.h" +#import "ETCoreMLLogging.h" +#import "ETCoreMLModel.h" +#import "model_metadata.h" using namespace executorchcoreml; @@ -64,8 +65,7 @@ + (nullable ETCoreMLModel *)loadModelWithContentsOfURL:(NSURL *)compiledModelURL if (localError) { ETCoreMLLogError(localError, - "%@: Failed to load model from compiled asset with identifier = %@", - NSStringFromClass(ETCoreMLModelLoader.class), + "Failed to load model from compiled asset with identifier = %@", identifier); } diff --git a/backends/apple/coreml/runtime/delegate/ETCoreMLModelManager.mm b/backends/apple/coreml/runtime/delegate/ETCoreMLModelManager.mm index 3848f7c9b3c..c6da7750a11 100644 --- a/backends/apple/coreml/runtime/delegate/ETCoreMLModelManager.mm +++ b/backends/apple/coreml/runtime/delegate/ETCoreMLModelManager.mm @@ -5,6 +5,8 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. +#import "ETCoreMLModelManager.h" + #import "ETCoreMLAsset.h" #import "ETCoreMLAssetManager.h" #import "ETCoreMLDefaultModelExecutor.h" @@ -13,20 +15,20 @@ #import "ETCoreMLModelCompiler.h" #import "ETCoreMLModelExecutor.h" #import "ETCoreMLModelLoader.h" -#import "ETCoreMLModelManager.h" #import "ETCoreMLStrings.h" #import "MLModel_Prewarm.h" #import "MLMultiArray_Copy.h" -#import #import "inmemory_filesystem_utils.hpp" -#import -#import #import "model_metadata.h" #import "multiarray.h" #import "objc_array_util.h" +#import "serde_json.h" + +#import +#import +#import #import #import -#import "serde_json.h" #import #import #import @@ -73,11 +75,15 @@ BOOL is_backed_by_same_buffer(MLMultiArray *array1, MLMultiArray *array2) { __block BOOL result = NO; - [array1 getBytesWithHandler:^(const void *bytes1, NSInteger __unused size1){ - [array2 getBytesWithHandler:^(const void *bytes2, NSInteger __unused size2) { - result = (bytes1 == bytes2); + if (@available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *)) { + [array1 getBytesWithHandler:^(const void *bytes1, NSInteger __unused size1){ + [array2 getBytesWithHandler:^(const void *bytes2, NSInteger __unused size2) { + result = (bytes1 == bytes2); + }]; }]; - }]; + } else { + result = (array1.dataPointer == array2.dataPointer); + } return result; } @@ -86,17 +92,19 @@ BOOL is_backed_by_same_buffer(MLMultiArray *array1, MLMultiArray *array2) { NSOrderedSet *output_names, NSError * __autoreleasing *error) { MLPredictionOptions *options = [MLPredictionOptions new]; - NSMutableDictionary *output_backings = [NSMutableDictionary new]; - NSEnumerator *enumerator = [output_names objectEnumerator]; - for (MLMultiArray *output in outputs) { - NSString *output_name = [enumerator nextObject]; - if (output_name.length == 0) { - ETCoreMLLogErrorAndSetNSError(error, 0, "%@: Model is broken.", NSStringFromClass(ETCoreMLModelManager.class)); - return nil; + if (@available(macOS 11.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)) { + NSMutableDictionary *output_backings = [NSMutableDictionary dictionary]; + NSEnumerator *enumerator = [output_names objectEnumerator]; + for (MLMultiArray *output in outputs) { + NSString *output_name = [enumerator nextObject]; + if (output_name.length == 0) { + ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, "Model is broken."); + return nil; + } + output_backings[output_name] = output; } - output_backings[output_name] = output; + options.outputBackings = output_backings; } - options.outputBackings = output_backings; return options; } @@ -138,14 +146,25 @@ void set_outputs(NSArray *outputs, NSArray *mode } void copy(MLMultiArray *src, executorchcoreml::MultiArray& dst) { - [src getBytesWithHandler:^(const void * _Nonnull bytes, NSInteger size) { + void (^copy_data)(void *) = ^(void *bytes) { if (bytes == dst.data()) { return; } - - MultiArray::MemoryLayout src_layout(get_data_type(src.dataType).value(), to_vector(src.shape), to_vector(src.strides)); + + MultiArray::MemoryLayout src_layout( + get_data_type(src.dataType).value(), + to_vector(src.shape), + to_vector(src.strides) + ); MultiArray(const_cast(bytes), std::move(src_layout)).copy(dst); - }]; + }; + if (@available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *)) { + [src getBytesWithHandler:^(const void * _Nonnull bytes, NSInteger size) { + copy_data(const_cast(bytes)); + }]; + } else { + copy_data(src.dataPointer); + } } void set_outputs(std::vector& outputs, @@ -212,8 +231,7 @@ void set_outputs(std::vector& outputs, ETCoreMLLogUnderlyingErrorAndSetNSError(error, ETCoreMLErrorModelSaveFailed, local_error, - "%@: Failed to create directory when saving model with identifier = %@.", - NSStringFromClass(ETCoreMLModelManager.class), + "Failed to create directory when saving model with identifier = %@.", identifier); return nil; } @@ -236,8 +254,7 @@ void set_outputs(std::vector& outputs, if (!inmemory_fs->write_item_to_disk(file_path, model_path, true, ec)) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorModelSaveFailed, - "%@: Failed to write model files to disk when saving model with identifier = %@.", - NSStringFromClass(ETCoreMLModelManager.class), + "Failed to write model files to disk when saving model with identifier = %@.", identifier); return nil; } @@ -395,8 +412,7 @@ - (nullable ETCoreMLAsset *)assetWithIdentifier:(NSString *)identifier { modelAsset = [self.assetManager assetWithIdentifier:identifier error:&localError]; if (localError) { ETCoreMLLogError(localError, - "%@: Failed to retrieve asset with identifier = %@", - NSStringFromClass(self.assetManager.class), + "Failed to retrieve asset with identifier = %@.", identifier); } @@ -411,8 +427,7 @@ - (nullable NSURL *)compiledModelURLWithIdentifier:(NSString *)identifier if (!modelAssetType) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, - "%@: AOT blob is missing model file.", - NSStringFromClass(ETCoreMLModelManager.class)); + "AOT blob is missing model file."); return nil; } @@ -420,11 +435,12 @@ - (nullable NSURL *)compiledModelURLWithIdentifier:(NSString *)identifier NSURL *modelURL = ::write_model_files(dstURL, self.fileManager, identifier, modelAssetType.value(), inMemoryFS, error); switch (modelAssetType.value()) { case ModelAssetType::CompiledModel: { + // Model is already compiled. return modelURL; } case ModelAssetType::Model: { - // we need to compiled the model. + // Compile the model. NSURL *compiledModelURL = [ETCoreMLModelCompiler compileModelAtURL:modelURL maxWaitTimeInSeconds:(5 * 60) error:error]; @@ -442,6 +458,12 @@ - (nullable NSURL *)compiledModelURLWithIdentifier:(NSString *)identifier NSString *identifier = @(metadata.identifier.c_str()); // Otherwise try to retrieve the compiled asset. ETCoreMLAsset *compiledModelAsset = [self assetWithIdentifier:identifier]; + if (compiledModelAsset) { + ETCoreMLLogInfo("Cache Hit: Successfully retrieved model with identifier=%@ from the models cache.", identifier); + } else { + ETCoreMLLogInfo("Cache Miss: Model with identifier=%@ was not found in the models cache.", identifier); + } + // Create a unique directory for writing model files. NSURL *dstURL = [self.assetManager.trashDirectoryURL URLByAppendingPathComponent:[NSUUID UUID].UUIDString]; auto modelAssetType = get_model_asset_type(inMemoryFS); @@ -499,9 +521,11 @@ - (nullable NSURL *)compiledModelURLWithIdentifier:(NSString *)identifier ETCoreMLAsset *asset = [self assetWithIdentifier:identifier]; ETCoreMLModel *model = asset ? get_model_from_asset(asset, configuration, metadata, error) : nil; if (model) { + ETCoreMLLogInfo("Cache Hit: Successfully retrieved model with identifier=%@ from the models cache.", identifier); return [[ETCoreMLDefaultModelExecutor alloc] initWithModel:model]; } + ETCoreMLLogInfo("Cache Miss: Model with identifier=%@ was not found in the models cache.", identifier); // Compile the model. NSURL *compiledModelURL = [self compiledModelURLWithIdentifier:identifier inMemoryFS:inMemoryFS @@ -531,8 +555,7 @@ - (nullable NSURL *)compiledModelURLWithIdentifier:(NSString *)identifier if (!inMemoryFS) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, - "%@: Model data is corrupted.", - NSStringFromClass(ETCoreMLModelManager.class)); + "Model data is corrupted."); return nil; } @@ -540,8 +563,7 @@ - (nullable NSURL *)compiledModelURLWithIdentifier:(NSString *)identifier if (!metadata) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedMetadata, - "%@: Metadata is invalid or missing.", - NSStringFromClass(ETCoreMLModelManager.class)); + "Metadata is invalid or missing."); return nil; } @@ -607,9 +629,7 @@ - (void)prewarmRecentlyUsedAssetsWithMaxCount:(NSUInteger)maxCount { NSArray *assets = [self.assetManager mostRecentlyUsedAssetsWithMaxCount:maxCount error:&localError]; if (localError) { - ETCoreMLLogError(localError, - "%@: Failed to retrieve recently used assets.", - NSStringFromClass(self.assetManager.class)); + ETCoreMLLogError(localError, "Failed to retrieve recently used assets."); } if (assets.count == 0) { @@ -627,8 +647,7 @@ - (void)prewarmRecentlyUsedAssetsWithMaxCount:(NSUInteger)maxCount { NSError *prewarmError = nil; if (![asset prewarmAndReturnError:&prewarmError]) { ETCoreMLLogError(prewarmError, - "%@: Failed to prewarm asset with identifier = %@", - NSStringFromClass(strongSelf.assetManager.class), + "Failed to prewarm asset with identifier = %@", asset.identifier); return; } @@ -664,18 +683,20 @@ - (void)addPrewarmedAsset:(ETCoreMLAsset *)asset { NSArray *modelOutputs = [executor executeModelWithInputs:inputFeatures predictionOptions:predictionOptions - loggingOptions:loggingOptions + loggingOptions:loggingOptions eventLogger:eventLogger error:&localError]; // Try without output backings. - if (!modelOutputs && predictionOptions.outputBackings.count > 0) { - executor.ignoreOutputBackings = YES; - localError = nil; - modelOutputs = [executor executeModelWithInputs:inputFeatures - predictionOptions:predictionOptions - loggingOptions:loggingOptions - eventLogger:eventLogger - error:&localError]; + if (@available(macOS 11.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)) { + if (!modelOutputs && predictionOptions.outputBackings.count > 0) { + executor.ignoreOutputBackings = YES; + localError = nil; + modelOutputs = [executor executeModelWithInputs:inputFeatures + predictionOptions:predictionOptions + loggingOptions:loggingOptions + eventLogger:eventLogger + error:&localError]; + } } if (error) { @@ -693,9 +714,8 @@ - (BOOL)executeModelWithHandle:(ModelHandle *)handle id executor = [self executorWithHandle:handle]; if (!executor) { ETCoreMLLogErrorAndSetNSError(error, - 0, - "%@: Model is already unloaded.", - NSStringFromClass(self.class)); + ETCoreMLErrorInternalError, + "Model is already unloaded."); return NO; } @@ -703,8 +723,7 @@ - (BOOL)executeModelWithHandle:(ModelHandle *)handle if (args.count != model.orderedInputNames.count + model.orderedOutputNames.count) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, - "%@: Model is invalid, expected args count to be %lu but got %lu.", - NSStringFromClass(self.class), + "Model is invalid, expected args count to be %lu but got %lu.", static_cast(model.orderedInputNames.count + model.orderedOutputNames.count), args.count); return NO; @@ -741,9 +760,8 @@ - (BOOL)executeModelWithHandle:(ModelHandle *)handle id executor = [self executorWithHandle:handle]; if (!executor) { ETCoreMLLogErrorAndSetNSError(error, - 0, - "%@: Model is already unloaded.", - NSStringFromClass(self.class)); + ETCoreMLErrorInternalError, + "Model is already unloaded."); return NO; } @@ -751,8 +769,7 @@ - (BOOL)executeModelWithHandle:(ModelHandle *)handle if (argsVec.size() != model.orderedInputNames.count + model.orderedOutputNames.count) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, - "%@: Model is invalid, expected args count to be %lu but got %lu.", - NSStringFromClass(self.class), + "Model is invalid, expected args count to be %lu but got %lu.", static_cast(model.orderedInputNames.count + model.orderedOutputNames.count), argsVec.size()); return NO; diff --git a/backends/apple/coreml/runtime/delegate/MLModel_Prewarm.mm b/backends/apple/coreml/runtime/delegate/MLModel_Prewarm.mm index d6f59666cf0..6a737d1e82b 100644 --- a/backends/apple/coreml/runtime/delegate/MLModel_Prewarm.mm +++ b/backends/apple/coreml/runtime/delegate/MLModel_Prewarm.mm @@ -5,10 +5,34 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "MLModel_Prewarm.h" +#include #import +namespace { + size_t get_number_of_bytes(MLMultiArrayDataType data_type) { + switch (data_type) { + case MLMultiArrayDataTypeFloat16: { + return 2; + } + case MLMultiArrayDataTypeFloat32: { + return 4; + } + case MLMultiArrayDataTypeInt32: { + return 4; + } + case MLMultiArrayDataTypeFloat64: { + return 8; + } + default: { + return 0; + } + } + } + +} + @interface MLMultiArray (Prewarm) + (nullable MLMultiArray *)zeroedMultiArrayWithShape:(NSArray *)shape @@ -28,11 +52,22 @@ + (MLMultiArray *)zeroedMultiArrayWithShape:(NSArray *)shape return nil; } - [multiArray getMutableBytesWithHandler:^(void *mutableBytes, NSInteger size, NSArray * __unused strides) { - uint8_t *start = reinterpret_cast(mutableBytes); - uint8_t *end = start + size; - std::fill(start, end, uint8_t(0)); - }]; + + if (@available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *)) { + void (^fill_zeroes)(void *, NSInteger) = ^(void *bytes, NSInteger size) { + uint8_t *start = reinterpret_cast(bytes); + uint8_t *end = start + size; + std::fill(start, end, uint8_t(0)); + }; + + if (@available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *)) { + [multiArray getMutableBytesWithHandler:^(void *mutableBytes, NSInteger size, NSArray * __unused strides) { + fill_zeroes(mutableBytes, size); + }]; + } else { + fill_zeroes(multiArray.dataPointer, multiArray.count * get_number_of_bytes(multiArray.dataType)); + } + } return multiArray; } diff --git a/backends/apple/coreml/runtime/delegate/MLMultiArray_Copy.mm b/backends/apple/coreml/runtime/delegate/MLMultiArray_Copy.mm index b8a10fcbbbc..313ee3edaf9 100644 --- a/backends/apple/coreml/runtime/delegate/MLMultiArray_Copy.mm +++ b/backends/apple/coreml/runtime/delegate/MLMultiArray_Copy.mm @@ -5,10 +5,10 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "MLMultiArray_Copy.h" -#import -#import +#import "objc_array_util.h" +#import "multiarray.h" namespace { using namespace executorchcoreml; @@ -27,13 +27,19 @@ MultiArray to_multi_array(void *data, @implementation MLMultiArray (Copy) - (void)copyInto:(MLMultiArray *)dstMultiArray { - [self getBytesWithHandler:^(const void *srcBytes, __unused NSInteger srcSize) { - [dstMultiArray getMutableBytesWithHandler:^(void *dstBytes, __unused NSInteger size, NSArray * strides) { - auto src = ::to_multi_array(const_cast(srcBytes), self.dataType, self.shape, self.strides); - auto dst = ::to_multi_array(dstBytes, dstMultiArray.dataType, dstMultiArray.shape, strides); - src.copy(dst); + if (@available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *)) { + [self getBytesWithHandler:^(const void *srcBytes, __unused NSInteger srcSize) { + [dstMultiArray getMutableBytesWithHandler:^(void *dstBytes, __unused NSInteger size, NSArray * strides) { + auto src = ::to_multi_array(const_cast(srcBytes), self.dataType, self.shape, self.strides); + auto dst = ::to_multi_array(dstBytes, dstMultiArray.dataType, dstMultiArray.shape, strides); + src.copy(dst); + }]; }]; - }]; + } else { + auto src = ::to_multi_array(self.dataPointer, self.dataType, self.shape, self.strides); + auto dst = ::to_multi_array(dstMultiArray.dataPointer, dstMultiArray.dataType, dstMultiArray.shape, dstMultiArray.strides); + src.copy(dst); + } } @end diff --git a/backends/apple/coreml/runtime/delegate/asset.mm b/backends/apple/coreml/runtime/delegate/asset.mm index c9a6e16d2af..6df2dfbd3c5 100644 --- a/backends/apple/coreml/runtime/delegate/asset.mm +++ b/backends/apple/coreml/runtime/delegate/asset.mm @@ -1,16 +1,16 @@ // -// ModelAsset.cpp +// asset.cpp // // Copyright © 2024 Apple Inc. All rights reserved. // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "asset.h" #import -#import +#import "objc_safe_cast.h" namespace { diff --git a/backends/apple/coreml/runtime/delegate/backend_delegate.h b/backends/apple/coreml/runtime/delegate/backend_delegate.h index 9af3df01af2..93c420e11d2 100644 --- a/backends/apple/coreml/runtime/delegate/backend_delegate.h +++ b/backends/apple/coreml/runtime/delegate/backend_delegate.h @@ -7,7 +7,8 @@ #pragma once -#include +#include "model_logging_options.h" + #include #include #include diff --git a/backends/apple/coreml/runtime/delegate/backend_delegate.mm b/backends/apple/coreml/runtime/delegate/backend_delegate.mm index d8096e16781..2cb274f0a89 100644 --- a/backends/apple/coreml/runtime/delegate/backend_delegate.mm +++ b/backends/apple/coreml/runtime/delegate/backend_delegate.mm @@ -6,13 +6,15 @@ // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import -#import -#import -#import -#import -#import -#import +#import "backend_delegate.h" + +#import "ETCoreMLAssetManager.h" +#import "ETCoreMLLogging.h" +#import "ETCoreMLModel.h" +#import "ETCoreMLModelManager.h" +#import "ETCoreMLStrings.h" +#import "model_event_logger.h" +#import "multiarray.h" namespace { using namespace executorchcoreml; @@ -282,6 +284,9 @@ explicit BackendDelegateImpl(const Config& config) noexcept ModelHandle *modelHandle = [model_manager_ loadModelFromAOTData:data configuration:configuration error:&localError]; + if (localError != nil) { + ETCoreMLLogError(localError, "Model init failed"); + } return modelHandle; } @@ -290,13 +295,16 @@ bool execute(Handle* handle, const ModelLoggingOptions& logging_options, ModelEventLogger *event_logger, std::error_code& ec) const noexcept override { - NSError *error = nil; + NSError *localError = nil; if (![model_manager_ executeModelWithHandle:handle argsVec:args loggingOptions:logging_options eventLogger:event_logger - error:&error]) { - ec = static_cast(error.code); + error:&localError]) { + if (localError != nil) { + ETCoreMLLogError(localError, "Model execution failed"); + ec = static_cast(localError.code); + } return false; } diff --git a/backends/apple/coreml/runtime/delegate/coreml_backend_delegate.mm b/backends/apple/coreml/runtime/delegate/coreml_backend_delegate.mm index 380ec52b7d7..028191ce497 100644 --- a/backends/apple/coreml/runtime/delegate/coreml_backend_delegate.mm +++ b/backends/apple/coreml/runtime/delegate/coreml_backend_delegate.mm @@ -5,22 +5,25 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import -#import -#import -#import -#import +#import "coreml_backend/delegate.h" + +#import "backend_delegate.h" +#import "ETCoreMLLogging.h" +#import "ETCoreMLModel.h" +#import "ETCoreMLStrings.h" +#import "model_event_logger.h" +#import "model_logging_options.h" +#import "multiarray.h" +#import "objc_safe_cast.h" + #import #import #import + +#include #import -#import -#import -#import -#import #import #import -#include #ifdef ET_EVENT_TRACER_ENABLED #import diff --git a/backends/apple/coreml/runtime/delegate/model_metadata.h b/backends/apple/coreml/runtime/delegate/model_metadata.h index 275aa39dd3b..8d0c1f0914d 100644 --- a/backends/apple/coreml/runtime/delegate/model_metadata.h +++ b/backends/apple/coreml/runtime/delegate/model_metadata.h @@ -10,7 +10,7 @@ #import #import -#import +#import "serde_json.h" namespace executorchcoreml { diff --git a/backends/apple/coreml/runtime/delegate/multiarray.mm b/backends/apple/coreml/runtime/delegate/multiarray.mm index de705991780..d38ac377799 100644 --- a/backends/apple/coreml/runtime/delegate/multiarray.mm +++ b/backends/apple/coreml/runtime/delegate/multiarray.mm @@ -6,13 +6,14 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "multiarray.h" + +#import "objc_array_util.h" #import #import #import #import -#import #import #import diff --git a/backends/apple/coreml/runtime/delegate/serde_json.mm b/backends/apple/coreml/runtime/delegate/serde_json.mm index 3568ffe4ce8..e39df4d734e 100644 --- a/backends/apple/coreml/runtime/delegate/serde_json.mm +++ b/backends/apple/coreml/runtime/delegate/serde_json.mm @@ -5,11 +5,11 @@ // // Please refer to the license found in the LICENSE file in the root directory of the source tree. -#import +#import "serde_json.h" -#import -#import -#import +#import "asset.h" +#import "objc_json_serde.h" +#import "model_metadata.h" namespace { struct FileInfoKeys { diff --git a/backends/apple/coreml/runtime/sdk/ETCoreMLModelAnalyzer.mm b/backends/apple/coreml/runtime/sdk/ETCoreMLModelAnalyzer.mm index 988b5d808a0..87e086c5bbd 100644 --- a/backends/apple/coreml/runtime/sdk/ETCoreMLModelAnalyzer.mm +++ b/backends/apple/coreml/runtime/sdk/ETCoreMLModelAnalyzer.mm @@ -65,9 +65,7 @@ - (nullable instancetype)initWithCompiledModelAsset:(ETCoreMLAsset *)compiledMod assetManager:assetManager error:&localError]; if (!model) { - ETCoreMLLogError(localError, - "%@: Failed to create model profiler.", - NSStringFromClass(ETCoreMLAssetManager.class)); + ETCoreMLLogError(localError, "Failed to create model profiler."); } self = [super init]; @@ -98,8 +96,7 @@ - (nullable instancetype)initWithCompiledModelAsset:(ETCoreMLAsset *)compiledMod if (!self.profiler) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorModelProfilingNotSupported, - "%@: Model profiling is only available for macOS >= 14.4, iOS >= 17.4, tvOS >= 17.4 and watchOS >= 10.4.", - NSStringFromClass(ETCoreMLModelAnalyzer.class)); + "Model profiling is only available for macOS >= 14.4, iOS >= 17.4, tvOS >= 17.4 and watchOS >= 10.4."); return nil; } @@ -125,8 +122,7 @@ - (nullable instancetype)initWithCompiledModelAsset:(ETCoreMLAsset *)compiledMod if (!self.modelAsset) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedData, - "%@: There is no mlpackage, mlpackage is required for debugging a model. Please check the export path.", - NSStringFromClass(ETCoreMLModelAnalyzer.class)); + "The AOT blob is missing an 'mlpackage', which is required for debugging the model. Please check the export path."); return nil; } diff --git a/backends/apple/coreml/runtime/sdk/ETCoreMLModelDebugger.mm b/backends/apple/coreml/runtime/sdk/ETCoreMLModelDebugger.mm index 3be28b56d66..1cac0de40f3 100644 --- a/backends/apple/coreml/runtime/sdk/ETCoreMLModelDebugger.mm +++ b/backends/apple/coreml/runtime/sdk/ETCoreMLModelDebugger.mm @@ -7,7 +7,6 @@ #import "ETCoreMLModelDebugger.h" -#import #import "ETCoreMLAsset.h" #import "ETCoreMLAssetManager.h" #import "ETCoreMLLogging.h" @@ -16,12 +15,14 @@ #import "ETCoreMLModelStructurePath.h" #import "ETCoreMLPair.h" #import "ETCoreMLStrings.h" -#import -#import -#import -#import +#import "format/MIL.pb.h" +#import "format/Model.pb.h" #import "model_package_info.h" #import "objc_json_serde.h" + +#import +#import +#import #import #import @@ -43,13 +44,19 @@ const auto& info_value = info.value(); auto it = info_value.items.find(info_value.root_model_identifier); if (it == info_value.items.end()) { - ETCoreMLLogErrorAndSetNSError(error, 0, "%@ is broken, root model info doesn't exist.", model_package_url.lastPathComponent); + ETCoreMLLogErrorAndSetNSError(error, + ETCoreMLErrorCorruptedModel, + "%@ is broken, root model info doesn't exist.", + model_package_url.lastPathComponent); return nil; } auto path = it->second.path; if (path.empty()) { - ETCoreMLLogErrorAndSetNSError(error, 0, "%@ is broken, root model path doesn't exist.", model_package_url.lastPathComponent); + ETCoreMLLogErrorAndSetNSError(error, + ETCoreMLErrorCorruptedModel, + "%@ is broken, root model path doesn't exist.", + model_package_url.lastPathComponent); return nil; } @@ -350,8 +357,8 @@ void set_model_outputs(id output_features, NSMutableArray *values = [NSMutableArray arrayWithCapacity:output_names.count]; for (NSString *output_name in output_names) { MLFeatureValue *feature_value = [output_features featureValueForName:output_name]; - NSCAssert(feature_value.multiArrayValue != nil, @"%@: Expected a multiarray value for output name=%@.", - NSStringFromClass(ETCoreMLModelDebugger.class), + NSCAssert(feature_value.multiArrayValue != nil, + @"Expected a multiarray value for output name=%@.", output_name); [values addObject:feature_value.multiArrayValue]; } @@ -570,8 +577,7 @@ - (nullable ETCoreMLAsset *)compiledModelAssetWithOutputsAtPaths:(NSArray #import diff --git a/backends/apple/coreml/runtime/sdk/ETCoreMLModelProfiler.mm b/backends/apple/coreml/runtime/sdk/ETCoreMLModelProfiler.mm index 5998701eb0f..e381bbb03d1 100644 --- a/backends/apple/coreml/runtime/sdk/ETCoreMLModelProfiler.mm +++ b/backends/apple/coreml/runtime/sdk/ETCoreMLModelProfiler.mm @@ -14,9 +14,10 @@ #import "ETCoreMLOperationProfilingInfo.h" #import "ETCoreMLPair.h" #import "ETCoreMLStrings.h" +#import "program_path.h" + #import #import -#import "program_path.h" namespace { using namespace executorchcoreml::modelstructure; @@ -42,8 +43,7 @@ ETCoreMLLogUnderlyingErrorAndSetNSError(error, ETCoreMLErrorCompilationFailed, local_error, - "%@: Failed to get compute plan of model with name=%@.", - NSStringFromClass(ETCoreMLModelProfiler.class), + "Failed to get compute plan of model with name=%@.", model_url.lastPathComponent); return nil; } @@ -288,8 +288,7 @@ - (nullable instancetype)initWithModel:(ETCoreMLModel *)model #endif ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorModelProfilingNotSupported, - "%@: Model profiling is only available for macOS >= 14.4, iOS >= 17.4, tvOS >= 17.4 and watchOS >= 10.4.", - NSStringFromClass(self.class)); + "Model profiling is only available for macOS >= 14.4, iOS >= 17.4, tvOS >= 17.4 and watchOS >= 10.4."); return nil; } diff --git a/backends/apple/coreml/runtime/sdk/ETCoreMLOperationProfilingInfo.h b/backends/apple/coreml/runtime/sdk/ETCoreMLOperationProfilingInfo.h index 80c49f8965e..13d4bb8e6ac 100644 --- a/backends/apple/coreml/runtime/sdk/ETCoreMLOperationProfilingInfo.h +++ b/backends/apple/coreml/runtime/sdk/ETCoreMLOperationProfilingInfo.h @@ -7,7 +7,7 @@ #import -#import +#import "ETCoreMLComputeUnits.h" NS_ASSUME_NONNULL_BEGIN diff --git a/backends/apple/coreml/runtime/sdk/model_event_logger_impl.mm b/backends/apple/coreml/runtime/sdk/model_event_logger_impl.mm index 12ac8ec15a3..be34e384b72 100644 --- a/backends/apple/coreml/runtime/sdk/model_event_logger_impl.mm +++ b/backends/apple/coreml/runtime/sdk/model_event_logger_impl.mm @@ -9,11 +9,13 @@ #import "ETCoreMLModelStructurePath.h" #import "ETCoreMLOperationProfilingInfo.h" -#import #import "objc_array_util.h" +#import "MLMultiArray_Copy.h" + +#import + #import #import -#import "MLMultiArray_Copy.h" namespace { diff --git a/backends/apple/coreml/runtime/sdk/model_package_info.mm b/backends/apple/coreml/runtime/sdk/model_package_info.mm index b7b26178fde..f4b13048718 100644 --- a/backends/apple/coreml/runtime/sdk/model_package_info.mm +++ b/backends/apple/coreml/runtime/sdk/model_package_info.mm @@ -66,7 +66,7 @@ static void from_json(id json, ModelPackageInfo& package_info) { NSURL *manifest_url = [model_package_url URLByAppendingPathComponent:@"manifest.json"].URLByStandardizingPath; BOOL is_directory = NO; if (![fm fileExistsAtPath:manifest_url.path isDirectory:&is_directory] || is_directory) { - ETCoreMLLogErrorAndSetNSError(error, 0, "%@ is broken, manifest doesn't exist.", model_package_url.lastPathComponent); + ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, "%@ is broken, manifest doesn't exist.", model_package_url.lastPathComponent); return std::nullopt; } diff --git a/backends/apple/coreml/runtime/test/ETCoreMLTestUtils.mm b/backends/apple/coreml/runtime/test/ETCoreMLTestUtils.mm index 3c0908201ac..50b0f2ec766 100644 --- a/backends/apple/coreml/runtime/test/ETCoreMLTestUtils.mm +++ b/backends/apple/coreml/runtime/test/ETCoreMLTestUtils.mm @@ -250,16 +250,14 @@ + (BOOL)extractModelAssetAndMetadataFromAOTData:(NSData *)data if (!inMemoryFS) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedModel, - "%@: Model data is corrupted.", - NSStringFromClass(ETCoreMLTestUtils.class)); + "Model data is corrupted."); return NO; } if (!extract_model_metadata(*inMemoryFS, metadata) || !metadata.is_valid()) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorCorruptedMetadata, - "%@: Model metadata is corrupted.", - NSStringFromClass(ETCoreMLTestUtils.class)); + "Model metadata is corrupted."); return NO; } @@ -269,8 +267,7 @@ + (BOOL)extractModelAssetAndMetadataFromAOTData:(NSData *)data if (![fileManager createDirectoryAtURL:modelURL withIntermediateDirectories:NO attributes:@{} error:error]) { ETCoreMLLogErrorAndSetNSError(error, ETCoreMLErrorModelSaveFailed, - "%@: Failed to create directory when saving model with name = %@.", - NSStringFromClass(ETCoreMLTestUtils.class), + "Failed to create directory when saving model with name = %@.", modelURL.lastPathComponent); return NO; } diff --git a/examples/apple/coreml/scripts/build_executor_runner.sh b/examples/apple/coreml/scripts/build_executor_runner.sh index bc3f2872291..bdfbf24a0cf 100755 --- a/examples/apple/coreml/scripts/build_executor_runner.sh +++ b/examples/apple/coreml/scripts/build_executor_runner.sh @@ -5,11 +5,33 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +set -e + +MODE="Release" + +usage() { + echo "Builds Core ML executor runner" + echo "Options:" + echo " --Debug Use Debug build mode. Default: 'Release'" + echo "Example:" + echo " $0 --Debug" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) usage ;; + --Debug) MODE="Debug" ;; + *) + esac +done + SCRIPT_DIR_PATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 pwd -P )" + EXECUTORCH_ROOT_PATH=$(realpath "$SCRIPT_DIR_PATH/../../../../") COREML_DIR_PATH="$EXECUTORCH_ROOT_PATH/backends/apple/coreml" EXAMPLES_COREML_DIR_PATH="$EXECUTORCH_ROOT_PATH/examples/apple/coreml" @@ -23,13 +45,13 @@ cd "$EXECUTORCH_ROOT_PATH" echo "ExecuTorch: Building executor_runner" -echo "ExecuTorch: Removing build directory $CMAKE_BUILD_DIR" +echo "ExecuTorch: Removing build directory $CMAKE_BUILD_DIR_PATH" rm -rf "$CMAKE_BUILD_DIR_PATH" # Build executorch echo "ExecuTorch: Building executorch" cmake "$EXECUTORCH_ROOT_PATH" -B"$CMAKE_BUILD_DIR_PATH" \ --DCMAKE_BUILD_TYPE=Release \ +-DCMAKE_BUILD_TYPE="$MODE" \ -DCMAKE_TOOLCHAIN_FILE="$IOS_TOOLCHAIN_PATH" \ -DPLATFORM=MAC_UNIVERSAL \ -DDEPLOYMENT_TARGET=13.0 \