diff --git a/.gitignore b/.gitignore index f94c4a5..0592392 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target -/.venv .DS_Store diff --git a/docs/MOJO_SPIKE_84.md b/docs/MOJO_SPIKE_84.md deleted file mode 100644 index d59387e..0000000 --- a/docs/MOJO_SPIKE_84.md +++ /dev/null @@ -1,153 +0,0 @@ -# Mojo 1.0 Metal integration spike (#84) - -## Decision - -**STOP** the product integration at the license/runtime gate. DS4Server can pin -and invoke the Mojo 1.0 compiler through `uv`, but Mojo 1.0's open standard -library does not provide the host-side `DeviceContext` needed to load and run a -Metal kernel. That API is delivered by MAX and links to separately shipped -AsyncRT and KGEN runtime libraries whose redistribution status is not explicit. - -This is a mandatory stop under issue #84, not a performance conclusion. The -existing Objective-C Metal backend remains the production path. DS4Server now -targets Apple silicon and macOS 15 or newer, matching Mojo 1.0's supported host -floor. No MAX wheel, runtime library, virtual environment, or Modular source -checkout is bundled. - -Run the committed proof from the repository root: - -```sh -tools/mojo-spike/check.sh -``` - -The command syncs the locked `uv` environment, checks the exact compiler build, -emits a C-ABI object and dynamic library, records their closure under -`target/mojo-spike`, and verifies that the compiler-only environment cannot -import the GPU host API. Once the lock has been synced, the same proof runs -without network access as `UV_OFFLINE=1 tools/mojo-spike/check.sh`. - -## Pinned environment - -| Component | Pin / observation | -| --- | --- | -| Mojo compiler | `mojo-compiler==1.0.0` | -| Compiler identity | `Mojo 1.0.0 (ed45d567)` | -| Dependency manager | `uv.lock` revision 3; hashes recorded for every wheel | -| Mojo source tag | `mojo/v1.0.0`, commit `b4497b7ce9ba96331c72c637ad41b44bab374f33` | -| MAX probe | `max==26.5.0`, isolated outside the project environment | -| Host | Apple M5 Max, arm64, macOS 26.6.2 (25G83) | -| Xcode / Metal | Xcode 26.6 (17F113), Metal toolchain 17F109 | - -Only `mojo-compiler` is a project build dependency. The broader `mojo` package -and MAX are intentionally absent because they add tools and runtimes that the -committed proof does not need or may not redistribute. - -## Build and ABI findings - -`@export` produces a callable C symbol and `mojo build --emit object` produces a -Mach-O object that can be linked by the platform linker. This is the viable ABI -boundary if the GPU runtime gate is resolved: opaque handles, fixed-width C -scalars, caller-owned buffers, integer status codes, and an explicit last-error -function. Rust unwinding and Mojo exceptions must never cross it. - -`mojo build --emit shared-lib` is not self-contained. Even the trivial -`ds4_mojo_probe` export has this non-system dependency: - -```text -@rpath/libKGENCompilerRTShared.dylib -``` - -The object form avoids that dependency for the trivial CPU export, but it does -not provide a way to construct a Metal device context or launch a GPU kernel. -Importing `DeviceContext` from the open `std.gpu.host` package fails because it -is not exported there. Importing the working API from `max.gpu.host` fails in -the compiler-only environment because MAX is not installed. - -Compiling the Apache-licensed `max.gpu.host` Mojo sources directly did not make -the program self-contained. The link still required these external symbols: - -```text -_AsyncRT_DeviceContext_create -_AsyncRT_DeviceContext_deviceName -_AsyncRT_DeviceContext_release -_AsyncRT_DeviceContext_strfree -``` - -An isolated `max==26.5.0` probe could enumerate the Apple M5 Max, proving that -the API is technically viable when the proprietary runtime is present. Its -executable closure included: - -```text -@rpath/libKGENCompilerRTShared.dylib -@rpath/libAsyncRTMojoBindings.dylib -/usr/lib/libSystem.B.dylib -``` - -That probe is deliberately not part of the repository dependency graph. - -## License and redistribution inventory - -| Component | Source / package evidence | Product decision | -| --- | --- | --- | -| Mojo language, compiler sources, and standard library | Apache-2.0 with LLVM exceptions in the `modular/modular` repository | Approved for build use, subject to normal notices | -| `mojo-compiler` and `mojo-compiler-mojo-libs` wheels | Pinned by hash; wheel metadata identifies the MAX Platform Software License | Build-only; do not redistribute the wheels | -| MAX Mojo source modules | Repository source is Apache-2.0 with LLVM exceptions, while Modular separately states MAX usage and distribution remain under the Community License | Source license alone does not approve the runtime closure | -| `max`, `max-core`, and `max-mojo-libs` wheels | Wheel metadata: `LicenseRef-MAX-Platform-Software-License` | Not a product dependency; do not bundle | -| `libAsyncRTMojoBindings.dylib` and related AsyncRT libraries | Supplied only by the MAX wheel in this probe; no component-specific redistribution grant found | Blocked | -| `libKGENCompilerRTShared.dylib` | Required by compiler-emitted shared libraries and the MAX GPU executable; no component-specific redistribution grant found | Blocked | -| Apple Metal frameworks and system libraries | Supplied by macOS | Approved system dependency | -| Existing DS4Server Objective-C Metal backend | Existing project code and Apple system frameworks | Remains the production implementation | - -The governing sources are the [Mojo repository license](https://github.com/modular/modular/blob/mojo/v1.0.0/LICENSE), -the [Modular repository notice separating MAX licensing](https://github.com/modular/modular#license), -and the [MAX and Mojo Community License](https://www.modular.com/legal/max-mojo-license). -The Community License permits redistribution only for components Modular -expressly identifies as redistributable and subject to its conditions. No -authoritative component list was found that names the two required dylibs. -Silence is not permission, so packaging is blocked. - -## Platform and packaging result - -Mojo 1.0 officially requires Apple silicon, macOS 15 or newer, Xcode or Command -Line Tools 16 or newer, and the Metal toolchain. DS4Server now declares that -same architecture and OS floor in its build environment, package metadata, and -README. The native backend remains necessary because the license/runtime gate, -not the platform floor, blocks the Mojo backend. - -The required package proof cannot pass today: - -- a clean machine would need non-system MAX runtime dylibs; -- their exact redistributable status and required notices are unresolved; -- an ad-hoc signed `.app` cannot be accepted while those dylibs are absent or - copied without permission; -- CUDA viability cannot be inferred from this Metal probe and remains a - separate Linux/NVIDIA build, runtime, and license audit. - -## Performance result - -No parity number is reported. The approved compiler-only environment cannot -launch a Metal operation, so there is no license-safe Mojo candidate to compare -with native Metal. Timing a MAX-backed or CPU-only substitute would answer a -different question and create a misleading baseline. The parity harness and raw -GPU/wall-clock measurements begin only after an approved host/runtime path can -build, link, and package. - -## Conditions to resume - -All of the following are required before issue #85 or later implementation may -replace native code: - -1. Modular publishes an authoritative redistribution grant naming every - required runtime library, or Mojo exposes a host-side Metal launch path whose - complete closure is under an approved open-source/system license. -2. The locked environment still builds through `uv` and works offline after - dependency installation. -3. `otool -L` and `nm -u` show only system libraries and explicitly approved, - packaged runtime components. -4. A clean-machine ad-hoc signed app launch proves install-name, rpath, code-sign, - and notice handling. -5. The parity harness records identical workloads, correctness, GPU execution - time, wall time, and repeated samples against the native Metal oracle. - -Until then, later milestone issues are design and inventory work only; they may -not introduce MAX as a Cargo, `uv`, build-script, or application dependency. diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index b05e3f6..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,8 +0,0 @@ -[project] -name = "ds4server-mojo" -version = "0.1.0" -requires-python = ">=3.10" -dependencies = ["mojo-compiler==1.0.0"] - -[tool.uv] -package = false diff --git a/tools/mojo-spike/abi.mojo b/tools/mojo-spike/abi.mojo deleted file mode 100644 index 9b1479e..0000000 --- a/tools/mojo-spike/abi.mojo +++ /dev/null @@ -1,3 +0,0 @@ -@export("ds4_mojo_probe") -def ds4_mojo_probe(value: Int32) abi("C") -> Int32: - return value diff --git a/tools/mojo-spike/check.sh b/tools/mojo-spike/check.sh deleted file mode 100755 index b4e7236..0000000 --- a/tools/mojo-spike/check.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -set -eu - -cd "$(dirname "$0")/../.." - -output_dir=target/mojo-spike -mkdir -p "$output_dir" - -uv sync --frozen - -version=$(uv run --frozen --no-sync mojo --version) -test "$version" = "Mojo 1.0.0 (ed45d567)" - -uv run --frozen --no-sync mojo build --emit object \ - -o "$output_dir/abi.o" tools/mojo-spike/abi.mojo -uv run --frozen --no-sync mojo build --emit shared-lib \ - -o "$output_dir/libds4_mojo_probe.dylib" tools/mojo-spike/abi.mojo - -otool -L "$output_dir/libds4_mojo_probe.dylib" \ - > "$output_dir/abi-closure.txt" -nm -u "$output_dir/libds4_mojo_probe.dylib" \ - > "$output_dir/abi-undefined.txt" - -grep -F '@rpath/libKGENCompilerRTShared.dylib' \ - "$output_dir/abi-closure.txt" >/dev/null - -if uv run --frozen --no-sync mojo build \ - -o "$output_dir/gpu-host" tools/mojo-spike/gpu_host.mojo \ - > "$output_dir/gpu-host-build.txt" 2>&1; then - echo "unexpectedly found a GPU host runtime in the compiler-only environment" >&2 - exit 1 -fi - -grep -F "unable to locate module 'max'" \ - "$output_dir/gpu-host-build.txt" >/dev/null - -printf '%s\n' \ - "Mojo 1.0 compiler and C ABI: verified" \ - "Open Metal GPU host path: unavailable" \ - "Shared-library runtime closure: @rpath/libKGENCompilerRTShared.dylib" \ - "Decision: STOP until the runtime closure is explicitly redistributable" diff --git a/tools/mojo-spike/gpu_host.mojo b/tools/mojo-spike/gpu_host.mojo deleted file mode 100644 index af2cac3..0000000 --- a/tools/mojo-spike/gpu_host.mojo +++ /dev/null @@ -1,6 +0,0 @@ -from max.gpu.host import DeviceContext - - -def main() raises: - var context = DeviceContext() - print(context.name()) diff --git a/uv.lock b/uv.lock deleted file mode 100644 index c535436..0000000 --- a/uv.lock +++ /dev/null @@ -1,35 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.10" - -[[package]] -name = "ds4server-mojo" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "mojo-compiler" }, -] - -[package.metadata] -requires-dist = [{ name = "mojo-compiler", specifier = "==1.0.0" }] - -[[package]] -name = "mojo-compiler" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mojo-compiler-mojo-libs" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/59/c11cf3129d4bc77b1604ac3a84bee51ee1a7cd8a3a8fa25c14528f4bd51e/mojo_compiler-1.0.0-py3-none-macosx_13_0_arm64.whl", hash = "sha256:5077ee27c0dfbbdf138a11ec12838b0d3f10148a874cf95040c9ca2332ae2622", size = 70979164, upload-time = "2026-08-11T14:34:51.281Z" }, - { url = "https://files.pythonhosted.org/packages/a5/f9/cbfe2bf947d0926ad57599513d898f1e02ee0c60af1253b779ecaa810235/mojo_compiler-1.0.0-py3-none-manylinux_2_34_aarch64.whl", hash = "sha256:3ae3eb0c58a8956f542e324f736866df0ae2f9f875e8a279cbeea961ec4e9ee8", size = 76295262, upload-time = "2026-08-11T14:34:22.131Z" }, - { url = "https://files.pythonhosted.org/packages/f0/5f/f38fefe327d1c81e28def69c4a52ae4f75e389cb6e613a2c04ca8d68d582/mojo_compiler-1.0.0-py3-none-manylinux_2_34_x86_64.whl", hash = "sha256:e9e60f9638e69ca0f4be7292468523fc98a143f58dbf9024f60ed68b874a867e", size = 79142588, upload-time = "2026-08-11T14:34:05.301Z" }, -] - -[[package]] -name = "mojo-compiler-mojo-libs" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/99/ea401ff1db56a4af8607283b95627e01b986fc67f510715b07f100118105/mojo_compiler_mojo_libs-1.0.0-py3-none-any.whl", hash = "sha256:20a92e37ecbd19e2dbb1a525612a8de4c9f266f5536def55c5e2b0786320e8b3", size = 3187048, upload-time = "2026-08-11T14:33:53.171Z" }, -]