ANE/training/test_ane_model.m

2261 lines
112 KiB
Objective-C

// test_ane_model.m — Experiments E-H: _ANEModel loading, ANECompiler, chaining, shared events
// Build: make test_ane_model && ./test_ane_model
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
#import <dlfcn.h>
#import <IOSurface/IOSurface.h>
#import <mach/mach_time.h>
#include <limits.h>
static mach_timebase_info_data_t g_tb;
static double tb_ms(uint64_t t) { return (double)t * g_tb.numer / g_tb.denom / 1e6; }
__attribute__((unused)) static int g_fp16_io = 1;
#pragma mark - Helpers
static void dump_class(const char *name) {
Class cls = NSClassFromString([NSString stringWithUTF8String:name]);
if (!cls) { printf(" %s: NOT FOUND\n", name); return; }
printf("\n=== %s ===\n", name);
unsigned int count;
Method *methods = class_copyMethodList(object_getClass(cls), &count);
if (count) printf(" Class methods (%u):\n", count);
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);
methods = class_copyMethodList(cls, &count);
if (count) printf(" Instance methods (%u):\n", count);
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);
unsigned int pcount;
objc_property_t *props = class_copyPropertyList(cls, &pcount);
if (pcount) printf(" Properties (%u):\n", pcount);
for (unsigned int i = 0; i < pcount; i++) {
const char *pname = property_getName(props[i]);
const char *pattr = property_getAttributes(props[i]);
printf(" @property %s [%s]\n", pname, pattr ? pattr : "?");
}
free(props);
}
static void dump_all_properties(id obj, Class cls) {
if (!obj) return;
unsigned int pcount;
objc_property_t *props = class_copyPropertyList(cls, &pcount);
for (unsigned int i = 0; i < pcount; i++) {
const char *pname = property_getName(props[i]);
@try {
id val = [obj valueForKey:[NSString stringWithUTF8String:pname]];
printf(" %s = %s\n", pname, val ? [[val description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf(" %s = <exception: %s>\n", pname, [[ex reason] UTF8String]);
}
}
free(props);
}
static void list_dir_recursive(NSString *path, int depth) {
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *items = [fm contentsOfDirectoryAtPath:path error:nil];
for (NSString *item in items) {
NSString *full = [path stringByAppendingPathComponent:item];
BOOL isDir = NO;
[fm fileExistsAtPath:full isDirectory:&isDir];
NSDictionary *attrs = [fm attributesOfItemAtPath:full error:nil];
unsigned long long sz = [attrs fileSize];
for (int i = 0; i < depth; i++) printf(" ");
if (isDir) {
printf(" [DIR] %s/\n", [item UTF8String]);
list_dir_recursive(full, depth + 1);
} else {
printf(" %s (%llu bytes)\n", [item UTF8String], sz);
}
}
}
static IOSurfaceRef make_surface(size_t bytes) {
return IOSurfaceCreate((__bridge CFDictionaryRef)@{
(id)kIOSurfaceWidth:@(bytes), (id)kIOSurfaceHeight:@1,
(id)kIOSurfaceBytesPerElement:@1, (id)kIOSurfaceBytesPerRow:@(bytes),
(id)kIOSurfaceAllocSize:@(bytes), (id)kIOSurfacePixelFormat:@0});
}
#pragma mark - MIL Generation (FP16 conv)
static NSString *gen_conv_mil(int ch, int sp) {
return [NSString stringWithFormat:
@"program(1.0)\n[buildInfo = dict<tensor<string, []>, tensor<string, []>>"
"({{\"coremlc-version\", \"3505.4.1\"}})]\n{\n"
" func main<ios16>(tensor<fp16, [1, %d, 1, %d]> x) {\n"
" tensor<string, []> pt = const()[name=tensor<string, []>(\"pt\"),"
" val=tensor<string, []>(\"valid\")];\n"
" tensor<int32, [2]> st = const()[name=tensor<string, []>(\"st\"),"
" val=tensor<int32, [2]>([1,1])];\n"
" tensor<int32, [4]> pd = const()[name=tensor<string, []>(\"pd\"),"
" val=tensor<int32, [4]>([0,0,0,0])];\n"
" tensor<int32, [2]> dl = const()[name=tensor<string, []>(\"dl\"),"
" val=tensor<int32, [2]>([1,1])];\n"
" tensor<int32, []> gr = const()[name=tensor<string, []>(\"gr\"),"
" val=tensor<int32, []>(1)];\n"
" tensor<fp16, [%d,%d,1,1]> W = const()[name=tensor<string, []>(\"W\"), "
"val=tensor<fp16, [%d,%d,1,1]>(BLOBFILE(path=tensor<string, []>"
"(\"@model_path/weights/weight.bin\"), offset=tensor<uint64, []>(64)))];\n"
" tensor<fp16, [1,%d,1,%d]> y = conv(dilations=dl,groups=gr,"
"pad=pd,pad_type=pt,strides=st,weight=W,x=x)"
"[name=tensor<string, []>(\"conv\")];\n"
" } -> (y);\n}\n", ch, sp, ch, ch, ch, ch, ch, sp];
}
#pragma mark - Kernel Compilation
typedef struct {
id model;
IOSurfaceRef ioIn, ioOut;
NSString *tmpDir;
NSString *hexId;
int ch, sp;
} CompiledKernel;
static CompiledKernel compile_kernel(int ch, int sp) {
CompiledKernel k = {0};
k.ch = ch; k.sp = sp;
Class gD = NSClassFromString(@"_ANEInMemoryModelDescriptor");
Class gI = NSClassFromString(@"_ANEInMemoryModel");
if (!gD || !gI) { printf(" ERROR: ANE classes not found\n"); return k; }
int ws = ch * ch * 2;
int tot = 128 + ws;
uint8_t *blob = (uint8_t *)calloc((size_t)tot, 1);
blob[0] = 1; blob[4] = 2;
blob[64] = 0xEF; blob[65] = 0xBE; blob[66] = 0xAD; blob[67] = 0xDE;
blob[68] = 1;
*(uint32_t *)(blob + 72) = (uint32_t)ws;
*(uint32_t *)(blob + 80) = 128;
_Float16 *wp = (_Float16 *)(blob + 128);
for (int i = 0; i < ch; i++) wp[i * ch + i] = (_Float16)1.0f;
NSData *wdata = [NSData dataWithBytesNoCopy:blob length:(NSUInteger)tot
freeWhenDone:YES];
NSString *mil = gen_conv_mil(ch, sp);
NSData *md = [mil dataUsingEncoding:NSUTF8StringEncoding];
id desc = ((id(*)(Class,SEL,id,id,id))objc_msgSend)(gD,
@selector(modelWithMILText:weights:optionsPlist:),
md, @{@"@model_path/weights/weight.bin": @{@"offset":@0, @"data":wdata}}, nil);
id mdl = ((id(*)(Class,SEL,id))objc_msgSend)(gI,
@selector(inMemoryModelWithDescriptor:), desc);
if (!mdl) { printf(" ERROR: inMemoryModel creation failed\n"); return k; }
id hx = ((id(*)(id,SEL))objc_msgSend)(mdl, @selector(hexStringIdentifier));
k.hexId = hx;
NSString *td = [NSTemporaryDirectory() stringByAppendingPathComponent:hx];
NSFileManager *fm = [NSFileManager defaultManager];
[fm createDirectoryAtPath:[td stringByAppendingPathComponent:@"weights"]
withIntermediateDirectories:YES attributes:nil error:nil];
[md writeToFile:[td stringByAppendingPathComponent:@"model.mil"] atomically:YES];
[wdata writeToFile:[td stringByAppendingPathComponent:@"weights/weight.bin"]
atomically:YES];
NSError *e = nil;
BOOL ok = ((BOOL(*)(id,SEL,unsigned int,id,NSError**))objc_msgSend)(
mdl, @selector(compileWithQoS:options:error:), 21, @{}, &e);
if (!ok) {
printf(" Compile failed: %s\n", e ? [[e description] UTF8String] : "unknown");
return k;
}
ok = ((BOOL(*)(id,SEL,unsigned int,id,NSError**))objc_msgSend)(
mdl, @selector(loadWithQoS:options:error:), 21, @{}, &e);
if (!ok) {
printf(" Load failed: %s\n", e ? [[e description] UTF8String] : "unknown");
return k;
}
k.model = mdl;
k.ioIn = make_surface((size_t)ch * sp * 2);
k.ioOut = make_surface((size_t)ch * sp * 2);
k.tmpDir = td;
return k;
}
static void free_kernel(CompiledKernel *k) {
if (!k->model) return;
NSError *e = nil;
((BOOL(*)(id,SEL,unsigned int,NSError**))objc_msgSend)(
k->model, @selector(unloadWithQoS:error:), 21, &e);
if (k->ioIn) CFRelease(k->ioIn);
if (k->ioOut) CFRelease(k->ioOut);
}
#pragma mark - Main
int main(int argc, const char *argv[]) {
(void)argc; (void)argv;
@autoreleasepool {
mach_timebase_info(&g_tb);
printf("==============================================================\n");
printf(" ANE Experiments E-H: _ANEModel, Compiler, Chaining\n");
printf("==============================================================\n\n");
void *handle = dlopen(
"/System/Library/PrivateFrameworks/AppleNeuralEngine.framework/"
"AppleNeuralEngine", RTLD_NOW);
if (!handle) { printf("FATAL: dlopen ANE framework failed\n"); return 1; }
Class gAIO = NSClassFromString(@"_ANEIOSurfaceObject");
Class gAR = NSClassFromString(@"_ANERequest");
Class gBuf = NSClassFromString(@"_ANEBuffer");
Class gOutSets = NSClassFromString(@"_ANEIOSurfaceOutputSets");
Class gChain = NSClassFromString(@"_ANEChainingRequest");
id client = [NSClassFromString(@"_ANEClient")
performSelector:@selector(sharedConnection)];
printf("=== Compiling test kernels (64x32 FP16 conv) ===\n");
CompiledKernel k1 = compile_kernel(64, 32);
CompiledKernel k2 = compile_kernel(64, 32);
if (!k1.model || !k2.model) {
printf("FATAL: Kernel compilation failed\n");
return 1;
}
printf(" k1: hexId=%s\n tmpDir=%s\n",
[k1.hexId UTF8String], [k1.tmpDir UTF8String]);
printf(" k2: hexId=%s\n tmpDir=%s\n",
[k2.hexId UTF8String], [k2.tmpDir UTF8String]);
// =================================================================
// EXPERIMENT E: Load _ANEModel from compiled temp directory
// =================================================================
printf("\n------------------------------------------------------------\n");
printf(" EXPERIMENT E: Load _ANEModel from compiled temp dir\n");
printf("------------------------------------------------------------\n");
id diskModel1 = nil;
id diskModel2 = nil;
Class gANEModel = NSClassFromString(@"_ANEModel");
if (!gANEModel) {
printf(" FATAL: _ANEModel class not found\n");
} else {
printf("\n --- E.1: Full _ANEModel API surface ---\n");
dump_class("_ANEModel");
printf("\n --- E.2: Temp dir contents (k1) ---\n");
printf(" Path: %s\n", [k1.tmpDir UTF8String]);
list_dir_recursive(k1.tmpDir, 0);
printf("\n --- E.3: Factory method probing ---\n");
unsigned int mcount;
Method *cmethods = class_copyMethodList(
object_getClass(gANEModel), &mcount);
printf(" All _ANEModel class methods (%u):\n", mcount);
for (unsigned int i = 0; i < mcount; i++) {
printf(" + %s\n", sel_getName(method_getName(cmethods[i])));
}
free(cmethods);
NSURL *dirURL1 = [NSURL fileURLWithPath:k1.tmpDir];
NSString *hexKey1 = k1.hexId;
printf("\n URL: %s\n", [[dirURL1 absoluteString] UTF8String]);
printf(" key (hexId): %s\n", [hexKey1 UTF8String]);
// E.3a: modelAtURL:key:
printf("\n --- E.3a: modelAtURL:key: ---\n");
@try {
SEL sel = NSSelectorFromString(@"modelAtURL:key:");
if ([gANEModel respondsToSelector:sel]) {
diskModel1 = ((id(*)(Class,SEL,id,id))objc_msgSend)(
gANEModel, sel, dirURL1, hexKey1);
printf(" Result: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String] : "nil");
} else {
printf(" NOT available\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
// E.3b: modelAtURL:key:modelAttributes:
if (!diskModel1) {
printf("\n --- E.3b: modelAtURL:key:modelAttributes: ---\n");
@try {
SEL sel = NSSelectorFromString(
@"modelAtURL:key:modelAttributes:");
if ([gANEModel respondsToSelector:sel]) {
diskModel1 = ((id(*)(Class,SEL,id,id,id))objc_msgSend)(
gANEModel, sel, dirURL1, hexKey1, @{});
printf(" empty attrs: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String]
: "nil");
if (!diskModel1) {
diskModel1 = ((id(*)(Class,SEL,id,id,id))objc_msgSend)(
gANEModel, sel, dirURL1, hexKey1, nil);
printf(" nil attrs: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String]
: "nil");
}
} else {
printf(" NOT available\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
}
// E.3c: modelWithCacheURLIdentifier:
if (!diskModel1) {
printf("\n --- E.3c: modelWithCacheURLIdentifier: ---\n");
@try {
SEL sel = NSSelectorFromString(@"modelWithCacheURLIdentifier:");
if ([gANEModel respondsToSelector:sel]) {
diskModel1 = ((id(*)(Class,SEL,id))objc_msgSend)(
gANEModel, sel, hexKey1);
printf(" hexId: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String]
: "nil");
if (!diskModel1) {
diskModel1 = ((id(*)(Class,SEL,id))objc_msgSend)(
gANEModel, sel, k1.tmpDir);
printf(" tmpDir: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String]
: "nil");
}
} else {
printf(" NOT available\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
}
// E.3d: modelAtURLWithSourceURL:sourceURL:key:cacheURLIdentifier:
if (!diskModel1) {
printf("\n --- E.3d: modelAtURLWithSourceURL:... ---\n");
@try {
SEL sel = NSSelectorFromString(
@"modelAtURLWithSourceURL:sourceURL:key:cacheURLIdentifier:");
if ([gANEModel respondsToSelector:sel]) {
diskModel1 = ((id(*)(Class,SEL,id,id,id,id))objc_msgSend)(
gANEModel, sel, dirURL1, dirURL1, hexKey1, hexKey1);
printf(" Result: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String]
: "nil");
} else {
printf(" NOT available\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
}
// E.3e: alloc/init variants
if (!diskModel1) {
printf("\n --- E.3e: alloc/init variants ---\n");
unsigned int imcount;
Method *imethods = class_copyMethodList(gANEModel, &imcount);
printf(" Init-like instance methods:\n");
for (unsigned int i = 0; i < imcount; i++) {
const char *mname = sel_getName(method_getName(imethods[i]));
if (strstr(mname, "init") || strstr(mname, "Init")) {
printf(" - %s [%s]\n", mname,
method_getTypeEncoding(imethods[i]));
}
}
free(imethods);
@try {
SEL initSel = NSSelectorFromString(@"initWithURL:key:");
if ([gANEModel instancesRespondToSelector:initSel]) {
id obj = [gANEModel alloc];
diskModel1 = ((id(*)(id,SEL,id,id))objc_msgSend)(
obj, initSel, dirURL1, hexKey1);
printf(" initWithURL:key: %s\n",
diskModel1 ? [[diskModel1 description] UTF8String]
: "nil");
}
} @catch (NSException *ex) {
printf(" initWithURL:key: EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
// E.3f: Search for .hwx files
if (!diskModel1) {
printf("\n --- E.3f: Search for .hwx / .plist files ---\n");
NSFileManager *fm = [NSFileManager defaultManager];
NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath:k1.tmpDir];
NSString *file;
while ((file = [dirEnum nextObject])) {
NSString *ext = [file pathExtension];
if ([ext isEqualToString:@"hwx"] ||
[ext isEqualToString:@"plist"] ||
[ext isEqualToString:@"espresso"]) {
NSString *fp = [k1.tmpDir
stringByAppendingPathComponent:file];
NSDictionary *attrs = [fm attributesOfItemAtPath:fp
error:nil];
printf(" Found: %s (%llu bytes)\n",
[file UTF8String], [attrs fileSize]);
}
}
NSString *netPlist = [k1.tmpDir
stringByAppendingPathComponent:@"net.plist"];
if ([fm fileExistsAtPath:netPlist]) {
printf(" net.plist found! Reading...\n");
@try {
NSDictionary *plist = [NSDictionary
dictionaryWithContentsOfFile:netPlist];
if (plist) {
printf(" net.plist keys: %s\n",
[[[plist allKeys] description] UTF8String]);
} else {
NSData *raw = [NSData dataWithContentsOfFile:netPlist];
printf(" net.plist: binary (%lu bytes)\n",
(unsigned long)raw.length);
}
} @catch (NSException *ex) {
printf(" net.plist EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
}
// E.3g: Try constructing from programHandle
if (!diskModel1) {
printf("\n --- E.3g: programHandle-based construction ---\n");
@try {
id progHandle = [k1.model valueForKey:@"programHandle"];
printf(" k1 programHandle = %s\n",
progHandle ? [[progHandle description] UTF8String]
: "nil");
unsigned int mct;
Method *cls_m = class_copyMethodList(
object_getClass(gANEModel), &mct);
for (unsigned int i = 0; i < mct; i++) {
const char *mn = sel_getName(method_getName(cls_m[i]));
if (strstr(mn, "Handle") || strstr(mn, "handle") ||
strstr(mn, "program") || strstr(mn, "Program")) {
printf(" Relevant factory: +%s\n", mn);
}
}
free(cls_m);
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
}
// E.4: If loaded, query critical methods
if (diskModel1) {
printf("\n ======================================================\n");
printf(" _ANEModel LOADED SUCCESSFULLY!\n");
printf(" ======================================================\n");
printf("\n --- E.4a: All properties ---\n");
dump_all_properties(diskModel1, gANEModel);
printf("\n --- E.4b: getUUID ---\n");
@try {
SEL uuidSel = NSSelectorFromString(@"getUUID");
if ([diskModel1 respondsToSelector:uuidSel]) {
id uuid = ((id(*)(id,SEL))objc_msgSend)(
diskModel1, uuidSel);
printf(" getUUID: %s\n",
uuid ? [[uuid description] UTF8String] : "nil");
} else {
printf(" getUUID: NOT available\n");
}
} @catch (NSException *ex) {
printf(" getUUID EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
printf("\n --- E.4c: Symbol indices ---\n");
@try {
SEL inSel = NSSelectorFromString(
@"inputSymbolIndicesForProcedureIndex:");
if ([diskModel1 respondsToSelector:inSel]) {
id idx = ((id(*)(id,SEL,NSUInteger))objc_msgSend)(
diskModel1, inSel, (NSUInteger)0);
printf(" inputSymbolIndices(0): %s\n",
idx ? [[idx description] UTF8String] : "nil");
}
SEL outSel = NSSelectorFromString(
@"outputSymbolIndicesForProcedureIndex:");
if ([diskModel1 respondsToSelector:outSel]) {
id idx = ((id(*)(id,SEL,NSUInteger))objc_msgSend)(
diskModel1, outSel, (NSUInteger)0);
printf(" outputSymbolIndices(0): %s\n",
idx ? [[idx description] UTF8String] : "nil");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- E.4d: mapper ---\n");
@try {
id mapper = [diskModel1 valueForKey:@"mapper"];
printf(" mapper: %s\n",
mapper ? [[mapper description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- E.4e: program ---\n");
@try {
id prog = [diskModel1 valueForKey:@"program"];
printf(" program: %s\n",
prog ? [[prog description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
// E.4f: Copy programHandle + program from InMemoryModel
printf("\n --- E.4f: Populate _ANEModel from InMemoryModel ---\n");
@try {
id imProgHandle = [k1.model valueForKey:@"programHandle"];
id imProgram = [k1.model valueForKey:@"program"];
id imMapper = nil;
@try { imMapper = [k1.model valueForKey:@"mapper"]; }
@catch (NSException *ex) { (void)ex; }
printf(" InMemoryModel programHandle: %s\n",
imProgHandle ? [[imProgHandle description] UTF8String]
: "nil");
printf(" InMemoryModel program: %s\n",
imProgram ? [[imProgram description] UTF8String]
: "nil");
if (imProgHandle) {
uint64_t ph = [imProgHandle unsignedLongLongValue];
((void(*)(id,SEL,uint64_t))objc_msgSend)(
diskModel1,
@selector(setProgramHandle:), ph);
printf(" Set programHandle on _ANEModel: %llu\n", ph);
}
if (imProgram) {
((void(*)(id,SEL,id))objc_msgSend)(
diskModel1, @selector(setProgram:), imProgram);
printf(" Set program on _ANEModel\n");
}
// Verify
id newPH = [diskModel1 valueForKey:@"programHandle"];
id newProg = [diskModel1 valueForKey:@"program"];
printf(" _ANEModel programHandle now: %s\n",
newPH ? [[newPH description] UTF8String] : "nil");
printf(" _ANEModel program now: %s\n",
newProg ? [[newProg description] UTF8String] : "nil");
// Re-check symbol indices after populating
printf("\n Re-checking symbol indices...\n");
SEL inSel2 = NSSelectorFromString(
@"inputSymbolIndicesForProcedureIndex:");
if ([diskModel1 respondsToSelector:inSel2]) {
id idx = ((id(*)(id,SEL,unsigned int))objc_msgSend)(
diskModel1, inSel2, (unsigned int)0);
printf(" inputSymbolIndices(0): %s\n",
idx ? [[idx description] UTF8String] : "nil");
}
SEL outSel2 = NSSelectorFromString(
@"outputSymbolIndicesForProcedureIndex:");
if ([diskModel1 respondsToSelector:outSel2]) {
id idx = ((id(*)(id,SEL,unsigned int))objc_msgSend)(
diskModel1, outSel2, (unsigned int)0);
printf(" outputSymbolIndices(0): %s\n",
idx ? [[idx description] UTF8String] : "nil");
}
// Try getUUID again
id uuid2 = ((id(*)(id,SEL))objc_msgSend)(
diskModel1, NSSelectorFromString(@"getUUID"));
printf(" getUUID after populate: %s\n",
uuid2 ? [[uuid2 description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf(" Populate EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
// Also load k2 and populate it
printf("\n --- E.5: Loading k2 as _ANEModel ---\n");
NSURL *dirURL2 = [NSURL fileURLWithPath:k2.tmpDir];
@try {
SEL sel = NSSelectorFromString(@"modelAtURL:key:");
if ([gANEModel respondsToSelector:sel]) {
diskModel2 = ((id(*)(Class,SEL,id,id))objc_msgSend)(
gANEModel, sel, dirURL2, k2.hexId);
printf(" k2 _ANEModel: %s\n",
diskModel2 ? "LOADED" : "nil");
if (diskModel2) {
id k2ph = [k2.model valueForKey:@"programHandle"];
id k2prog = [k2.model valueForKey:@"program"];
if (k2ph) {
((void(*)(id,SEL,uint64_t))objc_msgSend)(
diskModel2, @selector(setProgramHandle:),
[k2ph unsignedLongLongValue]);
}
if (k2prog) {
((void(*)(id,SEL,id))objc_msgSend)(
diskModel2, @selector(setProgram:),
k2prog);
}
printf(" k2 populated with programHandle + program\n");
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
} else {
printf("\n _ANEModel could NOT be loaded via any factory.\n");
printf(" Proceeding to Experiment E2 (ANECompiler).\n");
}
}
// =================================================================
// EXPERIMENT E2: ANECompiler probing
// =================================================================
printf("\n------------------------------------------------------------\n");
printf(" EXPERIMENT E2: ANECompiler / model.hwx generation\n");
printf("------------------------------------------------------------\n");
{
printf("\n --- E2.1: Looking for ANECompiler ---\n");
const char *compiler_paths[] = {
"/System/Library/PrivateFrameworks/"
"ANECompiler.framework/ANECompiler",
"/System/Library/PrivateFrameworks/"
"ANECompiler.framework/Versions/Current/ANECompiler",
"/System/Library/Frameworks/"
"CoreML.framework/Versions/A/CoreML",
NULL
};
void *compilerHandle = NULL;
for (int i = 0; compiler_paths[i]; i++) {
compilerHandle = dlopen(compiler_paths[i], RTLD_NOW);
if (compilerHandle) {
printf(" Found: %s\n", compiler_paths[i]);
break;
} else {
printf(" Not at: %s\n", compiler_paths[i]);
}
}
printf("\n --- E2.2: Compiler class search ---\n");
const char *compiler_classes[] = {
"ANECompiler", "_ANECompiler", "ANECompilerService",
"_ANECompilerService", "ANECompileOptions",
"_ANECompileOptions", "ANEModelCompiler",
"_ANEModelCompiler", "ANECCompiler", NULL
};
for (int i = 0; compiler_classes[i]; i++) {
Class cls = NSClassFromString(
[NSString stringWithUTF8String:compiler_classes[i]]);
if (cls) {
printf(" FOUND: %s\n", compiler_classes[i]);
dump_class(compiler_classes[i]);
} else {
printf(" %s: not found\n", compiler_classes[i]);
}
}
printf("\n --- E2.3: Compile with debug_mask ---\n");
@try {
Class gD = NSClassFromString(@"_ANEInMemoryModelDescriptor");
Class gI = NSClassFromString(@"_ANEInMemoryModel");
int dbg_ch = 32, dbg_ws = dbg_ch * dbg_ch * 2;
int dbg_tot = 128 + dbg_ws;
uint8_t *dbg_blob = (uint8_t *)calloc((size_t)dbg_tot, 1);
dbg_blob[0] = 1; dbg_blob[4] = 2;
dbg_blob[64] = 0xEF; dbg_blob[65] = 0xBE;
dbg_blob[66] = 0xAD; dbg_blob[67] = 0xDE;
dbg_blob[68] = 1;
*(uint32_t *)(dbg_blob + 72) = (uint32_t)dbg_ws;
*(uint32_t *)(dbg_blob + 80) = 128;
_Float16 *dbg_wp = (_Float16 *)(dbg_blob + 128);
for (int i = 0; i < dbg_ch; i++)
dbg_wp[i * dbg_ch + i] = (_Float16)1.0f;
NSData *wdata = [NSData dataWithBytesNoCopy:dbg_blob
length:(NSUInteger)dbg_tot freeWhenDone:YES];
NSString *mil = gen_conv_mil(32, 16);
NSData *md = [mil dataUsingEncoding:NSUTF8StringEncoding];
id desc = ((id(*)(Class,SEL,id,id,id))objc_msgSend)(gD,
@selector(modelWithMILText:weights:optionsPlist:),
md,
@{@"@model_path/weights/weight.bin":
@{@"offset":@0, @"data":wdata}},
nil);
id mdl = ((id(*)(Class,SEL,id))objc_msgSend)(gI,
@selector(inMemoryModelWithDescriptor:), desc);
id hx = ((id(*)(id,SEL))objc_msgSend)(mdl,
@selector(hexStringIdentifier));
NSString *td = [NSTemporaryDirectory()
stringByAppendingPathComponent:
[NSString stringWithFormat:@"debug_%@", hx]];
NSFileManager *fm = [NSFileManager defaultManager];
[fm createDirectoryAtPath:
[td stringByAppendingPathComponent:@"weights"]
withIntermediateDirectories:YES attributes:nil error:nil];
[md writeToFile:[td stringByAppendingPathComponent:@"model.mil"]
atomically:YES];
[wdata writeToFile:
[td stringByAppendingPathComponent:@"weights/weight.bin"]
atomically:YES];
NSDictionary *debugOpts = @{
@"debug_mask": @(INT_MAX),
@"ANEDebugMask": @(INT_MAX),
@"ane_debug_mask": @(INT_MAX),
};
printf(" Compiling with debug_mask=%d...\n", INT_MAX);
NSError *e = nil;
BOOL ok = ((BOOL(*)(id,SEL,unsigned int,id,NSError**))
objc_msgSend)(mdl,
@selector(compileWithQoS:options:error:),
21, debugOpts, &e);
printf(" Compile: %s\n", ok ? "SUCCESS" : "FAILED");
if (!ok && e)
printf(" Error: %s\n", [[e description] UTF8String]);
if (ok) {
printf(" Temp dir after debug compile:\n");
list_dir_recursive(td, 0);
NSDirectoryEnumerator *de = [fm enumeratorAtPath:td];
NSString *f;
int hwxCount = 0;
while ((f = [de nextObject])) {
if ([[f pathExtension] isEqualToString:@"hwx"])
hwxCount++;
}
if (hwxCount > 0)
printf(" Found %d .hwx file(s)!\n", hwxCount);
if (gANEModel && !diskModel1) {
@try {
SEL sel = NSSelectorFromString(@"modelAtURL:key:");
if ([gANEModel respondsToSelector:sel]) {
NSURL *dURL = [NSURL fileURLWithPath:td];
diskModel1 = ((id(*)(Class,SEL,id,id))
objc_msgSend)(gANEModel, sel, dURL, hx);
printf(" modelAtURL:key: on debug dir: %s\n",
diskModel1
? [[diskModel1 description] UTF8String]
: "nil");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
}
[fm removeItemAtPath:td error:nil];
} @catch (NSException *ex) {
printf(" E2.3 EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- E2.4: ane_compiler_service search ---\n");
{
NSFileManager *fm = [NSFileManager defaultManager];
const char *svc_paths[] = {
"/usr/libexec/ane_compiler_service",
"/System/Library/CoreServices/ane_compiler_service",
"/System/Library/PrivateFrameworks/"
"ANECompiler.framework/ane_compiler_service",
NULL
};
for (int i = 0; svc_paths[i]; i++) {
NSString *p = [NSString stringWithUTF8String:svc_paths[i]];
printf(" %s: %s\n", svc_paths[i],
[fm fileExistsAtPath:p] ? "FOUND" : "not found");
}
}
printf("\n --- E2.5: _ANEInMemoryModel compilation methods ---\n");
{
Class gI = NSClassFromString(@"_ANEInMemoryModel");
unsigned int mc;
Method *ms = class_copyMethodList(gI, &mc);
for (unsigned int i = 0; i < mc; i++) {
const char *mn = sel_getName(method_getName(ms[i]));
if (strstr(mn, "compile") || strstr(mn, "Compile") ||
strstr(mn, "hwx") || strstr(mn, "HWX") ||
strstr(mn, "binary") || strstr(mn, "Binary") ||
strstr(mn, "save") || strstr(mn, "Save") ||
strstr(mn, "export") || strstr(mn, "Export") ||
strstr(mn, "path") || strstr(mn, "Path") ||
strstr(mn, "url") || strstr(mn, "URL") ||
strstr(mn, "temp") || strstr(mn, "Temp") ||
strstr(mn, "cache") || strstr(mn, "Cache")) {
printf(" - %s [%s]\n", mn,
method_getTypeEncoding(ms[i]));
}
}
free(ms);
}
}
// =================================================================
// EXPERIMENT F: Full chaining pipeline with _ANEModel
// =================================================================
printf("\n------------------------------------------------------------\n");
printf(" EXPERIMENT F: Full chaining pipeline\n");
printf("------------------------------------------------------------\n");
{
if (!diskModel1) {
printf(" SKIPPED: _ANEModel not loaded\n");
printf(" Fallback: prepareChainingWithModel on InMemoryModel\n\n");
@try {
id ioObj1 = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioIn);
id buf1 = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf,
@selector(bufferWithIOSurfaceObject:symbolIndex:source:),
ioObj1, @0, (long long)0);
id outIO1 = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioOut);
id outBuf1 = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf,
@selector(bufferWithIOSurfaceObject:symbolIndex:source:),
outIO1, @0, (long long)1);
IOSurfaceRef statsSurf = make_surface(64);
id outSet = ((id(*)(Class,SEL,IOSurfaceRef,id))objc_msgSend)(
gOutSets,
@selector(objectWithstatsSurRef:outputBuffer:),
statsSurf, @[outBuf1]);
id chainReq = ((id(*)(Class,SEL,id,id,id,id,id,id,id,id,id))
objc_msgSend)(gChain,
@selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:procedureIndex:
signalEvents:transactionHandle:fwEnqueueDelay:
memoryPoolId:),
@[buf1], @[outSet], @(-1), @(-1), @0,
@[], @0, @0, @0);
if (chainReq) {
BOOL valid = ((BOOL(*)(id,SEL))objc_msgSend)(
chainReq, @selector(validate));
printf(" validate: %s\n", valid ? "YES" : "NO");
NSError *prepErr = nil;
BOOL prepOk = ((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(client,
@selector(prepareChainingWithModel:options:
chainingReq:qos:error:),
k1.model, @{}, chainReq, (unsigned int)21,
&prepErr);
printf(" prepareChainingWithModel (InMemory): %s\n",
prepOk ? "YES" : "NO");
if (!prepOk && prepErr)
printf(" Error: %s\n",
[[prepErr description] UTF8String]);
}
CFRelease(statsSurf);
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
printf(" (Expected: getUUID unrecognized selector)\n");
}
} else {
printf(" Using _ANEModel for chaining!\n\n");
NSArray *inputSymbols = nil;
NSArray *outputSymbols = nil;
@try {
SEL inSel = NSSelectorFromString(
@"inputSymbolIndicesForProcedureIndex:");
inputSymbols = ((id(*)(id,SEL,NSUInteger))objc_msgSend)(
diskModel1, inSel, (NSUInteger)0);
SEL outSel = NSSelectorFromString(
@"outputSymbolIndicesForProcedureIndex:");
outputSymbols = ((id(*)(id,SEL,NSUInteger))objc_msgSend)(
diskModel1, outSel, (NSUInteger)0);
printf(" Input symbols: %s\n",
inputSymbols ? [[inputSymbols description] UTF8String]
: "nil");
printf(" Output symbols: %s\n",
outputSymbols ? [[outputSymbols description] UTF8String]
: "nil");
} @catch (NSException *ex) {
printf(" Symbol query EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
@try {
NSNumber *inSymIdx = (inputSymbols.count > 0)
? inputSymbols[0] : @0;
NSNumber *outSymIdx = (outputSymbols.count > 0)
? outputSymbols[0] : @0;
id ioObj1 = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioIn);
id inBuf = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf,
@selector(bufferWithIOSurfaceObject:symbolIndex:source:),
ioObj1, inSymIdx, (long long)0);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioOut);
id outBuf = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf,
@selector(bufferWithIOSurfaceObject:symbolIndex:source:),
outIO, outSymIdx, (long long)1);
IOSurfaceRef statsSurf = make_surface(64);
id outSet = ((id(*)(Class,SEL,IOSurfaceRef,id))objc_msgSend)(
gOutSets,
@selector(objectWithstatsSurRef:outputBuffer:),
statsSurf, @[outBuf]);
id chainReq = ((id(*)(Class,SEL,id,id,id,id,id,id,id,id,id))
objc_msgSend)(gChain,
@selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:procedureIndex:
signalEvents:transactionHandle:fwEnqueueDelay:
memoryPoolId:),
@[inBuf], @[outSet], @(-1), @(-1), @0,
@[], @0, @0, @0);
if (chainReq) {
BOOL valid = ((BOOL(*)(id,SEL))objc_msgSend)(
chainReq, @selector(validate));
printf(" validate: %s\n", valid ? "YES" : "NO");
NSError *prepErr = nil;
BOOL prepOk = ((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(client,
@selector(prepareChainingWithModel:options:
chainingReq:qos:error:),
diskModel1, @{}, chainReq, (unsigned int)21,
&prepErr);
printf(" prepareChainingWithModel: %s\n",
prepOk ? "YES" : "NO");
if (!prepOk && prepErr)
printf(" Error: %s\n",
[[prepErr description] UTF8String]);
if (prepOk) {
printf(" CHAINING PREPARE SUCCEEDED!\n");
@try {
NSError *enqErr = nil;
BOOL enqOk = ((BOOL(*)(id,SEL,id,id,id,
unsigned int,NSError**))objc_msgSend)(
client,
@selector(enqueueSetsWithModel:outputSet:
options:qos:error:),
diskModel1, outSet, @{},
(unsigned int)21, &enqErr);
printf(" enqueueSets: %s\n",
enqOk ? "YES" : "NO");
if (!enqOk && enqErr)
printf(" Error: %s\n",
[[enqErr description] UTF8String]);
} @catch (NSException *ex) {
printf(" enqueueSets EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
@try {
NSError *rdyErr = nil;
BOOL rdyOk = ((BOOL(*)(id,SEL,id,id,id,
unsigned int,NSError**))objc_msgSend)(
client,
@selector(buffersReadyWithModel:
inputBuffers:options:qos:error:),
diskModel1, @[inBuf], @{},
(unsigned int)21, &rdyErr);
printf(" buffersReady: %s\n",
rdyOk ? "YES" : "NO");
if (!rdyOk && rdyErr)
printf(" Error: %s\n",
[[rdyErr description] UTF8String]);
} @catch (NSException *ex) {
printf(" buffersReady EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
// Benchmark sequential baseline
printf("\n --- Benchmark ---\n");
id wI = ((id(*)(Class,SEL,IOSurfaceRef))
objc_msgSend)(gAIO,
@selector(objectWithIOSurface:), k1.ioIn);
id wO = ((id(*)(Class,SEL,IOSurfaceRef))
objc_msgSend)(gAIO,
@selector(objectWithIOSurface:), k1.ioOut);
id req = ((id(*)(Class,SEL,id,id,id,id,id,id,id))
objc_msgSend)(gAR,
@selector(requestWithInputs:inputIndices:
outputs:outputIndices:weightsBuffer:
perfStats:procedureIndex:),
@[wI], @[@0], @[wO], @[@0], nil, nil, @0);
int iters = 100;
NSError *seqErr = nil;
uint64_t t0 = mach_absolute_time();
for (int i = 0; i < iters; i++) {
((BOOL(*)(id,SEL,unsigned int,id,id,
NSError**))objc_msgSend)(k1.model,
@selector(evaluateWithQoS:options:
request:error:),
21, @{}, req, &seqErr);
}
double seqMs = tb_ms(
mach_absolute_time() - t0) / iters;
printf(" Sequential: %.3f ms/kernel\n", seqMs);
}
}
CFRelease(statsSurf);
} @catch (NSException *ex) {
printf(" Chaining EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
}
// =================================================================
// EXPERIMENT G: IOSurfaceSharedEvent / hardware fences
// =================================================================
printf("\n------------------------------------------------------------\n");
printf(" EXPERIMENT G: IOSurfaceSharedEvent / hardware fences\n");
printf("------------------------------------------------------------\n");
{
Class gSigEvent = NSClassFromString(@"_ANESharedSignalEvent");
Class gWaitEvent = NSClassFromString(@"_ANESharedWaitEvent");
printf("\n --- G.1: Event class API ---\n");
if (gSigEvent) dump_class("_ANESharedSignalEvent");
else printf(" _ANESharedSignalEvent: NOT FOUND\n");
if (gWaitEvent) dump_class("_ANESharedWaitEvent");
else printf(" _ANESharedWaitEvent: NOT FOUND\n");
printf("\n --- G.2: MTLSharedEvent via Metal ---\n");
@try {
void *metalH = dlopen(
"/System/Library/Frameworks/Metal.framework/Metal",
RTLD_NOW);
if (metalH) {
id (*createDev)(void) = dlsym(metalH,
"MTLCreateSystemDefaultDevice");
if (createDev) {
id dev = createDev();
printf(" MTLDevice: %s\n",
dev ? [[dev description] UTF8String] : "nil");
if (dev) {
SEL newEvt = NSSelectorFromString(
@"newSharedEvent");
if ([dev respondsToSelector:newEvt]) {
id shEvt = ((id(*)(id,SEL))objc_msgSend)(
dev, newEvt);
printf(" MTLSharedEvent: %s\n",
shEvt ? [[shEvt description] UTF8String]
: "nil");
if (shEvt && gSigEvent) {
printf("\n --- G.3: _ANESharedSignalEvent "
"with MTLSharedEvent ---\n");
// Factory: (Q16 I24 q28 @36) =
// (uint64_t, unsigned int, long long, id)
@try {
SEL sigSel = NSSelectorFromString(
@"signalEventWithValue:symbolIndex:"
"eventType:sharedEvent:");
if ([gSigEvent respondsToSelector:sigSel]) {
for (int et = 0; et <= 2; et++) {
id se = ((id(*)(Class,SEL,
uint64_t,unsigned int,
long long,id))
objc_msgSend)(gSigEvent,
sigSel, (uint64_t)1,
(unsigned int)0,
(long long)et, shEvt);
printf(" eventType=%d: %s\n",
et,
se ? [[se description]
UTF8String] : "nil");
if (se) {
dump_all_properties(
se, gSigEvent);
}
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
if (shEvt && gWaitEvent) {
printf("\n --- G.4: _ANESharedWaitEvent "
"with MTLSharedEvent ---\n");
// Factory: waitEventWithValue:sharedEvent:
// (Q16 @24) = (uint64_t, id)
// Factory: waitEventWithValue:sharedEvent:eventType:
// (Q16 @24 Q32) = (uint64_t, id, uint64_t)
@try {
SEL wSel = NSSelectorFromString(
@"waitEventWithValue:sharedEvent:");
if ([gWaitEvent respondsToSelector:wSel]) {
id we = ((id(*)(Class,SEL,
uint64_t,id))
objc_msgSend)(gWaitEvent,
wSel, (uint64_t)1, shEvt);
printf(" waitEvent(2-param): %s\n",
we ? [[we description]
UTF8String] : "nil");
if (we)
dump_all_properties(
we, gWaitEvent);
}
} @catch (NSException *ex) {
printf(" 2-param EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
@try {
SEL wSel3 = NSSelectorFromString(
@"waitEventWithValue:"
"sharedEvent:eventType:");
if ([gWaitEvent respondsToSelector:wSel3]) {
id we = ((id(*)(Class,SEL,
uint64_t,id,uint64_t))
objc_msgSend)(gWaitEvent,
wSel3, (uint64_t)1, shEvt,
(uint64_t)0);
printf(" waitEvent(3-param): %s\n",
we ? [[we description]
UTF8String] : "nil");
if (we)
dump_all_properties(
we, gWaitEvent);
}
} @catch (NSException *ex) {
printf(" 3-param EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
}
}
}
}
} @catch (NSException *ex) {
printf(" Metal EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- G.5: IOSurfaceSharedEventCreate ---\n");
@try {
void *iosH = dlopen(
"/System/Library/Frameworks/"
"IOSurface.framework/IOSurface", RTLD_NOW);
if (iosH) {
typedef id (*CreateFunc)(void);
CreateFunc fn = dlsym(iosH, "IOSurfaceSharedEventCreate");
if (fn) {
id iosEvt = fn();
printf(" IOSurfaceSharedEventCreate: %s\n",
iosEvt ? [[iosEvt description] UTF8String]
: "nil");
// Try using IOSurfaceSharedEvent with signal/wait
if (iosEvt && gSigEvent) {
printf("\n G.5b: SignalEvent with IOSurfaceSharedEvent\n");
@try {
SEL sigSel = NSSelectorFromString(
@"signalEventWithValue:symbolIndex:"
"eventType:sharedEvent:");
id se = ((id(*)(Class,SEL,uint64_t,
unsigned int,long long,id))
objc_msgSend)(gSigEvent, sigSel,
(uint64_t)1, (unsigned int)0,
(long long)0, iosEvt);
printf(" signalEvent: %s\n",
se ? [[se description] UTF8String]
: "nil");
if (se) dump_all_properties(se, gSigEvent);
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
if (iosEvt && gWaitEvent) {
printf("\n G.5c: WaitEvent with IOSurfaceSharedEvent\n");
@try {
SEL wSel = NSSelectorFromString(
@"waitEventWithValue:sharedEvent:");
id we = ((id(*)(Class,SEL,uint64_t,id))
objc_msgSend)(gWaitEvent, wSel,
(uint64_t)1, iosEvt);
printf(" waitEvent: %s\n",
we ? [[we description] UTF8String]
: "nil");
if (we) dump_all_properties(we, gWaitEvent);
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
} else {
printf(" IOSurfaceSharedEventCreate: not found\n");
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
}
// =================================================================
// EXPERIMENT H: Alternative chaining preparation
// =================================================================
printf("\n------------------------------------------------------------\n");
printf(" EXPERIMENT H: Alternative chaining preparation\n");
printf("------------------------------------------------------------\n");
{
printf("\n --- H.1: _ANEClient chaining methods ---\n");
Class clientCls = NSClassFromString(@"_ANEClient");
if (clientCls) {
unsigned int mc;
Method *ms = class_copyMethodList(clientCls, &mc);
for (unsigned int i = 0; i < mc; i++) {
const char *mn = sel_getName(method_getName(ms[i]));
if (strstr(mn, "chain") || strstr(mn, "Chain") ||
strstr(mn, "prepare") || strstr(mn, "Prepare") ||
strstr(mn, "enqueue") || strstr(mn, "Enqueue") ||
strstr(mn, "buffer") || strstr(mn, "Buffer") ||
strstr(mn, "ready") || strstr(mn, "Ready") ||
strstr(mn, "pipeline") || strstr(mn, "Pipeline") ||
strstr(mn, "batch") || strstr(mn, "Batch") ||
strstr(mn, "async") || strstr(mn, "Async")) {
printf(" - %s [%s]\n", mn,
method_getTypeEncoding(ms[i]));
}
}
free(ms);
printf("\n --- H.2: doPrepareChainingWithModel ---\n");
SEL doPrep = NSSelectorFromString(
@"doPrepareChainingWithModel:options:"
"chainingReq:qos:error:");
if ([client respondsToSelector:doPrep]) {
printf(" doPrepareChainingWithModel EXISTS\n");
@try {
id ioObj = ((id(*)(Class,SEL,IOSurfaceRef))
objc_msgSend)(gAIO,
@selector(objectWithIOSurface:), k1.ioIn);
id buf = ((id(*)(Class,SEL,id,id,long long))
objc_msgSend)(gBuf,
@selector(bufferWithIOSurfaceObject:
symbolIndex:source:),
ioObj, @0, (long long)0);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))
objc_msgSend)(gAIO,
@selector(objectWithIOSurface:), k1.ioOut);
id outBuf = ((id(*)(Class,SEL,id,id,long long))
objc_msgSend)(gBuf,
@selector(bufferWithIOSurfaceObject:
symbolIndex:source:),
outIO, @0, (long long)1);
IOSurfaceRef ss = make_surface(64);
id os = ((id(*)(Class,SEL,IOSurfaceRef,id))
objc_msgSend)(gOutSets,
@selector(objectWithstatsSurRef:outputBuffer:),
ss, @[outBuf]);
id cr = ((id(*)(Class,SEL,id,id,id,id,id,id,id,id,id))
objc_msgSend)(gChain,
@selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:
procedureIndex:signalEvents:
transactionHandle:fwEnqueueDelay:
memoryPoolId:),
@[buf], @[os], @(-1), @(-1), @0,
@[], @0, @0, @0);
NSError *err = nil;
printf(" With _ANEInMemoryModel...\n");
BOOL ok = ((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(client, doPrep,
k1.model, @{}, cr, (unsigned int)21, &err);
printf(" Result: %s\n", ok ? "YES" : "NO");
if (!ok && err)
printf(" Error: %s\n",
[[err description] UTF8String]);
CFRelease(ss);
} @catch (NSException *ex) {
printf(" InMemory EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
if (diskModel1) {
@try {
id ioObj = ((id(*)(Class,SEL,IOSurfaceRef))
objc_msgSend)(gAIO,
@selector(objectWithIOSurface:), k1.ioIn);
id buf = ((id(*)(Class,SEL,id,id,long long))
objc_msgSend)(gBuf,
@selector(bufferWithIOSurfaceObject:
symbolIndex:source:),
ioObj, @0, (long long)0);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))
objc_msgSend)(gAIO,
@selector(objectWithIOSurface:), k1.ioOut);
id outBuf = ((id(*)(Class,SEL,id,id,long long))
objc_msgSend)(gBuf,
@selector(bufferWithIOSurfaceObject:
symbolIndex:source:),
outIO, @0, (long long)1);
IOSurfaceRef ss = make_surface(64);
id os = ((id(*)(Class,SEL,IOSurfaceRef,id))
objc_msgSend)(gOutSets,
@selector(objectWithstatsSurRef:outputBuffer:),
ss, @[outBuf]);
id cr = ((id(*)(Class,SEL,id,id,id,id,id,id,id,id,id))
objc_msgSend)(gChain,
@selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:
procedureIndex:signalEvents:
transactionHandle:fwEnqueueDelay:
memoryPoolId:),
@[buf], @[os], @(-1), @(-1), @0,
@[], @0, @0, @0);
NSError *err = nil;
printf(" With _ANEModel...\n");
BOOL ok = ((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(client, doPrep,
diskModel1, @{}, cr, (unsigned int)21, &err);
printf(" Result: %s\n", ok ? "YES" : "NO");
if (!ok && err)
printf(" Error: %s\n",
[[err description] UTF8String]);
CFRelease(ss);
} @catch (NSException *ex) {
printf(" ANEModel EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
} else {
printf(" NOT available\n");
}
printf("\n --- H.3: All _ANEClient methods ---\n");
unsigned int allC;
Method *allM = class_copyMethodList(clientCls, &allC);
printf(" Total: %u\n", allC);
for (unsigned int i = 0; i < allC; i++) {
printf(" - %s\n",
sel_getName(method_getName(allM[i])));
}
free(allM);
}
}
// =================================================================
// Experiment K: ChainingRequest Factory Type Encoding Analysis
// =================================================================
printf("\n==============================================================\n");
printf(" Experiment K: Type Encoding Analysis\n");
printf("==============================================================\n\n");
{
Class clientCls = object_getClass(client);
SEL chainFactorySel = @selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:procedureIndex:
signalEvents:transactionHandle:fwEnqueueDelay:memoryPoolId:);
Method chainFactory = class_getClassMethod(gChain, chainFactorySel);
if (chainFactory) {
const char *enc = method_getTypeEncoding(chainFactory);
printf(" ChainingRequest factory encoding: %s\n", enc ? enc : "nil");
if (enc) {
const char *paramNames[] = {
"return", "self", "_cmd",
"inputs", "outputSets", "lbInputSymbolId",
"lbOutputSymbolId", "procedureIndex", "signalEvents",
"transactionHandle", "fwEnqueueDelay", "memoryPoolId"
};
unsigned int nargs = method_getNumberOfArguments(chainFactory);
printf(" Number of arguments: %u\n", nargs);
for (unsigned int i = 0; i < nargs && i < 12; i++) {
char argType[64] = {0};
method_getArgumentType(chainFactory, i, argType, sizeof(argType));
printf(" arg[%u] %-20s = %s", i, paramNames[i], argType);
if (argType[0] == '@') printf(" (id/object)");
else if (argType[0] == 'q') printf(" (int64_t)");
else if (argType[0] == 'Q') printf(" (uint64_t)");
else if (argType[0] == 'i') printf(" (int32_t)");
else if (argType[0] == 'I') printf(" (uint32_t)");
else if (argType[0] == 'B') printf(" (BOOL)");
else if (argType[0] == 'v') printf(" (void)");
else if (argType[0] == ':') printf(" (SEL)");
printf("\n");
}
}
} else {
printf(" ChainingRequest factory: NOT FOUND\n");
}
SEL prepSel = @selector(prepareChainingWithModel:options:
chainingReq:qos:error:);
Method prepMethod = class_getInstanceMethod(clientCls, prepSel);
if (!prepMethod)
prepMethod = class_getInstanceMethod(
NSClassFromString(@"_ANEClient"), prepSel);
if (prepMethod) {
const char *enc = method_getTypeEncoding(prepMethod);
printf("\n prepareChainingWithModel encoding: %s\n",
enc ? enc : "nil");
if (enc) {
const char *pNames[] = {
"return", "self", "_cmd",
"model", "options", "chainingReq", "qos", "error"
};
unsigned int nargs = method_getNumberOfArguments(prepMethod);
printf(" Number of arguments: %u\n", nargs);
for (unsigned int i = 0; i < nargs && i < 8; i++) {
char argType[64] = {0};
method_getArgumentType(prepMethod, i, argType, sizeof(argType));
printf(" arg[%u] %-15s = %s", i, pNames[i], argType);
if (argType[0] == '@') printf(" (id/object)");
else if (argType[0] == 'q') printf(" (int64_t)");
else if (argType[0] == 'Q') printf(" (uint64_t)");
else if (argType[0] == 'I') printf(" (uint32_t)");
else if (argType[0] == 'B') printf(" (BOOL)");
printf("\n");
}
}
} else {
printf("\n prepareChainingWithModel: NOT FOUND\n");
}
SEL doPrepSel = NSSelectorFromString(
@"doPrepareChainingWithModel:options:chainingReq:qos:error:");
Method doPrepMethod = class_getInstanceMethod(
NSClassFromString(@"_ANEClient"), doPrepSel);
if (doPrepMethod) {
const char *enc = method_getTypeEncoding(doPrepMethod);
printf("\n doPrepareChainingWithModel encoding: %s\n",
enc ? enc : "nil");
unsigned int nargs = method_getNumberOfArguments(doPrepMethod);
printf(" Number of arguments: %u\n", nargs);
for (unsigned int i = 0; i < nargs; i++) {
char argType[64] = {0};
method_getArgumentType(doPrepMethod, i, argType, sizeof(argType));
printf(" arg[%u] = %s\n", i, argType);
}
}
printf("\n --- K.2: All _ANEChainingRequest methods type encodings ---\n");
{
unsigned int mc;
Method *cms = class_copyMethodList(object_getClass(gChain), &mc);
printf(" Class methods (%u):\n", mc);
for (unsigned int i = 0; i < mc; i++) {
const char *name = sel_getName(method_getName(cms[i]));
const char *enc = method_getTypeEncoding(cms[i]);
printf(" + %s\n encoding: %s\n", name, enc ? enc : "?");
}
free(cms);
Method *ims = class_copyMethodList(gChain, &mc);
printf(" Instance methods (%u):\n", mc);
for (unsigned int i = 0; i < mc; i++) {
const char *name = sel_getName(method_getName(ims[i]));
const char *enc = method_getTypeEncoding(ims[i]);
printf(" - %s\n encoding: %s\n", name, enc ? enc : "?");
}
free(ims);
}
}
// =================================================================
// Experiment L: Array-Typed ChainingRequest Parameters
// =================================================================
printf("\n==============================================================\n");
printf(" Experiment L: Array-Typed ChainingRequest Parameters\n");
printf("==============================================================\n\n");
BOOL chainingPrepSuccess = NO;
id bestChainReq = nil;
id bestModel = diskModel1 ? diskModel1 : k1.model;
{
id ioObj = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioIn);
id inBuf = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf, @selector(bufferWithIOSurfaceObject:symbolIndex:source:),
ioObj, @0, (long long)0);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioOut);
id outBuf = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf, @selector(bufferWithIOSurfaceObject:symbolIndex:source:),
outIO, @0, (long long)1);
IOSurfaceRef statsSurf = make_surface(64);
id outSet = ((id(*)(Class,SEL,IOSurfaceRef,id))objc_msgSend)(
gOutSets, @selector(objectWithstatsSurRef:outputBuffer:),
statsSurf, @[outBuf]);
struct {
const char *label;
id lbIn; id lbOut; id procIdx;
} combos[] = {
{ "arrays @[@(-1)]", @[@(-1)], @[@(-1)], @[@0] },
{ "arrays @[@0]", @[@0], @[@0], @[@0] },
{ "empty arrays @[]", @[], @[], @[] },
{ "nil values", nil, nil, nil },
{ "original NSNumber", @(-1), @(-1), @0 },
};
int ncombos = sizeof(combos)/sizeof(combos[0]);
for (int ci = 0; ci < ncombos; ci++) {
printf(" --- L.%d: %s ---\n", ci+1, combos[ci].label);
@try {
id cr = ((id(*)(Class,SEL,id,id,id,id,id,id,id,id,id))
objc_msgSend)(gChain,
@selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:procedureIndex:
signalEvents:transactionHandle:fwEnqueueDelay:
memoryPoolId:),
@[inBuf], @[outSet],
combos[ci].lbIn, combos[ci].lbOut, combos[ci].procIdx,
@[], @0, @0, @0);
if (!cr) {
printf(" ChainingRequest: nil\n\n");
continue;
}
BOOL valid = ((BOOL(*)(id,SEL))objc_msgSend)(
cr, @selector(validate));
printf(" validate: %s\n", valid ? "YES" : "NO");
printf(" desc: %s\n",
[[cr description] UTF8String]);
@try {
NSError *prepErr = nil;
BOOL prepOk = ((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(client,
@selector(prepareChainingWithModel:options:
chainingReq:qos:error:),
bestModel, @{}, cr, (unsigned int)21, &prepErr);
printf(" prepareChainingWithModel: %s\n",
prepOk ? "YES" : "NO");
if (prepErr)
printf(" Error: %s\n",
[[prepErr description] UTF8String]);
if (prepOk || !prepErr) {
chainingPrepSuccess = prepOk;
bestChainReq = cr;
printf(" *** GOT PAST THE CRASH! ***\n");
}
} @catch (NSException *prepEx) {
printf(" prepare EXCEPTION: %s\n",
[[prepEx reason] UTF8String]);
}
} @catch (NSException *ex) {
printf(" factory EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
printf("\n");
}
CFRelease(statsSurf);
}
// =================================================================
// Experiment M: Load Model via _ANEClient
// =================================================================
printf("\n==============================================================\n");
printf(" Experiment M: Load Model via _ANEClient\n");
printf("==============================================================\n\n");
id fullyLoadedModel = nil;
{
if (!diskModel1) {
printf(" SKIPPED: no _ANEModel from Experiment E\n");
} else {
@try {
id st = [diskModel1 valueForKey:@"state"];
printf(" diskModel1 state before: %s\n",
st ? [[st description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf(" state query exception: %s\n",
[[ex reason] UTF8String]);
}
printf("\n --- M.1: compiledModelExistsFor: ---\n");
@try {
SEL existsSel = NSSelectorFromString(
@"compiledModelExistsFor:");
if ([client respondsToSelector:existsSel]) {
BOOL exists = ((BOOL(*)(id,SEL,id))objc_msgSend)(
client, existsSel, diskModel1);
printf(" compiledModelExistsFor: %s\n",
exists ? "YES" : "NO");
} else {
printf(" compiledModelExistsFor: NOT AVAILABLE\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- M.2: loadModel:options:qos:error: ---\n");
@try {
SEL loadSel = NSSelectorFromString(
@"loadModel:options:qos:error:");
if ([client respondsToSelector:loadSel]) {
NSError *loadErr = nil;
BOOL loadOk = ((BOOL(*)(id,SEL,id,id,unsigned int,
NSError**))objc_msgSend)(client, loadSel,
diskModel1, @{}, (unsigned int)21, &loadErr);
printf(" loadModel: %s\n", loadOk ? "YES" : "NO");
if (loadErr)
printf(" Error: %s\n",
[[loadErr description] UTF8String]);
if (loadOk) {
fullyLoadedModel = diskModel1;
@try {
SEL inSel = NSSelectorFromString(
@"inputSymbolIndicesForProcedureIndex:");
id inSyms = ((id(*)(id,SEL,NSUInteger))
objc_msgSend)(diskModel1, inSel, 0);
SEL outSel = NSSelectorFromString(
@"outputSymbolIndicesForProcedureIndex:");
id outSyms = ((id(*)(id,SEL,NSUInteger))
objc_msgSend)(diskModel1, outSel, 0);
printf(" After load - inputSymbols: %s\n",
inSyms ? [[inSyms description] UTF8String]
: "nil/empty");
printf(" After load - outputSymbols: %s\n",
outSyms ? [[outSyms description] UTF8String]
: "nil/empty");
} @catch (NSException *ex) {
printf(" Symbol query EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
} else {
printf(" loadModel: NOT AVAILABLE\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- M.3: compileModel:options:qos:error: ---\n");
@try {
SEL compileSel = NSSelectorFromString(
@"compileModel:options:qos:error:");
if ([client respondsToSelector:compileSel]) {
NSError *compErr = nil;
BOOL compOk = ((BOOL(*)(id,SEL,id,id,unsigned int,
NSError**))objc_msgSend)(client, compileSel,
diskModel1, @{}, (unsigned int)21, &compErr);
printf(" compileModel: %s\n", compOk ? "YES" : "NO");
if (compErr)
printf(" Error: %s\n",
[[compErr description] UTF8String]);
if (compOk) {
fullyLoadedModel = diskModel1;
@try {
id inSyms = ((id(*)(id,SEL,NSUInteger))
objc_msgSend)(diskModel1,
NSSelectorFromString(
@"inputSymbolIndicesForProcedureIndex:"),
0);
id outSyms = ((id(*)(id,SEL,NSUInteger))
objc_msgSend)(diskModel1,
NSSelectorFromString(
@"outputSymbolIndicesForProcedureIndex:"),
0);
printf(" After compile - inputSymbols: %s\n",
inSyms ? [[inSyms description] UTF8String]
: "nil/empty");
printf(" After compile - outputSymbols: %s\n",
outSyms ? [[outSyms description] UTF8String]
: "nil/empty");
} @catch (NSException *ex) {
printf(" Symbol query EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
} else {
printf(" compileModel: NOT AVAILABLE\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
@try {
id st = [diskModel1 valueForKey:@"state"];
printf("\n diskModel1 state after: %s\n",
st ? [[st description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf("\n state query exception: %s\n",
[[ex reason] UTF8String]);
}
}
}
// =================================================================
// Experiment N: IOSurface Mapping via _ANEProgramIOSurfacesMapper
// =================================================================
printf("\n==============================================================\n");
printf(" Experiment N: IOSurface Mapping\n");
printf("==============================================================\n\n");
{
Class gMapper = NSClassFromString(@"_ANEProgramIOSurfacesMapper");
if (!gMapper) {
printf(" _ANEProgramIOSurfacesMapper: NOT FOUND\n");
} else {
printf(" _ANEProgramIOSurfacesMapper: FOUND\n");
dump_class("_ANEProgramIOSurfacesMapper");
id progHandle = nil;
@try {
progHandle = [k1.model valueForKey:@"programHandle"];
} @catch (NSException *ex) {
printf(" programHandle exception: %s\n",
[[ex reason] UTF8String]);
}
printf("\n --- N.1: mapperWithProgramHandle: ---\n");
id mapper = nil;
if (progHandle) {
uint64_t ph = [progHandle unsignedLongLongValue];
printf(" programHandle = %llu\n", ph);
@try {
SEL mapperSel = NSSelectorFromString(
@"mapperWithProgramHandle:");
mapper = ((id(*)(Class,SEL,uint64_t))objc_msgSend)(
gMapper, mapperSel, ph);
printf(" mapper created: %s\n",
mapper ? [[mapper description] UTF8String]
: "nil");
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
id targetModel = diskModel1 ? diskModel1 : k1.model;
const char *modelType = diskModel1 ? "_ANEModel" : "InMemoryModel";
if (mapper) {
printf("\n --- N.2: mapIOSurfacesWithModel: (%s) ---\n",
modelType);
@try {
id ioObj = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioIn);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioOut);
id req = ((id(*)(Class,SEL,id,id,id,id,id,id,id))
objc_msgSend)(gAR,
@selector(requestWithInputs:inputIndices:
outputs:outputIndices:weightsBuffer:
perfStats:procedureIndex:),
@[ioObj], @[@0], @[outIO], @[@0], nil, nil, @0);
if (req) {
SEL mapSel = NSSelectorFromString(
@"mapIOSurfacesWithModel:request:"
"cacheInference:error:");
NSError *mapErr = nil;
BOOL mapOk = ((BOOL(*)(id,SEL,id,id,BOOL,
NSError**))objc_msgSend)(mapper, mapSel,
targetModel, req, NO, &mapErr);
printf(" mapIOSurfaces: %s\n",
mapOk ? "YES" : "NO");
if (mapErr)
printf(" Error: %s\n",
[[mapErr description] UTF8String]);
if (mapOk) {
dump_all_properties(mapper,
[mapper class]);
}
} else {
printf(" Request creation failed\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
printf("\n --- N.3: validateRequest:model: ---\n");
@try {
id ioObj = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioIn);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioOut);
id req = ((id(*)(Class,SEL,id,id,id,id,id,id,id))
objc_msgSend)(gAR,
@selector(requestWithInputs:inputIndices:
outputs:outputIndices:weightsBuffer:
perfStats:procedureIndex:),
@[ioObj], @[@0], @[outIO], @[@0], nil, nil, @0);
SEL valSel = NSSelectorFromString(
@"validateRequest:model:");
BOOL valOk = ((BOOL(*)(id,SEL,id,id))objc_msgSend)(
mapper, valSel, req, targetModel);
printf(" validateRequest: %s\n",
valOk ? "YES" : "NO");
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
if (diskModel1) {
printf("\n --- N.4: _ANEModel.mapper property ---\n");
@try {
id modelMapper = [diskModel1 valueForKey:@"mapper"];
printf(" model.mapper: %s\n",
modelMapper
? [[modelMapper description] UTF8String]
: "nil");
if (modelMapper) {
dump_all_properties(modelMapper,
[modelMapper class]);
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
}
}
// =================================================================
// Experiment O: Procedure Info Extraction
// =================================================================
printf("\n==============================================================\n");
printf(" Experiment O: Procedure Info Extraction\n");
printf("==============================================================\n\n");
{
id targetModel = diskModel1 ? diskModel1 : k1.model;
const char *modelType = diskModel1 ? "_ANEModel" : "InMemoryModel";
printf(" Using: %s\n", modelType);
printf("\n --- O.1: procedureInfoForProcedureIndex:0 ---\n");
@try {
SEL piSel = NSSelectorFromString(
@"procedureInfoForProcedureIndex:");
if ([targetModel respondsToSelector:piSel]) {
id pInfo = ((id(*)(id,SEL,NSUInteger))objc_msgSend)(
targetModel, piSel, (NSUInteger)0);
printf(" procedureInfo: %s\n",
pInfo ? [[pInfo description] UTF8String] : "nil");
if (pInfo) {
printf(" class: %s\n",
[NSStringFromClass([pInfo class]) UTF8String]);
dump_all_properties(pInfo, [pInfo class]);
}
} else {
printf(" procedureInfoForProcedureIndex: NOT AVAILABLE\n");
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- O.2: procedureCount ---\n");
@try {
SEL pcSel = NSSelectorFromString(@"procedureCount");
if ([targetModel respondsToSelector:pcSel]) {
NSUInteger pc = ((NSUInteger(*)(id,SEL))objc_msgSend)(
targetModel, pcSel);
printf(" procedureCount: %lu\n", (unsigned long)pc);
} else {
printf(" procedureCount: NOT AVAILABLE\n");
id pcVal = nil;
@try {
pcVal = [targetModel valueForKey:@"procedureCount"];
printf(" procedureCount (KVC): %s\n",
pcVal ? [[pcVal description] UTF8String] : "nil");
} @catch (NSException *ex2) {
printf(" procedureCount KVC: %s\n",
[[ex2 reason] UTF8String]);
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- O.3: modelAttributes ---\n");
@try {
id attrs = [targetModel valueForKey:@"modelAttributes"];
printf(" modelAttributes: %s\n",
attrs ? [[attrs description] UTF8String] : "nil");
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
printf("\n --- O.4: inputSymbolNames / outputSymbolNames ---\n");
@try {
SEL inNamesSel = NSSelectorFromString(@"inputSymbolNames");
if ([targetModel respondsToSelector:inNamesSel]) {
id names = ((id(*)(id,SEL))objc_msgSend)(
targetModel, inNamesSel);
printf(" inputSymbolNames: %s\n",
names ? [[names description] UTF8String] : "nil");
} else {
printf(" inputSymbolNames: NOT AVAILABLE as method\n");
@try {
id n = [targetModel valueForKey:@"inputSymbolNames"];
printf(" inputSymbolNames (KVC): %s\n",
n ? [[n description] UTF8String] : "nil");
} @catch (NSException *ex2) {
printf(" inputSymbolNames KVC: not available\n");
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
@try {
SEL outNamesSel = NSSelectorFromString(@"outputSymbolNames");
if ([targetModel respondsToSelector:outNamesSel]) {
id names = ((id(*)(id,SEL))objc_msgSend)(
targetModel, outNamesSel);
printf(" outputSymbolNames: %s\n",
names ? [[names description] UTF8String] : "nil");
} else {
printf(" outputSymbolNames: NOT AVAILABLE as method\n");
@try {
id n = [targetModel valueForKey:@"outputSymbolNames"];
printf(" outputSymbolNames (KVC): %s\n",
n ? [[n description] UTF8String] : "nil");
} @catch (NSException *ex2) {
printf(" outputSymbolNames KVC: not available\n");
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
if (diskModel1) {
printf("\n --- O.5: Full _ANEModel property dump ---\n");
dump_all_properties(diskModel1,
NSClassFromString(@"_ANEModel"));
}
}
// =================================================================
// Experiment P: Full Chaining Retry with Fixes
// =================================================================
printf("\n==============================================================\n");
printf(" Experiment P: Full Chaining Retry\n");
printf("==============================================================\n\n");
BOOL chainExecuted = NO;
{
void *metalHandle = dlopen(
"/System/Library/Frameworks/Metal.framework/Metal", RTLD_NOW);
(void)metalHandle;
id mtlDev = nil;
{
id (*createDev)(void) = (id(*)(void))
dlsym(RTLD_DEFAULT, "MTLCreateSystemDefaultDevice");
if (createDev) mtlDev = createDev();
}
id signalEvents = @[];
id shEvt = nil;
if (mtlDev) {
printf(" Metal device: %s\n",
[[mtlDev description] UTF8String]);
@try {
shEvt = ((id(*)(id,SEL))objc_msgSend)(
mtlDev, NSSelectorFromString(@"newSharedEvent"));
if (shEvt) {
Class gSigEvent = NSClassFromString(
@"_ANESharedSignalEvent");
if (gSigEvent) {
long long et = 0;
@try {
id etObj = [gSigEvent valueForKey:
@"ANESignalEventTypeMTLSharedEvent"];
if (etObj) et = [etObj longLongValue];
} @catch (NSException *ex) { (void)ex; }
SEL sigSel = NSSelectorFromString(
@"signalEventWithValue:symbolIndex:"
"eventType:sharedEvent:");
id se = ((id(*)(Class,SEL,uint64_t,unsigned int,
long long,id))objc_msgSend)(
gSigEvent, sigSel, (uint64_t)1,
(unsigned int)0, et, shEvt);
if (se)
signalEvents = @[se];
printf(" SignalEvent: %s\n",
se ? "created" : "nil");
}
}
} @catch (NSException *ex) {
printf(" SharedEvent EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
}
struct {
const char *label;
id model;
} modelCandidates[3];
int nCandidates = 0;
CompiledKernel k3 = compile_kernel(64, 32);
if (k3.model) {
NSURL *url = [NSURL fileURLWithPath:k3.tmpDir isDirectory:YES];
Class gANEModel = NSClassFromString(@"_ANEModel");
id freshDisk = ((id(*)(Class,SEL,id,id))objc_msgSend)(
gANEModel, @selector(modelAtURL:key:), url, k3.hexId);
if (freshDisk) {
id ph = [k3.model valueForKey:@"programHandle"];
id prog = [k3.model valueForKey:@"program"];
if (ph) ((void(*)(id,SEL,uint64_t))objc_msgSend)(
freshDisk, @selector(setProgramHandle:),
[ph unsignedLongLongValue]);
if (prog) ((void(*)(id,SEL,id))objc_msgSend)(
freshDisk, @selector(setProgram:), prog);
modelCandidates[nCandidates++] = (typeof(modelCandidates[0]))
{"fresh _ANEModel (state=1)", freshDisk};
}
modelCandidates[nCandidates++] = (typeof(modelCandidates[0]))
{"InMemoryModel (k3)", k3.model};
}
if (diskModel1) {
modelCandidates[nCandidates++] = (typeof(modelCandidates[0]))
{"populated _ANEModel (from E)", diskModel1};
}
for (int mi = 0; mi < nCandidates; mi++) {
printf("\n --- P.%d: %s ---\n", mi+1, modelCandidates[mi].label);
id chainModel = modelCandidates[mi].model;
printf(" class: %s\n",
[NSStringFromClass([chainModel class]) UTF8String]);
@try {
id st = [chainModel valueForKey:@"state"];
printf(" state: %s\n",
st ? [[st description] UTF8String] : "N/A");
} @catch (NSException *ex) { (void)ex; }
id ioObj1 = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioIn);
id inBuf = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf,
@selector(bufferWithIOSurfaceObject:symbolIndex:source:),
ioObj1, @0, (long long)0);
id outIO = ((id(*)(Class,SEL,IOSurfaceRef))objc_msgSend)(
gAIO, @selector(objectWithIOSurface:), k1.ioOut);
id outBuf = ((id(*)(Class,SEL,id,id,long long))objc_msgSend)(
gBuf,
@selector(bufferWithIOSurfaceObject:symbolIndex:source:),
outIO, @0, (long long)1);
IOSurfaceRef sSurf = make_surface(64);
id outSet = ((id(*)(Class,SEL,IOSurfaceRef,id))objc_msgSend)(
gOutSets, @selector(objectWithstatsSurRef:outputBuffer:),
sSurf, @[outBuf]);
@try {
id cr = ((id(*)(Class,SEL,id,id,id,id,id,id,id,id,id))
objc_msgSend)(gChain,
@selector(chainingRequestWithInputs:outputSets:
lbInputSymbolId:lbOutputSymbolId:procedureIndex:
signalEvents:transactionHandle:fwEnqueueDelay:
memoryPoolId:),
@[inBuf], @[outSet], nil, nil, nil,
signalEvents, @0, @0, @0);
if (!cr) {
printf(" ChainingRequest: nil\n");
CFRelease(sSurf);
continue;
}
BOOL valid = ((BOOL(*)(id,SEL))objc_msgSend)(
cr, @selector(validate));
printf(" validate: %s\n", valid ? "YES" : "NO");
NSError *prepErr = nil;
BOOL prepOk = ((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(client,
@selector(prepareChainingWithModel:options:
chainingReq:qos:error:),
chainModel, @{}, cr, (unsigned int)21, &prepErr);
printf(" prepare: %s\n", prepOk ? "YES" : "NO");
if (prepErr)
printf(" prepareError: %s\n",
[[prepErr description] UTF8String]);
if (prepOk) {
printf(" *** PREPARE SUCCEEDED! ***\n");
chainingPrepSuccess = YES;
chainExecuted = YES;
printf("\n --- enqueueSetsWithModel ---\n");
@try {
SEL eqSel = NSSelectorFromString(
@"enqueueSetsWithModel:outputSet:"
"options:qos:error:");
NSError *eqErr = nil;
BOOL eqOk = ((BOOL(*)(id,SEL,id,id,id,
unsigned int,NSError**))objc_msgSend)(
client, eqSel, chainModel, outSet, @{},
(unsigned int)21, &eqErr);
printf(" enqueueSets: %s\n",
eqOk ? "YES" : "NO");
if (eqErr)
printf(" Error: %s\n",
[[eqErr description] UTF8String]);
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
printf("\n --- buffersReadyWithModel ---\n");
@try {
SEL brSel = NSSelectorFromString(
@"buffersReadyWithModel:inputBuffers:"
"options:qos:error:");
NSError *brErr = nil;
BOOL brOk = ((BOOL(*)(id,SEL,id,id,id,
unsigned int,NSError**))objc_msgSend)(
client, brSel, chainModel, @[inBuf], @{},
(unsigned int)21, &brErr);
printf(" buffersReady: %s\n",
brOk ? "YES" : "NO");
if (brErr)
printf(" Error: %s\n",
[[brErr description] UTF8String]);
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n",
[[ex reason] UTF8String]);
}
printf("\n --- Benchmark ---\n");
uint64_t t0 = mach_absolute_time();
int niters = 50;
for (int i = 0; i < niters; i++) {
@try {
SEL brSel = NSSelectorFromString(
@"buffersReadyWithModel:inputBuffers:"
"options:qos:error:");
((BOOL(*)(id,SEL,id,id,id,unsigned int,
NSError**))objc_msgSend)(
client, brSel, chainModel, @[inBuf],
@{}, (unsigned int)21, nil);
} @catch (NSException *ex) {
if (i == 0)
printf(" Bench EXCEPTION: %s\n",
[[ex reason] UTF8String]);
break;
}
}
double elapsed = tb_ms(mach_absolute_time() - t0);
printf(" %d iters in %.3f ms (%.4f ms/iter)\n",
niters, elapsed, elapsed / niters);
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
CFRelease(sSurf);
}
printf("\n --- P.extra: Try with _ANEInputBuffersReady ---\n");
@try {
Class gIBR = NSClassFromString(@"_ANEInputBuffersReady");
if (gIBR) {
dump_class("_ANEInputBuffersReady");
SEL ibrSel = NSSelectorFromString(
@"inputBuffersWithProcedureIndex:inputBufferInfoIndex:"
"inputFreeValue:executionDelay:");
if (class_getClassMethod(gIBR, ibrSel)) {
Method m = class_getClassMethod(gIBR, ibrSel);
const char *enc = method_getTypeEncoding(m);
printf(" inputBuffersReady encoding: %s\n",
enc ? enc : "?");
unsigned int na = method_getNumberOfArguments(m);
printf(" args: %u\n", na);
for (unsigned int i = 0; i < na; i++) {
char at[64] = {0};
method_getArgumentType(m, i, at, sizeof(at));
printf(" [%u] = %s\n", i, at);
}
}
}
Class gOSE = NSClassFromString(@"_ANEOutputSetEnqueue");
if (gOSE) {
dump_class("_ANEOutputSetEnqueue");
SEL oseSel = NSSelectorFromString(
@"outputSetWithProcedureIndex:setIndex:signalValue:"
"signalNotRequired:isOpenLoop:");
if (class_getClassMethod(gOSE, oseSel)) {
Method m = class_getClassMethod(gOSE, oseSel);
const char *enc = method_getTypeEncoding(m);
printf(" outputSetEnqueue encoding: %s\n",
enc ? enc : "?");
unsigned int na = method_getNumberOfArguments(m);
printf(" args: %u\n", na);
for (unsigned int i = 0; i < na; i++) {
char at[64] = {0};
method_getArgumentType(m, i, at, sizeof(at));
printf(" [%u] = %s\n", i, at);
}
}
}
} @catch (NSException *ex) {
printf(" EXCEPTION: %s\n", [[ex reason] UTF8String]);
}
if (k3.model) free_kernel(&k3);
}
// =================================================================
// Summary
// =================================================================
printf("\n============================================================\n");
printf(" RESULTS SUMMARY\n");
printf("============================================================\n");
printf(" Exp E: _ANEModel loaded: %s\n",
diskModel1 ? "YES" : "NO");
printf(" Exp E2: ANECompiler found: (see above)\n");
printf(" Exp F: Chaining pipeline: %s\n",
diskModel1 ? "ATTEMPTED" : "SKIPPED");
printf(" Exp G: SharedEvents: (see above)\n");
printf(" Exp H: Alt preparation: (see above)\n");
printf(" Exp K: Type encodings: DONE\n");
printf(" Exp L: Array params: %s\n",
chainingPrepSuccess ? "PREPARE SUCCEEDED" : "see above");
printf(" Exp M: Client load model: %s\n",
fullyLoadedModel ? "LOADED" : "see above");
printf(" Exp N: IOSurface mapping: DONE\n");
printf(" Exp O: Procedure info: DONE\n");
printf(" Exp P: Full chaining retry: %s\n",
chainExecuted ? "EXECUTED" : "see above");
printf("============================================================\n");
free_kernel(&k1);
free_kernel(&k2);
printf("\nDone.\n");
}
return 0;
}