Repository navigation
Conversation
MLModel.compileModel ran on every mlperf_backend_create and the compiled .mlmodelc was never kept. Keep it in Caches/mlperf_coreml_models, one entry per source path, and reuse it while a fingerprint of the source files (path, size, mtime) matches. An unreadable entry is recompiled; a failure to cache falls back to the freshly compiled model. Build the model URL with URL(fileURLWithPath:) instead of URL(string:), which returns nil on iOS 15/16 for paths that need percent-encoding. MLError now carries its message as localizedDescription.
mlperf_backend_issue_query ignored ft_callback, so time to first token could not be measured on Core ML. Call it after the prediction when the benchmark sets custom_setting report-first-token=true. It stays off by default: non-token benchmarks don't expect token latencies, and in Offline mode the driver passes a sample index where loadgen reads a pointer. Also log the error when CoreMLExecutor creation fails.
The app already targets iOS 15.0; the backend still declared 13.1.
image_classification and image_classification_offline (v3_0 MobilenetEdgeTPU) are not task ids in tasks.pbtxt, so these entries were never used. image_classification is only the task_set of the _v2 tasks.
Pin coremltools 9.0 with the newest torch (2.7.0) and TensorFlow (2.12.0, via tensorflow-macos) it is tested with, on Python 3.11. coremltools 7 changed the ct.convert default to mlprogram. The TF scripts build NeuralNetwork models (.mlmodel, quantization_utils, NeuralNetworkBuilder), so pass convert_to='neuralnetwork' explicitly. Document the compiled-model cache and the custom settings the backend reads.
mlperf_backend_create set backendExists before loading the model and returned nullptr on failure without clearing it or freeing backend_data, so every later create failed with "Only one backend instance should exist at a time". Set the flag only once the backend is ready, and free the data on failure.
|
MLCommons CLA bot All contributors have signed the MLCommons CLA ✍️ ✅ |
|
|
@anhappdev check Core ML's built-in caching mechanism works or not. Or, in other words, does app-level cache pay off or not. If model compilation time is a concern, we can just load compiled model (.modelc/). |
@freedomtan The problem is that the app explicitly compiles the model everytime it runs the benchmark, so we need to fix the logic there. |
…#1191) ## Problem The Xcode Cloud "Deploy to TestFlight | Archive - iOS" run reports about 30 warnings on every build (31 on #1160 and #1164, 29 on #1190). None of them come from our code: - About 13 linker warnings `Search path '.../Metal.xctoolchain/usr/lib/swift/iphoneos' not found`, one per Swift pod plus the app. - About 15 compiler warnings in Flutter plugin sources under `.pub-cache`: firebase_auth (deprecated APIs, unused variables, `keyWindow`), firebase_core (pointer types), firebase_storage (non-exhaustive switch, retroactive `Error` conformance), share_plus (`keyWindow`), device_info_plus (integer precision). - `libtool: warning: 'dummy.o' has no symbols`. ## Cause CocoaPods adds `"${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"` to every Swift pod's `LIBRARY_SEARCH_PATHS`, and the url_launcher_ios and shared_preferences_foundation podspecs add `$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/`, which also reaches `Pods-Runner`. On Xcode Cloud the Metal toolchain comes first in `TOOLCHAINS`, so `TOOLCHAIN_DIR` points into `Metal.xctoolchain`. That toolchain has no `usr/lib/swift`, so every link step warns. ## Change In `flutter/ios/Podfile` `post_install`: - Remove the `$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)` entry (either spelling, and the old `DT_TOOLCHAIN_DIR` form) from the pod xcconfigs. The app targets iOS 15, which ships the Swift runtime in `/usr/lib/swift`, and `/usr/lib/swift` and `$(SDKROOT)/usr/lib/swift` stay in the search paths. This replaces the Xcode 15 `DT_TOOLCHAIN_DIR` → `TOOLCHAIN_DIR` rewrite, which no podspec here needs any more. - Set `GCC_WARN_INHIBIT_ALL_WARNINGS` and `SWIFT_SUPPRESS_WARNINGS` on pod targets. CocoaPods' `inhibit_all_warnings!` only covers Objective-C files, so it would leave the firebase_storage Swift warnings. Only third-party pod targets are affected. Warnings in our own Runner code still show up. ## Verification Local builds of the `Pods-Runner` target (all plugin and Firebase pods, `-sdk iphoneos`, Release, Xcode 26.6, CocoaPods 1.17.0). The Metal toolchain is installed and put first in `TOOLCHAINS` to match Xcode Cloud, which makes `TOOLCHAIN_DIR` point into `Metal.xctoolchain` there too: | Podfile | `TOOLCHAINS` | Result | Warnings | |---|---|---|---| | `master` | Metal first (like Xcode Cloud) | BUILD SUCCEEDED | 29: 12 `search path ... Metal.xctoolchain ... not found`, 15 plugin warnings, `dummy.o`, Crashlytics duplicate `-lc++` | | this PR | Metal first (like Xcode Cloud) | BUILD SUCCEEDED | 0 | | this PR | default | BUILD SUCCEEDED | 0 | The full app link (Runner plus the bazel-built backends) wasn't built locally. The Xcode Cloud archive on this PR is the end-to-end check.
|
To avoid compiling every time, we can simply compile a model offline. @freedomtan to check it. |



Summary
The "Core ML quick wins" from #1188. None of them depend on Core AI. One commit per item:
MLModel.compileModelused to run on everymlperf_backend_create. The compiled.mlmodelcnow lives inCaches/mlperf_coreml_models(one entry per source path) and is reused while a fingerprint of the source files (path, size, mtime) still matches. An unreadable entry gets recompiled. If caching fails, the backend uses the freshly compiled model. The model URL is built withURL(fileURLWithPath:).URL(string:)returns nil on iOS 15/16 for paths that need percent-encoding (iOS 17+ encodes them silently).ft_callback. It is called after the prediction when the benchmark setscustom_setting { id: "report-first-token" value: "true" }, and is off by default. Calling it for every benchmark is unsafe: non-token runs don't expect token latencies, and in Offline modeMlperfDriverputssample.back().indexwhere loadgen'sFirstTokenCompletedereferences aSampleMetadata*. No Core ML benchmark sets the flag yet; it's plumbing for a future LLM path. A failedCoreMLExecutorcreation now also logs the error.image_classification/image_classification_offlineentries (v3_0 MobilenetEdgeTPU).image_classificationis only thetask_setof the_v2tasks, not a task id.models/requirements.txt. It now pins coremltools 9.0, torch 2.7.0 / torchvision 0.22.0 / timm 1.0.15, and tensorflow-macos 2.12.0 (the newest torch and TF that coremltools 9.0 is tested with), on Python 3.11. coremltools 7 changed the defaultct.converttarget tomlprogram, which breaks the TF scripts'.mlmodel,quantization_utilsandNeuralNetworkBuildercalls. Somobilebert.py,mobiledet.py,mobilenet_edgetpu.pyandmosaic.pynow passconvert_to='neuralnetwork', which keeps their previous output.Also fixed: when model loading failed,
mlperf_backend_createleftbackendExists = trueand leakedbackend_data, so every later create was refused. The app aborts on a failed create anyway (LOG(FATAL)inexternal.cc), so this only affected callers that keep running, such asdev-utils.Test plan
bazel build --config=ios //mobile_back_apple/cpp/backend_coreml:libcoremlbackend(Xcode 26.6): the device slice hasminos 15.0and links CryptoKit.swiftc -typecheck -swift-version 6forarm64-apple-ios15.0andarm64-apple-macos13.1,swift-format lint --strict,clang-format16--dry-run --Werror, and markdownlint.CoreMLExecutor, with.mlpackageand.mlmodelfiles under a path containing a space. Checked: cold compile, warm reuse (entry untouched), recompile after the source changes, recovery from a corrupted entry, direct.mlmodelcload (nothing cached), and a clear error for a missing file. Predictions were correct in every case.v4_1/apple/mobilenetv4_fp32_NCHW.mlpackage(CPU & GPU, macOS VM): backend create took 266–428 ms before this change and 21–25 ms once cached. The cache entry is 62 MB.requirements.txt: TF SavedModel to NeuralNetwork plus fp16 weights, and timm MobileNetV4 to ML Program plus W8 and theexperimentalW8A8 API, thenpredict.ios_tests-apple-1080):apple-iPhone 16 Pro-18):All tests passed!. The device log shows each ML Program model loaded three times from oneLibrary/Caches/mlperf_coreml_models/<sha256>/model.mlmodelcentry, so compiled models are reused across backend creates.+14: All tests passed!, models served from the same cache, and no cache orCoreMLExecutorerrors.Espresso::overflow_errorlines on iOS 15. The base commit 846c58d logs 928 on the same device model, so they come from the model, not from this PR.Note: CI's test package doesn't start on iOS 15/16 for any PR. dyld can't find
lib_TestingInterop.dylibor_Testing_Foundation.framework: Xcode 26 doesn't embed them, and on iOS 18 they load from elsewhere on the device. For the iOS 15 runs above I copied both from Xcode intoRunner.app/Frameworksof the downloaded package. Fixing that inmake flutter/ios/test-packageis a separate change.