Skip to content

[Core ML] Improve error logging #9801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backends/apple/coreml/runtime/delegate/ETCoreMLAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#import <Foundation/Foundation.h>

#import <asset.h>
#import "asset.h"

NS_ASSUME_NONNULL_BEGIN

Expand Down
12 changes: 8 additions & 4 deletions backends/apple/coreml/runtime/delegate/ETCoreMLAsset.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
//
// Please refer to the license found in the LICENSE file in the root directory of the source tree.

#import <ETCoreMLAsset.h>
#import "ETCoreMLAsset.h"

#import "ETCoreMLLogging.h"
#import "objc_safe_cast.h"

#import <fcntl.h>
#import <os/lock.h>
#import <stdio.h>
#import <system_error>

#import <objc_safe_cast.h>

namespace {
using namespace executorchcoreml;

Expand Down Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#import <Foundation/Foundation.h>

#import <database.hpp>
#import "database.hpp"

@class ETCoreMLAsset;

Expand Down
40 changes: 17 additions & 23 deletions backends/apple/coreml/runtime/delegate/ETCoreMLAssetManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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 <ETCoreMLAsset.h>
#import <ETCoreMLLogging.h>
#import <database.hpp>

#import "ETCoreMLAsset.h"
#import "ETCoreMLLogging.h"
#import "database.hpp"
#import "json_key_value_store.hpp"
#import "serde_json.h"

#import <iostream>
#import <json_key_value_store.hpp>
#import <serde_json.h>
#import <sstream>

namespace {
Expand Down Expand Up @@ -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);
}
});
Expand Down Expand Up @@ -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.");
}
});
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <CoreML/CoreML.h>

#import <ETCoreMLModelExecutor.h>
#import "ETCoreMLModelExecutor.h"

@class ETCoreMLModel;

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <ETCoreMLAsset.h>
#import <ETCoreMLDefaultModelExecutor.h>
#import <ETCoreMLLogging.h>
#import <ETCoreMLModel.h>
#import "ETCoreMLAsset.h"
#import "ETCoreMLDefaultModelExecutor.h"
#import "ETCoreMLLogging.h"
#import "ETCoreMLModel.h"

@implementation ETCoreMLDefaultModelExecutor

Expand All @@ -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<MLFeatureProvider> outputs = [self.model predictionFromFeatures:inputs
Expand All @@ -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;
}
Expand Down
94 changes: 47 additions & 47 deletions backends/apple/coreml/runtime/delegate/ETCoreMLLogging.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
// Please refer to the license found in the LICENSE file in the root directory of the source tree.

#import <Foundation/Foundation.h>
#import <os/log.h>

#import <executorch/runtime/platform/log.h>
#import <os/log.h>

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions backends/apple/coreml/runtime/delegate/ETCoreMLLogging.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
//
// Please refer to the license found in the LICENSE file in the root directory of the source tree.

#import <ETCoreMLLogging.h>
#import "ETCoreMLLogging.h"

#import <ETCoreMLStrings.h>
#import "ETCoreMLStrings.h"

const NSErrorDomain ETCoreMLErrorDomain = @"com.apple.executorchcoreml";

Expand Down
24 changes: 16 additions & 8 deletions backends/apple/coreml/runtime/delegate/ETCoreMLModel.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//
// Please refer to the license found in the LICENSE file in the root directory of the source tree.

#import <ETCoreMLModel.h>
#import "ETCoreMLModel.h"

#import "ETCoreMLAsset.h"
#import "ETCoreMLLogging.h"
Expand Down Expand Up @@ -256,14 +256,23 @@ - (NSString *)identifier {
}

if (multiArrayArg && lCopyData) {
[multiArrayArg getMutableBytesWithHandler:^(void *_Nonnull mutableBytes,
NSInteger __unused size,
NSArray<NSNumber *> *strides) {
MultiArray buffer(mutableBytes, MultiArray::MemoryLayout(to_multiarray_data_type(constraint.dataType).value(),
void (^copy_data)(void *, NSArray<NSNumber *> *) = ^(void *bytes, NSArray<NSNumber *> *strides) {
MultiArray buffer(bytes, MultiArray::MemoryLayout(to_multiarray_data_type(constraint.dataType).value(),
layout.shape(),
to_vector<ssize_t>(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<NSNumber *> *strides) {
copy_data(mutableBytes, strides);
}];
} else {
copy_data(multiArrayArg.dataPointer, multiArrayArg.strides);
}
}

[result addObject:multiArrayArg];
Expand Down Expand Up @@ -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);
}

Expand Down
Loading
Loading