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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ under Unreleased and move into a version section at release time.

## Unreleased

### Changed

- Apple silicon Macs list the Neural Engine as `npu` in the device's
accelerators, next to `cpu` and `mps`. It was missing, so a model that runs
there had no matching entry. The Swift SDK already lists it.

## 0.3.0 - 2026-10-24

### Added
Expand Down
22 changes: 22 additions & 0 deletions tests/test_platform_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ def test_macos_gpu_accelerators_for_arm64(monkeypatch):
assert gpu_name is None


def test_macos_lists_the_neural_engine_on_arm64_only(monkeypatch):
platform = MacOSPlatform()
monkeypatch.setattr("platform.machine", lambda: "arm64")
assert platform.npu_accelerators() == ["npu"]
monkeypatch.setattr("platform.machine", lambda: "x86_64")
assert platform.npu_accelerators() == []


def test_other_platforms_list_no_npu():
assert LinuxPlatform().npu_accelerators() == []
assert WindowsPlatform().npu_accelerators() == []
assert UnknownPlatform().npu_accelerators() == []


def test_unknown_platform_disk_bytes_failure_returns_none(monkeypatch):
platform = UnknownPlatform()

Expand Down Expand Up @@ -223,3 +237,11 @@ def test_platform_adapters_expose_state_and_cache_paths():
):
assert adapter.state_base()
assert adapter.cache_base()


def test_apple_silicon_device_lists_cpu_gpu_and_neural_engine(monkeypatch):
platform = MacOSPlatform()
monkeypatch.setattr("platform.machine", lambda: "arm64")
monkeypatch.setattr(platform, "load_or_create_device_uuid", lambda: "uuid")
info = platform.detect_device(api_key="k", app_version="1.0")
assert info.accelerators == ["cpu", "mps", "npu"]
1 change: 1 addition & 0 deletions wildedge/accelerators.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
ROCM = "rocm" # AMD GPU
MPS = "mps" # Apple GPU (Metal)
COREML = "coreml" # Apple Core ML, which may use the GPU or Neural Engine
NPU = "npu" # Neural processing unit, such as Apple's Neural Engine
DIRECTML = "directml" # Windows DirectML
OPENVINO = "openvino" # Intel OpenVINO
5 changes: 4 additions & 1 deletion wildedge/platforms/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ def gpu_accelerator_for_offload(self) -> str: ...

# Optional hardware introspection — subclasses override what they support.

def npu_accelerators(self) -> list[str]:
return []

def meminfo(self) -> tuple[int | None, int | None]:
return None, None

Expand Down Expand Up @@ -113,7 +116,7 @@ def detect_device(
cpu_cores=os.cpu_count(),
ram_total_bytes=self.ram_bytes(),
disk_total_bytes=self.disk_bytes(),
accelerators=[accelerators.CPU, *gpu_accs],
accelerators=[accelerators.CPU, *gpu_accs, *self.npu_accelerators()],
gpu_name=gpu_name,
)
if overrides:
Expand Down
4 changes: 4 additions & 0 deletions wildedge/platforms/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ def gpu_accelerators(self) -> tuple[list[str], str | None]:
def gpu_accelerator_for_offload(self) -> str:
return accelerators.MPS if platform.machine() == "arm64" else accelerators.CPU

def npu_accelerators(self) -> list[str]:
# Every Apple silicon Mac has a Neural Engine.
return [accelerators.NPU] if platform.machine() == "arm64" else []

def cpu_freq(self) -> tuple[int | None, int | None]:
"""Read CPU frequency via sysctl.

Expand Down
Loading