forked from maderix/ANE
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi_exploration.m
More file actions
167 lines (151 loc) · 8.02 KB
/
api_exploration.m
File metadata and controls
167 lines (151 loc) · 8.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#import <Foundation/Foundation.h>
#import <CoreML/CoreML.h>
#import <objc/runtime.h>
#import <objc/message.h>
#import <dlfcn.h>
#import <mach/mach_time.h>
#import <IOSurface/IOSurface.h>
static mach_timebase_info_data_t g_tb;
static double ticksToMs(uint64_t t) { return (double)t * g_tb.numer / g_tb.denom / 1e6; }
int main() {
@autoreleasepool {
mach_timebase_info(&g_tb);
dlopen("/System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine", RTLD_NOW);
// === Approach 1: MLModelAsset from compiled .mlmodelc data ===
// First compile a known-working model to .mlmodelc
printf("=== Approach 1: MLModelAsset in-memory ===\n");
NSError *e = nil;
NSURL *src = [NSURL fileURLWithPath:@"/tmp/ane_sram_1024ch_64sp.mlpackage"];
NSURL *compiled = [MLModel compileModelAtURL:src error:&e];
if (e) { printf("Compile failed: %s\n", [[e description] UTF8String]); return 1; }
printf("Compiled to: %s\n", [[compiled path] UTF8String]);
// Read the model.mlmodel spec from the compiled bundle
// The spec is typically in coremldata.bin or model.mlmodel
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *files = [fm contentsOfDirectoryAtPath:[compiled path] error:nil];
printf("Files in .mlmodelc:\n");
for (NSString *f in files) printf(" %s\n", [f UTF8String]);
// Try loading with MLModelAsset
// MLModelAsset has modelAssetWithURL: on macOS 15
if (@available(macOS 14.0, *)) {
// Read the spec data
NSString *specPath = [[compiled path] stringByAppendingPathComponent:@"coremldata.bin"];
if (![fm fileExistsAtPath:specPath]) {
specPath = [[compiled path] stringByAppendingPathComponent:@"model.mlmodel"];
}
NSData *specData = [NSData dataWithContentsOfFile:specPath];
printf("Spec data: %lu bytes from %s\n", (unsigned long)[specData length],
[[specPath lastPathComponent] UTF8String]);
// Try MLModelAsset
Class assetClass = NSClassFromString(@"MLModelAsset");
if (assetClass) {
printf("MLModelAsset class found\n");
// List methods
unsigned int count;
Method *methods = class_copyMethodList(object_getClass(assetClass), &count);
for (unsigned int i = 0; i < count; i++)
printf(" + %s\n", sel_getName(method_getName(methods[i])));
free(methods);
}
}
// === Approach 2: Read a .mlmodelc, extract MIL, feed to _ANEInMemoryModelDescriptor ===
printf("\n=== Approach 2: Inspect MIL in compiled model ===\n");
// Look for model.mil or any MIL file
NSDirectoryEnumerator *en = [fm enumeratorAtPath:[compiled path]];
NSString *f;
while ((f = [en nextObject])) {
NSString *full = [[compiled path] stringByAppendingPathComponent:f];
BOOL isDir;
[fm fileExistsAtPath:full isDirectory:&isDir];
if (!isDir) {
NSDictionary *attrs = [fm attributesOfItemAtPath:full error:nil];
printf(" %s (%llu bytes)\n", [f UTF8String],
[[attrs objectForKey:NSFileSize] unsignedLongLongValue]);
}
}
// Try to find and read model.mil
NSString *milPath = [[compiled path] stringByAppendingPathComponent:@"model.mil"];
if ([fm fileExistsAtPath:milPath]) {
NSString *milText = [NSString stringWithContentsOfFile:milPath encoding:NSUTF8StringEncoding error:nil];
printf("\n=== model.mil contents (first 2000 chars) ===\n");
printf("%s\n", [[milText substringToIndex:MIN(2000, [milText length])] UTF8String]);
}
// Also check for mlmodelc structure
NSString *aneDir = nil;
en = [fm enumeratorAtPath:[compiled path]];
while ((f = [en nextObject])) {
if ([f hasSuffix:@".espresso.net"] || [f hasSuffix:@".hwx"] || [f hasSuffix:@".mil"]) {
printf(" FOUND: %s\n", [f UTF8String]);
}
}
// === Approach 3: Try _ANEInMemoryModelDescriptor with actual MIL from compiled model ===
printf("\n=== Approach 3: _ANEInMemoryModelDescriptor ===\n");
Class ANEInMemDesc = NSClassFromString(@"_ANEInMemoryModelDescriptor");
if (ANEInMemDesc) {
printf("Class exists. Methods:\n");
unsigned int count;
Method *methods = class_copyMethodList(object_getClass(ANEInMemDesc), &count);
for (unsigned int i = 0; i < count; i++) {
SEL s = method_getName(methods[i]);
printf(" + %s (args: %d)\n", sel_getName(s), method_getNumberOfArguments(methods[i]));
}
free(methods);
methods = class_copyMethodList(ANEInMemDesc, &count);
printf("Instance methods:\n");
for (unsigned int i = 0; i < count; i++) {
SEL s = method_getName(methods[i]);
const char *enc = method_getTypeEncoding(methods[i]);
printf(" - %s [%s]\n", sel_getName(s), enc ? enc : "?");
}
free(methods);
// If model.mil exists, try feeding it
if ([fm fileExistsAtPath:milPath]) {
NSString *milText = [NSString stringWithContentsOfFile:milPath encoding:NSUTF8StringEncoding error:nil];
printf("\nTrying modelWithMILText: with actual model.mil...\n");
id desc = ((id(*)(Class,SEL,id,id,id))objc_msgSend)(
ANEInMemDesc, @selector(modelWithMILText:weights:optionsPlist:),
milText, nil, nil);
printf("Result: %s\n", desc ? [[desc description] UTF8String] : "nil");
// Try with NSData
NSData *milData = [milText dataUsingEncoding:NSUTF8StringEncoding];
desc = ((id(*)(Class,SEL,id,id,id))objc_msgSend)(
ANEInMemDesc, @selector(modelWithMILText:weights:optionsPlist:),
milData, nil, nil);
printf("Result (NSData): %s\n", desc ? [[desc description] UTF8String] : "nil");
}
} else {
printf("_ANEInMemoryModelDescriptor NOT FOUND\n");
}
// === Approach 4: Hook into what CoreML actually sends to ANE ===
printf("\n=== Approach 4: Trace CoreML -> ANE path ===\n");
// Load the model the normal working way and inspect the _ANEModel
MLModelConfiguration *config = [[MLModelConfiguration alloc] init];
config.computeUnits = MLComputeUnitsAll;
MLModel *model = [MLModel modelWithContentsOfURL:compiled configuration:config error:&e];
if (e) { printf("MLModel load failed: %s\n", [[e description] UTF8String]); return 1; }
// Try to get internal model object
printf("MLModel: %s\n", [[model description] UTF8String]);
// Check if we can access the ANE model through the MLModel
// Try KVC for internal properties
@try {
id engine = [model valueForKey:@"engine"];
printf("engine: %s\n", engine ? [[engine description] UTF8String] : "nil");
} @catch(NSException *ex) {
printf("No 'engine' key\n");
}
@try {
id proxy = [model valueForKey:@"proxy"];
printf("proxy: %s\n", proxy ? [NSStringFromClass([proxy class]) UTF8String] : "nil");
} @catch(NSException *ex) {
printf("No 'proxy' key\n");
}
// Check MLNeuralNetworkEngine or MLANEEngine
Class aneEngine = NSClassFromString(@"MLANEEngine");
Class nnEngine = NSClassFromString(@"MLNeuralNetworkEngine");
Class milEngine = NSClassFromString(@"MLMILComputeEngine");
printf("MLANEEngine: %s\n", aneEngine ? "exists" : "not found");
printf("MLNeuralNetworkEngine: %s\n", nnEngine ? "exists" : "not found");
printf("MLMILComputeEngine: %s\n", milEngine ? "exists" : "not found");
}
return 0;
}