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
12 changes: 9 additions & 3 deletions backends/apple/coreai/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ endif()

enable_language(OBJCXX)

set(_coreai_runtime_sources runtime/coreai_assets.mm runtime/coreai_storage.mm)
set(_coreai_runtime_sources runtime/coreai_assets.mm runtime/coreai_storage.mm
runtime/coreai_bookmarks.mm
)

function(coreai_configure_objc_target target)
target_include_directories(
Expand All @@ -28,9 +30,13 @@ endfunction()
if(EXECUTORCH_BUILD_TESTS AND CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_executable(
coreai_host_test
runtime/test/coreai_host_test.mm runtime/test/coreai_manifest_test.mm
runtime/test/coreai_host_test.mm
runtime/test/coreai_manifest_test.mm
runtime/test/coreai_storage_test.mm
runtime/test/coreai_filesystem_fixture.mm ${_coreai_runtime_sources}
runtime/test/coreai_filesystem_fixture.mm
runtime/test/coreai_bookmark_test.mm
runtime/test/coreai_bookmark_fixture.mm
${_coreai_runtime_sources}
)
coreai_configure_objc_target(coreai_host_test)
target_compile_definitions(coreai_host_test PRIVATE COREAI_ASSETS_TESTING=1)
Expand Down
33 changes: 33 additions & 0 deletions backends/apple/coreai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,39 @@ Directory creation uses default permissions filtered by the process umask, witho
an explicit owner-only restriction. Existing permissions are not changed.
Backup exclusion and required durability flushes still apply on reused paths.

Each partition derives a key from its selected export digest/bundle, source/AOT
mode, platform, Core AI device architecture, default SDK cache namespace,
versioned default options and persistent policy. Function bindings and delivery
location are excluded. No model bytes are hashed at runtime. Each key determines
a raw bookmark in `bookmarks`, a bundle directory in `staging`, and one of
256 shared coordination files in `locks`. There is no PTE-wide bookmark list or
serialized lifecycle record.


Raw bookmarks have an 8 MiB backend allocation limit, not an asserted SDK format
maximum, and are published atomically because losing one orphans an SDK entry.
A fixed pool of at most 256 disk locks coordinates loading and eviction across
threads and processes. The first byte of the validated cache key selects
`stripe-v1-00.lock` through `stripe-v1-ff.lock` within the lock directory. Files
are created on demand, so new model versions do not grow the pool beyond 256.
The mapping is part of the on-disk format and is not configurable. Different
keys on the same stripe serialize; different stripes remain independent.
Bookmarks and staging remain separate for every key. Runtime
operations hold only one stripe at a time.

Lock ownership is maintained by the OS, and acquiring a lock does not flush its
file or directory. Stripe files are never removed, including during cache
clearing or after process exit, so waiters and future openers keep using the
same inode. Removing the assets root externally requires all loads, sessions
and maintenance to stop.

Upgrading from per-key lock files requires stopping all processes using the
root and upgrading them together. Old and new locking schemes must not run
concurrently against the same root. Legacy per-key lock files are ignored and
left untouched; they can be removed separately during a fully quiescent offline
cleanup. The 256-file bound applies to the new stripe pool, not pre-existing
legacy files. Bookmarks and staged bundles need no migration.

## Host Tests

On macOS, `EXECUTORCH_BUILD_COREAI=ON` with `EXECUTORCH_BUILD_TESTS=ON`
Expand Down
71 changes: 71 additions & 0 deletions backends/apple/coreai/runtime/coreai_bookmarks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once

#include <cstddef>
#include <memory>
#import "coreai_assets.h"
#include "coreai_file.h"

namespace executorch::backends::coreai {

runtime::Result<NSString*> bookmark_key(
const Manifest& selected,
NSString* platform,
NSString* architecture);
// The first key byte selects a stripe in a fixed, versioned lock namespace.
constexpr size_t kBookmarkLockStripeCount = 256;
runtime::Result<NSString*> bookmark_lock_name(NSString* key);
// With create=false, a missing root is returned unchanged for no-op
// maintenance.
runtime::Result<NSString*> resolve_bookmark_root(
NSString* path,
bool create = true);

class BookmarkLock final {
public:
BookmarkLock(const BookmarkLock&) = delete;
BookmarkLock& operator=(const BookmarkLock&) = delete;

private:
friend runtime::Result<std::unique_ptr<BookmarkLock>>
lock_bookmark(NSString* root, NSString* key, bool create);
friend runtime::Result<NSData*> read_bookmark(const BookmarkLock& lock);
friend runtime::Error write_bookmark(const BookmarkLock& lock, NSData* data);
friend runtime::Result<NSString*> prepare_bookmark_staging(
const BookmarkLock& lock);
BookmarkLock(
int root,
int bookmarks,
int file,
NSString* root_path,
NSString* key);
FileDescriptor root_;
FileDescriptor bookmarks_;
FileDescriptor file_;
NSString* root_path_;
NSString* key_;
};

// Each acquisition opens an independent descriptor on one of 256 stable
// stripes. Different keys can share a stripe; do not hold multiple
// BookmarkLocks at once. The backend never removes lock files. With
// create=false, missing roots or entries return a null lock. Existing entries
// may require creating coordination files, so the root must be writable even
// with create=false.
runtime::Result<std::unique_ptr<BookmarkLock>>
lock_bookmark(NSString* root, NSString* key, bool create = true);
// Missing is nil. Empty, oversized, inaccessible or nonregular files fail
// closed.
runtime::Result<NSData*> read_bookmark(const BookmarkLock& lock);
// A staging-only lock has no bookmark directory; writes return InvalidArgument.
runtime::Error write_bookmark(const BookmarkLock& lock, NSData* data);
// Prepared only for cold loads; source preparation appends key/bundle.
runtime::Result<NSString*> prepare_bookmark_staging(const BookmarkLock& lock);

} // namespace executorch::backends::coreai
Loading
Loading