Replies: 1 comment
-
|
in case you are interested in MetalGraph, I have a couple of blog posts on it (the latter related to this RFC in part): https://selfenrichment.hashnode.dev/the-honest-limits-reached-with-metalgraph |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I am working on MetalGraph, a small graph-oriented runtime experiment around Metal resources. One interop path that would be useful for projects like this is the ability to borrow the backing Metal storage of an evaluated MLX array for read-only external Metal use.
I am not asking for broad mutable sharing, hidden synchronization, or a general-purpose “zero-copy” promise. The narrower request is a supported C++/Metal API that can expose a retained read-only view of an evaluated array’s backing Metal storage, when MLX can safely provide one.
The intended contract would be:
This avoids the hardest synchronization and mutation problem. The MLX Metal allocator appears to use shared storage with untracked hazard tracking, so external runtimes should not assume implicit cross-command-queue hazard management. See
allocator.cpp. MLX also documents lazy evaluation and explicit evaluation/synchronization concepts, so the API should be clear about whether it fails, waits, or materializes before export. See the MLX lazy evaluation docs.The proposed API would guarantee only:
It would not guarantee safe external writes into MLX-owned storage.
Proposed API shape
The API could add a small C++ class that privately retains enough MLX ownership to keep the backing storage alive for the lifetime of the view. The retained owner could be the source array itself, or a smaller internal owner if maintainers prefer that.
Conceptually, the view would expose facts already tracked by
mlx::core::array, such as:array::data_size()already appears to represent the underlying data span in elements and may differ from the logical array size for broadcasted or irregularly-strided arrays. Seearray.h.One possible API shape:
The exact naming and placement are not important to me. I am mainly trying to describe the contract.
Lazy evaluation behavior
The export API should not silently materialize lazy MLX expressions by default.
If the source
mlx::core::arrayis not currently available/materialized,try_export_metal_storage(...)should return something like:An option such as
wait_until_available = truecould allow the caller to explicitly request MLX-side waiting/materialization before export, using whatever mechanism maintainers consider appropriate.Defaulting to “fail unless already available” would avoid surprising evaluation side effects and keep storage export separate from computation scheduling.
Layout behavior
The API could require row-contiguous layout by default.
If an array is not row-contiguous, the export call could return something like:
That kind of explicit failure is useful for external runtimes, because layout support is exactly where accidental “zero-copy” claims can become misleading.
The API could still report shape and stride metadata so that future versions, or more advanced callers, can intentionally support additional layouts later.
Possible PR scope
A PR might touch something like:
Possibly:
if maintainers prefer exporting the declaration from an existing Metal backend umbrella header.
I would not add Python bindings in the PR. A C++/Metal API would already be enough for extension authors and would keep the initial scope smaller.
Non-goals
This RFC is not proposing:
The goal is only to provide a supported, conservative storage export contract for advanced Metal interop.
Question for maintainers
Would this kind of read-only
MetalStorageViewAPI fit MLX’s design?If so, I would be interested in preparing a small PR limited to that scope: evaluated arrays only, read-only external use, explicit failure for unavailable or unsupported layouts, retained lifetime through the view object, and documentation that synchronization remains caller-managed.
Beta Was this translation helpful? Give feedback.
All reactions