-
Notifications
You must be signed in to change notification settings - Fork 229
MetalCompilerPlugin support #313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,12 @@ | ||
| // swift-tools-version: 5.12 | ||
| // swift-tools-version: 6.2 | ||
| // The swift-tools-version declares the minimum version of Swift required to build this package. | ||
| // Copyright © 2024 Apple Inc. | ||
|
|
||
| import Foundation | ||
| import PackageDescription | ||
|
|
||
| let inXcode = ProcessInfo.processInfo.environment["XCODE_VERSION_ACTUAL"] != nil | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this won't work correctly: Xcode can't build the shaders with the correct arguments (in particular the NAX shaders). That won't be a problem once those move to JIT builds, but I think it isn't a good idea to have to different build paths where bugs might show up in one and not in the other (I realize we have swiftPM, Xcode and Cmake so this is already an issue, but the swiftpm and Xcode paths do use the same build process).
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For Xcode builds, the MetalShaderCompiler is not needed. And for spm builds it is required.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The plugin allows you to specify arguments when building the shaders. |
||
|
|
||
| let package = Package( | ||
| name: "mlx-swift", | ||
|
|
||
|
|
@@ -26,7 +29,8 @@ let package = Package( | |
| ], | ||
| dependencies: [ | ||
| // for Complex type | ||
| .package(url: "https://github.com/apple/swift-numerics", from: "1.0.0") | ||
| .package(url: "https://github.com/apple/swift-numerics", from: "1.0.0"), | ||
| .package(url: "https://github.com/schwa/MetalCompilerPlugin", branch: "main"), | ||
| ], | ||
| targets: [ | ||
| .target( | ||
|
|
@@ -155,7 +159,14 @@ let package = Package( | |
| .linkedFramework("Foundation"), | ||
| .linkedFramework("Metal"), | ||
| .linkedFramework("Accelerate"), | ||
| ] | ||
| ], | ||
|
|
||
| plugins: | ||
| // Optional: Use plugin for custom Metal compilation | ||
| // needed for swift build. Xcode does it automatically | ||
| inXcode ? [] : [ | ||
| .plugin(name: "MetalCompilerPlugin", package: "MetalCompilerPlugin") | ||
| ], | ||
| ), | ||
| .testTarget( | ||
| name: "CmlxTests", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,10 +8,6 @@ MLX is an array framework for machine learning on Apple silicon. MLX Swift | |
| expands MLX to the Swift language, making research and experimentation easier | ||
| on Apple silicon. | ||
|
|
||
| ## Language Models | ||
|
|
||
| LLM and VLM implementations are available in [mlx-swift-lm](https://github.com/ml-explore/mlx-swift-lm). | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are these removed from the README?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was not intentional |
||
|
|
||
| ## Examples | ||
|
|
||
| MLX Swift has [many | ||
|
|
@@ -42,7 +38,7 @@ from MLX Python. | |
|
|
||
| ## Installation | ||
|
|
||
| The ``MLX`` Swift package can be built and run from Xcode or SwiftPM. A CMake installation is also provided, featuring a native Linux build option. | ||
| The ``MLX`` Swift package can be built and run from Xcode or SwiftPM. A CMake install is also provided. | ||
|
|
||
| More details are in the [documentation](https://swiftpackageindex.com/ml-explore/mlx-swift/main/documentation/mlx/install). | ||
|
|
||
|
|
@@ -72,6 +68,8 @@ dependencies: [.product(name: "MLX", package: "mlx-swift"), | |
| > [!Note] | ||
| > SwiftPM (command line) cannot build the Metal shaders so the ultimate build has to be done | ||
| > via Xcode. | ||
| > | ||
| >Update: Using [Metal Compiler Plugin](https://github.com/schwa/MetalCompilerPlugin), the library will be compiled and stored as default.metallib inside the Clmx-bundle. It is not in the Resources of the main bundle! With [patch](https://github.com/ml-explore/mlx/pull/2885) mlx is able to load default.metallib from any bundle root. What is left to the application/bundle to ensure, the bundle is loaded. Check the `setUp()` function in ArrayAtTests.swift as an example for manual loading. | ||
|
|
||
| ### xcodebuild | ||
|
|
||
|
|
@@ -99,57 +97,14 @@ brew install ninja | |
| With CMake: | ||
|
|
||
| ```shell | ||
| mkdir -p build | ||
| mkdir build | ||
| cd build | ||
| cmake .. -G Ninja | ||
| ninja | ||
| ./example1 | ||
| ./tutorial | ||
| ``` | ||
|
|
||
| <details> | ||
| <summary>Expand Native Linux Build Instructions</summary> | ||
|
|
||
| #### (1) Install Dependencies | ||
|
|
||
| RHEL/Fedora: | ||
| ```shell | ||
| sudo dnf install -y blas-devel lapack-devel openblas-devel clang llvm cmake make ninja | ||
| # Then install Swift by following the instructions at https://swift.org | ||
| ``` | ||
|
|
||
| Ubuntu/Debian: | ||
| ```shell | ||
| sudo apt update; | ||
| sudo apt install -y libblas-dev liblapack-dev libopenblas-dev clang llvm cmake make ninja; | ||
| # Then install Swift by following the instructions at https://swift.org | ||
| ``` | ||
|
|
||
| Refer to [swift.org](https://www.swift.org/install/linux/) for installation options and instructions specific to your Linux distribution. | ||
|
|
||
|
|
||
| #### (2) Build + Run Examples | ||
|
|
||
| On Linux, the examples use the CPU backend by default. | ||
|
|
||
| Note: GPU+CUDA support is a work in progress for `mlx-swift` on Linux, but is available in the Python-based MLX. | ||
|
|
||
| Note: SwiftPM builds are not currently supported for native Linux targets. | ||
|
|
||
| ```shell | ||
| mkdir -p build | ||
| cd build | ||
| cmake -DMLX_BUILD_METAL=OFF .. -G Ninja | ||
| ninja | ||
| ./example1 | ||
| ./tutorial | ||
| ``` | ||
|
|
||
|
|
||
| </details> | ||
|
|
||
| </br> | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this removed?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same. I think, I have copied over the Readme instead of redoing the modification. Should be an easy fix. |
||
|
|
||
| ## Contributing | ||
|
|
||
| Check out the [contribution guidelines](CONTRIBUTING.md) for more information | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "xcrun": true, | ||
| "find-inputs": false, | ||
| "include-dependencies": false, | ||
| "dependency-path-suffix": "include", | ||
| "include-paths": ["mlx-generated"], | ||
| "inputs": [ | ||
| "Source/Cmlx/mlx-generated/metal/steel/attn/kernels/steel_attention.metal", | ||
| "Source/Cmlx/mlx-generated/metal/arg_reduce.metal", | ||
| "Source/Cmlx/mlx-generated/metal/conv.metal", | ||
| "Source/Cmlx/mlx-generated/metal/rms_norm.metal", | ||
| "Source/Cmlx/mlx-generated/metal/random.metal", | ||
| "Source/Cmlx/mlx-generated/metal/scaled_dot_product_attention.metal", | ||
| "Source/Cmlx/mlx-generated/metal/gemv.metal", | ||
| "Source/Cmlx/mlx-generated/metal/layer_norm.metal", | ||
| "Source/Cmlx/mlx-generated/metal/rope.metal"], | ||
| "output": "default.metallib", | ||
| "flags": ["-gline-tables-only", "-frecord-sources", "-Wno-c++20-extensions", "-std=metal4.0"], | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure we can use metal4 for all the shaders, we just want it for the NAX shaders. If we do this then it won't run on pre-macOS 26. I think we need to vary this per file (which is why we can't currently support NAX in
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One way out would be, that swiftpm shader compilation is only supported from e.g. OS 26 onwards. |
||
| "plugin-logging": true, | ||
| "verbose-logging": false, | ||
| "metal-enable-logging": false, | ||
| "logging-prefix": "[Metal]" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,33 @@ | |
| import Foundation | ||
| import MLX | ||
| import XCTest | ||
| import Cmlx | ||
|
|
||
| class ArrayAtTests: XCTestCase { | ||
| override class func setUp() { | ||
| super.setUp() | ||
|
|
||
| // Cmlx is not an automatically loaded bundle. | ||
| // Let's load Cmlx manually, so that the mlx-lib can find the default.metallib. | ||
| // This requires patch #2885 in ml-explore/mlx be applied. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a workaround for the fix from the mlx repo?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. Both are needed. The issue is, that the plugin can only write to its plugin dir and the module dir, which depends on it. There is no way to get this metallib out of the module in the main module. The mlx-repo already supports searching all bundles‘ resource URL, which is a major step. Now the issue is, that I doubt, that the plugin can write a valid resource. At least I was not successful. So the remedy is, that not only the bundles’ resourceURL are searched, but the bundles‘ root directories, too. This is the purpose of the patch in mlx. Now the tricky thing is, that on swiftpm level modules are not autloaded. The patch in the test performs the manual loading of the bundle and then the mlx-code is (magically) able to find the bundle in the list. There is a lot of automatisms in the Xcode build process.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I think this will probably be a blocker until we can figure out how to get the resource production working -- applications can't be required to do this same work also.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought that producing resources was the only thing a plugin could do. We used to have a plugin that would prepare the include paths in the shaders: it didn't compile them. I know it can't produce a |
||
|
|
||
| // Find the test bundle (.xctest) | ||
| let testBundle = Bundle(for: self) | ||
|
|
||
| // Go to its parent directory: …/debug | ||
| let buildDir = testBundle.bundleURL.deletingLastPathComponent() | ||
|
|
||
| // Append the actual SwiftPM bundle name for Cmlx | ||
| let cmlxURL = buildDir.appendingPathComponent("mlx-swift_Cmlx.bundle") | ||
|
|
||
| if let cmlxBundle = Bundle(url: cmlxURL) { | ||
| print("Loaded Cmlx bundle at:", cmlxURL.path) | ||
| _ = cmlxBundle.load() // registers it globally | ||
| } else { | ||
| print("Failed to load Cmlx bundle at:", cmlxURL.path) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| func testArrayAt() { | ||
| // from example at https://ml-explore.github.io/mlx/build/html/python/_autosummary/mlx.core.array.at.html#mlx.core.array.at | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am concerned about this -- it locks out developers who use older Xcode. Why do we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to check, if this 6.2 is really necessary.