Skip to content
Open
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
15 changes: 8 additions & 7 deletions backends/apple/coreai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ python -m pytest backends/apple/coreai

## Runtime

The delegate manifest describes `.aimodel` source bundles, which require
`inline` packaging, and AOT-compiled `.aimodelc` bundles, which require
`aot_compiled_inline`. Both formats require a `function` name, and ordered
The delegate manifest's `packaging` field names the embedded format: `aimodel`
for a portable `.aimodel` bundle, located by `path`, or `aimodelc` for
AOT-compiled per-architecture `.aimodelc` bundles, located by `archs`. Both
formats require a `function` name, and ordered
`input_names` and `output_names` matching the converter's bindings. Dictionary
iteration order is not a binding contract. `export_hash` identifies the exported
program used to namespace embedded assets. The `files` object maps relative
Expand Down Expand Up @@ -128,9 +129,9 @@ even though the new complete contents are already visible. Use a local APFS
volume; unsupported full-device flushes are reported as errors, not downgraded
to `fsync`.

Inline bundles are read through `NamedDataMap` and materialized as unchanged
files under the cache directory. Named data can be supplied externally; inline
packaging does not require all bytes to reside in one physical PTE. The exporter
Embedded bundles are read through `NamedDataMap` and materialized as unchanged
files under the cache directory. Named data can be supplied externally; embedded
bundles do not require all bytes to reside in one physical PTE.
computes each bundle digest from all delivered relative filenames and file bytes,
not just the SDK's bytecode-only `main.hash`. Each AOT architecture has an
independent digest; only the selected architecture is materialized. NDS key names
Expand Down Expand Up @@ -191,7 +192,7 @@ choose the SDK artifact directory. The backend does not inspect SDK-private
files, alter their backup flags, or use an App Group cache.

Each selected bundle has a `bundle_identity` derived from its bundle digest,
name, and source/AOT mode. This identifies the delivered bundle independently of
name, and packaging (`aimodel` or `aimodelc`). This identifies the delivered bundle independently of
`export_hash`, which namespaces embedded assets. A readable cache key combines
that bundle identity with
the platform and Core AI device architecture, plus a hash of a versioned
Expand Down
10 changes: 5 additions & 5 deletions backends/apple/coreai/compiler/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ class COMPILE_SPEC_KEYS(Enum):

class AssetPackaging(str, Enum):
# Portable .aimodel embedded in the .pte via NamedDataStore.
INLINE = "inline"
AIMODEL = "aimodel"
# AOT-compiled per-arch .aimodelc bundles embedded in the .pte.
AOT_COMPILED_INLINE = "aot_compiled_inline"
AIMODELC = "aimodelc"


@dataclass(frozen=True)
Expand Down Expand Up @@ -213,7 +213,7 @@ def _deliver(
**manifest_extra,
**metadata,
}
if packaging == AssetPackaging.INLINE:
if packaging == AssetPackaging.AIMODEL:
manifest["path"] = f"{export_hash}/{manifest['path']}"
else:
manifest["archs"] = {
Expand Down Expand Up @@ -520,7 +520,7 @@ def _preprocess_portable(
_save_asset(program, Path(tmp) / "model.aimodel", min_os)
return _deliver(
Path(tmp),
AssetPackaging.INLINE,
AssetPackaging.AIMODEL,
{
**bindings,
# relative path the runtime resolves against its base
Expand All @@ -538,7 +538,7 @@ def _preprocess_aot_compiled(
out = _compile_aot(program, opts, Path(tmp))
return _deliver(
out,
AssetPackaging.AOT_COMPILED_INLINE,
AssetPackaging.AIMODELC,
{
**bindings,
"platform": opts["platform"],
Expand Down
2 changes: 1 addition & 1 deletion backends/apple/coreai/runtime/coreai_cache_key.mm
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ bool valid_device(NSString* device) {
bool aot_compiled) {
// Bumping the leading version makes every existing cache entry unreachable.
auto encoded = encode_json(
@[ @"1", digest, aot_compiled ? @"aot" : @"source", bundle_name ]);
@[ @"1", digest, aot_compiled ? @"aimodelc" : @"aimodel", bundle_name ]);
if (!encoded.ok()) {
return encoded.error();
}
Expand Down
2 changes: 1 addition & 1 deletion backends/apple/coreai/runtime/coreai_load_coordinator.mm
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ Error evict_one(id<ETCoreAIModelLoading> loader, NSData* bookmark) {
ET_LOG(
Info,
"Core AI specialization started: kind=%s, key=%s",
host_bundle.bundle.aot_compiled ? "aot" : "source",
host_bundle.bundle.aot_compiled ? "aimodelc" : "aimodel",
cache_key.UTF8String);
[loader specializeModelAtURL:url completion:completion];
});
Expand Down
8 changes: 4 additions & 4 deletions backends/apple/coreai/runtime/coreai_manifest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ bool parse_version(id value, NSOperatingSystemVersion& version) {
InvalidProgram,
"Missing Core AI packaging");
ET_CHECK_OR_RETURN_ERROR(
[packaging isEqualToString:@"inline"] ||
[packaging isEqualToString:@"aot_compiled_inline"],
[packaging isEqualToString:@"aimodel"] ||
[packaging isEqualToString:@"aimodelc"],
NotSupported,
"Unsupported Core AI packaging; expected .aimodel or AOT .aimodelc");
const bool aot_compiled = [packaging hasPrefix:@"aot_compiled_"];
"Unsupported Core AI packaging; expected aimodel or aimodelc");
const bool aot_compiled = [packaging isEqualToString:@"aimodelc"];
NSString* export_hash = dict[@"export_hash"];
NSString* function = dict[@"function"];
NSArray<NSString*>* inputs = dict[@"input_names"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void expect_preflight_rejection(
TEST_F(CoreAIDelegateTest, PreflightRejectsFutureDeploymentForSourceAndAot) {
@autoreleasepool {
for (bool aot : {false, true}) {
SCOPED_TRACE(aot ? "AOT" : "source");
SCOPED_TRACE(aot ? "aimodelc" : "aimodel");
auto dict = aot ? aot_manifest_dict() : manifest_dict();
dict[@"min_deployment_version"] = @"999999.0";
expect_preflight_rejection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ inline NSString* fixture_identity(char digit) {

inline NSMutableDictionary* manifest_dict() {
return [@{
@"packaging" : @"inline",
@"packaging" : @"aimodel",
@"export_hash" : @"ab",
@"path" : @"ab/model.aimodel",
@"function" : @"main",
Expand All @@ -37,7 +37,7 @@ inline NSMutableDictionary* manifest_dict() {
inline NSMutableDictionary* aot_manifest_dict() {
auto dict = manifest_dict();
[dict removeObjectForKey:@"path"];
dict[@"packaging"] = @"aot_compiled_inline";
dict[@"packaging"] = @"aimodelc";
dict[@"platform"] = @"macOS";
dict[@"archs"] = @{
@"arch_b" : @"ab/model.arch_b.aimodelc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

TEST_F(CoreAISourceTest, RejectsMalformedStoredBundlesWithoutReplacement) {
for (bool aot : {false, true}) {
SCOPED_TRACE(aot ? "aot" : "source");
SCOPED_TRACE(aot ? "aimodelc" : "aimodel");
for (NSString* damage in @[
@"missing-file",
@"extra-file",
Expand Down
14 changes: 6 additions & 8 deletions backends/apple/coreai/test/test_preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class PortablePreprocessTest(unittest.TestCase):
def test_inline_embeds_files_in_nds(self):
result = CoreAIBackend.preprocess(_edge_program(), [])
manifest = json.loads(result.processed_bytes)
self.assertEqual(manifest["packaging"], "inline")
self.assertEqual(manifest["packaging"], "aimodel")
self.assertTrue(manifest["files"], "expected at least one asset file")
out = result.data_store_output
self.assertIsNotNone(out)
Expand Down Expand Up @@ -215,7 +215,7 @@ def test_same_program_hash_with_different_metadata_merges(self):
(bundle / "metadata.json").write_text(
json.dumps({"creationDate": timestamp})
)
result = _deliver(root, AssetPackaging.INLINE, {"path": bundle.name})
result = _deliver(root, AssetPackaging.AIMODEL, {"path": bundle.name})
manifest = json.loads(result.processed_bytes)
manifests.append(manifest)
self.assertEqual(
Expand All @@ -240,9 +240,7 @@ def test_aot_namespace_covers_every_architecture(self):
(bundle / "model.mil").write_bytes(b"original")
for payload in (b"original", b"modified"):
(root / archs["h16"] / "model.mil").write_bytes(payload)
result = _deliver(
root, AssetPackaging.AOT_COMPILED_INLINE, {"archs": archs}
)
result = _deliver(root, AssetPackaging.AIMODELC, {"archs": archs})
manifest = json.loads(result.processed_bytes)
manifests.append(manifest)
for arch, name in archs.items():
Expand Down Expand Up @@ -378,7 +376,7 @@ def test_inline_embeds_compiled_bundles(self, _build):
[_aot_spec({"platform": "iOS", "architectures": ["h15g", "h16"]})],
)
manifest = json.loads(result.processed_bytes)
self.assertEqual(manifest["packaging"], "aot_compiled_inline")
self.assertEqual(manifest["packaging"], "aimodelc")
self.assertEqual(manifest["platform"], "iOS")
self.assertEqual(sorted(manifest["archs"]), ["h15g", "h16"])
# Compiled bundle contents are embedded (files under a *.aimodelc dir).
Expand All @@ -400,7 +398,7 @@ def test_defaults_to_all_architectures(self, _build):
# Empty architectures => coreai-build decides (our fake yields one).
result = CoreAIBackend.preprocess(_edge_program(), [_aot_spec({})])
manifest = json.loads(result.processed_bytes)
self.assertEqual(manifest["packaging"], "aot_compiled_inline")
self.assertEqual(manifest["packaging"], "aimodelc")
self.assertEqual(manifest["platform"], "macOS") # default
self.assertTrue(manifest["archs"])

Expand Down Expand Up @@ -448,7 +446,7 @@ def test_aot_inline_embeds_aimodelc(self):
CoreAIPartitioner(aot_compile_config=AOTCompileConfig(platform="macOS"))
)
lbm, manifest = _lowered_manifest(lowered)
self.assertEqual(manifest["packaging"], "aot_compiled_inline")
self.assertEqual(manifest["packaging"], "aimodelc")
self.assertEqual(manifest["platform"], "macOS")
self.assertGreaterEqual(len(manifest["archs"]), 1)
self.assertTrue(any(".aimodelc/" in f for f in manifest["files"]))
Expand Down
Loading