0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Apple M5 MaxをSlurm 26.11.0-0rc1の計算ノードにする―macOS版slurmd移植とMetal GPUジョブ実行

0
Posted at

はじめに

Slurm の公式Platformsページには、
Linux は x86_64 を含む複数アーキテクチャでテストされている一方、macOS は
過去に動作していたものの現在は動作しない、と記載されています。

そこで、Apple M5 Max 搭載MacをSlurmクラスタの計算ノードにするため、
macOS上で slurmd をビルド・起動し、Ubuntu上のコントローラからbatch jobと
Metal GPU jobを実行するPoCを行いました。

この記事では、成功した結果だけでなく、途中で遭遇したコンパイルエラー、
daemon起動エラー、job実行エラー、修正内容、そしてまだ確認できていない事項も
残します。

重要な検証範囲

macOSで移植・運用検証したdaemonは slurmd 側のみです。
slurmctldslurmdbd は x86-64版Ubuntu 24.04のヘッドノードで動かして
います。macOS上で slurmctld / slurmdbd が動くことを検証した記事では
ありません。

公式の以下の記述:

macOS — Slurm has run on macOS in the past, but does not currently.
It should be possible to fix this with some adjustments to linker and
compiler flags, and any patches would be appreciated.

だったら、LLMでパッチ作ってサクッと動かせるのでは?

っと思い、移植をやってみることに挑戦してみようかなと軽はずみに思って手を出したらまったく簡単ではなかったというオチです。


TL;DR

  • 作業フォルダ名は slurm.26-05 ですが、ソース、configureログ、生成物、
    インストール済みbinaryのEvidenceはすべて Slurm 26.11.0-0rc1 を示しました。
  • ヘッドノードは x86-64 / Ubuntu 24.04で、slurmctldslurmdbd、MariaDBを
    実行しました。
  • ワーカーノードは arm64 / macOS / Apple M5 Maxで、slurmd と、そのchildで
    ある slurmstepd のjob実行経路を検証しました。
  • pipe2accept4、POSIX timer、CPU bitmap、SACK、pthread、/proc
    Mach-O plugin symbolなど、多数のLinux/ELF依存を修正しました。
  • sbatchscancel、SlurmDBD accounting、Apple MLXによるMetal GPU jobまで
    動作しました。
  • CPU pinning、cgroupによるmemory/device隔離、interactive srun --pty
    最終確認、Linux regression、長時間安定性は未完了です。

クラスタ構成と検証範囲

ノード OS / architecture 今回の役割 macOS移植の検証対象
ubuntu2504 Ubuntu 24.04 / x86-64 slurmctld, slurmdbd, MariaDB いいえ
PC-210 macOS 26.5.1 / arm64 slurmd, slurmstepd, Metal GPU はい

macOS上で実行した sinfosqueuesbatchscancelsacct は、
slurmd の登録・job実行・accountingを観測するためのclient commandです。
client側の動作結果も記録しますが、cluster control daemonをmacOSへ移植した
という意味ではありません。

ヘッドノードについて保存されているログから、次を直接確認できました。

slurmctld version 26.11.0-0rc1 started on cluster cluster
slurmdbd version 26.11.0-0rc1 started
MySQL server version is: 10.11.14-MariaDB-0ubuntu0.24.04.1

Ubuntu 24.04 / x86-64という構成値は運用環境の記録とも一致します。ただし、
今回こちらからSSHで uname -m/etc/os-release を取得する試みは公開鍵認証
で拒否されました。この2コマンドの生出力は、記事公開前に追加取得する
Missing Evidenceとして後述します。

なお、Ubuntu 24.04はSlurm公式Platformsページにsupported distributionとして
掲載されています。このため、Linuxヘッドノードは比較的標準的な構成とし、
非公式状態にあるmacOSの slurmd 側を調査対象に絞りました。

記事内のEvidence区分

単にコンパイルできたことと、実運用経路で正しく動いたことを区別します。

状態 意味
確認済み 今回の実機出力または保存済みログで成功を確認した
部分確認 特定の経路では成功したが、網羅性・長時間安定性・回帰までは未確認
未確認 ソースまたは設定は用意したが、対象経路を実行していない
対象外 PoC の方針として機能を無効化した、または実装していない

フォルダ名は26.05だが、実体は26.11.0-0rc1

当初、作業フォルダを slurm.26-05 として開始しました。しかし、フォルダ名は
versionのEvidenceにはなりません。現在のソースとbinaryを再確認しました。

Git revision

git rev-parse HEAD
git describe --tags --always --dirty
a77367bb482ab2f626fb5981d1349159e5ae8740
slurm-25-05-0-1-8823-ga77367bb48-dirty

git describeslurm-25-05-0-1 は最も近い到達可能なtagを起点にした表記で、
package versionそのものではありません。このcheckoutは、そのtagから8823
commit進んだdirtyな開発treeです。

生成されたversion header

grep -E 'PACKAGE_VERSION|SLURM_VERSION_STRING' config.h
#define PACKAGE_VERSION "26.11"
#define SLURM_VERSION_STRING "26.11.0-0rc1"

configure log

config.log の冒頭には次が保存されています。

It was created by slurm configure 26.11

configureのprefixも /opt/slurm/26.11.0 です。

インストール済みbinary

/opt/slurm/26.11.0/sbin/slurmd -V
/opt/slurm/26.11.0/bin/sinfo --version
slurm 26.11.0-0rc1
slurm 26.11.0-0rc1

以上の4系統のEvidenceから、本記事の対象を Slurm 26.11.0-0rc1 と確定します。
「26.05」という名前は作業開始時のフォルダ名・初期資料名に残っているだけで、
検証対象versionを表していません。

また、古い /opt/slurm/26.05 を参照するlaunchd用draftは、そのまま現在環境へ
導入できません。この点も未確認事項として後述します。

検証環境

ヘッドノード

項目
Host ubuntu2504
OS Ubuntu 24.04
Architecture x86-64
Role slurmctld, slurmdbd, MariaDB
Slurm daemon version 26.11.0-0rc1
macOS移植検証 対象外

macOSワーカーノード

2026-09-09 にローカルで再確認した値です。

項目
Host PC-210.local
Hardware MacBook Pro / Apple M5 Max
CPU architecture arm64
CPU 18 cores
Memory 128 GB unified memory
macOS 26.5.1 (Build 25F80)
Darwin 25.5.0
Compiler Apple Clang 21.0.0
Linker Apple ld64, project ld-1267
Slurm 26.11.0-0rc1
hwloc 2.14.0
json-c 0.19
libjwt 2.1.3
Python 3.14.6
uv 0.12.2
MLX 0.32.2

当初の方針書には macOS 26.5.2 と記載されていましたが、現在の sw_vers
26.5.1でした。OS更新前後での再検証は行っていません。

configure条件

現在の config.log に記録された configure は次のとおり。

./configure \
  --prefix=/opt/slurm/26.11.0 \
  --sysconfdir=/opt/slurm/26.11.0/etc \
  --with-jwt=/opt/slurm-deps/libjwt-2.1.3 \
  --with-hwloc=/opt/homebrew/opt/hwloc \
  --with-json=/opt/homebrew/opt/json-c \
  --without-munge \
  --without-readline \
  --disable-cgroupv2 \
  --disable-x11 \
  --disable-sview \
  --disable-slurmrestd

config.logconfigure: exit 0 を記録しているため configure は確認済み。
--with-jsonserializer/json を生成するために追加した。MUNGE は使用せず、
auth/slurmcred/slurm を使用する。

発生した問題と修正経過

Apple ld64 と GNU ld オプションの非互換

症状:

  • -Wl,-rpath=<path>--no-as-needed-z noexecstack
    --format=binary など、GNU ld 前提の処理が Apple ld64 では成立しない。
  • .txt リソースを ELF オブジェクトへ変換する既存規則を Mach-O へそのまま
    適用できない。

修正:

  • Darwin 用の Automake conditional DARWIN_BUILD を追加。
  • rpath を Apple ld64 で受理される -Wl,-rpath,<path> 形式へ変更。
  • Darwin では --no-as-needed を付けない。
  • Darwin では .incbin を使う assembler 入力から Mach-O relocatable object
    を生成し、既存の __binary_*_start/end シンボル契約を維持。
  • 各コマンド配下の生成済み Makefile.in へ同等の規則を反映。

主な対象:

  • configure.ac, configure, auxdir/slurm.m4
  • make_ref.include
  • src/slurmd/slurmd/Makefile.am, Makefile.in
  • src/{sacct,sacctmgr,sackd,scontrol,scrontab,scrun,sinfo,slurmctld,slurmrestd,sprio,squeue,swait}/Makefile.in
  • src/plugins/certgen/script/Makefile.in

状態: 部分確認。macOS 上の実ビルドとコマンド生成は成立した。一方、用意
した testsuite/macos_build_compatibility.sh の全モード実行証跡、および
GNU/Linux 上での同一基準による回帰確認は残っていない。

cpu_set_t と Linux CPU affinity API

症状:

error: unknown type name 'cpu_set_t'

原因:

macOS は Linux の cpu_set_tCPU_*_Ssched_getaffinity()
sched_setaffinity() と互換の API を提供しない。

修正:

  • src/common/xsched.h に、Slurm 内部 bitmap 用の cpu_set_t
    CPU_ALLOC_SIZE / CPU_ZERO_S / CPU_SET_S / CPU_CLR_S /
    CPU_ISSET_S / CPU_COUNT_S 互換処理を追加。
  • bitmap と文字列の相互変換を macOS でも有効化。
  • xgetaffinity() 相当は _SC_NPROCESSORS_ONLN で取得した全 online CPU を
    使用可能として返す。
  • xsetaffinity() 相当は ENOTSUP を返す。

状態: 部分確認。18 CPU の検出と Slurm の CPU リソース割当は動作したが、
OS レベルの CPU pinning は実装していない。P-core/E-core の区別、NUMA、
特定 CPU への拘束も未確認または対象外である。

pipe2accept4SOCK_CLOEXECeventfd

症状:

eio.c: error: call to undeclared function 'pipe2'

および、Linux 固有の accept4()SOCK_CLOEXECeventfd() 依存。

修正:

  • src/common/fd.c / fd.h に次の共通 wrapper を追加。
    • fd_pipe_close_on_exec()
    • fd_event_create()
    • fd_socket_close_on_exec()
    • fd_accept_close_on_exec()
  • macOS では pipe() / socket() / accept() の後に fcntl()
    FD_CLOEXEC と必要な O_NONBLOCK を設定。
  • Linux では既存の pipe2() / eventfd() / accept4() を維持。
  • common、conmgr、slurmstepd、srun、salloc、scrun、PMI2、PMIx、cgroup v1
    などの呼び出しを wrapper へ置換。

状態: 部分確認。通常の slurmd 通信、batch job、signal、scancel 経路は
動作した。ただし macOS の pipe/socket/accept から fcntl までの処理は
Linux の atomic な CLOEXEC 設定と完全には同等でなく、並行 fork/exec 時の
descriptor leak 競合は未評価である。MPI/PMIx、salloc、scrun の個別実行も
未確認。

POSIX realtime timer 非対応

症状:

error: unknown type name 'timer_t'
error: call to undeclared function 'timer_create'
error: call to undeclared function 'timer_settime'
error: call to undeclared function 'timer_delete'

修正:

  • configure で timer_create() を検出し、HAVE_TIMER_CREATE を定義。
  • 非対応環境では pthread_cond_timedwait() を使う専用 timer thread で
    conmgr の遅延処理を起床させる。

状態: 部分確認。slurmd 起動・登録・通常ジョブ経路は進行したため基本経路
は通っている。一方、多数の遅延処理、deadline 更新競合、reconfigure、長時間
運転、終了処理を含む stress test は未実施。

socket listener 判定

症状:

fatal: init_sack_conmgr: [fd:6] conmgr rejected socket: Protocol not available

原因:

Darwin では SO_ACCEPTCONN が定義されていても getsockopt()
ENOPROTOOPT を返す経路がある。

修正:

  • src/conmgr/con.c で listener 状態に「不明」を追加。
  • macOS の ENOPROTOOPT は、呼び出し側が listener API を選択済みであること
    を前提に受理。

状態: 確認済み。修正後に auth/slurm 初期化を越えて slurmd が起動した。
ただし socket 種別を網羅する単体テストは未実施。

auth/slurm SACK runtime directory と peer credential

症状:

  • macOS に Linux 標準の /run がなく、SACK socket の作成に失敗。
  • Linux の SO_PEERCRED は macOS で使えない。

修正:

  • macOS の SACK root を /var/run、他 OS は /run とする共通定義を
    src/common/sack_api.h に追加。
  • client と daemon の SACK socket path を共通定義へ統一。
  • macOS の peer UID/GID/PID は LOCAL_PEERCREDLOCAL_PEERPID で取得。
  • sackd の default run directory も OS 依存化。

Slurm公式のAuthentication Plugins
では、auth/slurm / cred/slurm、全daemon間で共有する slurm.key、SACKの
役割が説明されています。公式手順のruntime directoryはLinuxの /run を前提
としているため、今回macOSだけを /var/run へ分岐しました。

状態: 確認済み。slurmd は auth/slurmslurm.key をロードし、batch
step は /var/run/slurm/sack.socket へ接続できた。実 key の内容は本記事および
リポジトリへ保存しない。

setresuidsetresgidfexecve

原因:

macOS には Linux と同じ setresuid() / setresgid() がなく、今回の経路では
fexecve() を利用しない。

修正:

  • 即時 execve() または即時終了する child helper に限定し、macOS では
    setuid() / setgid() で恒久的に権限を落とす。
  • Linux では既存の setresuid() / setresgid() / fexecve() を維持。
  • trigger helper と slurmd の user I/O helper にも feature detection を適用。

状態: 部分確認testuser の batch job は実行できた。補助グループ、複数
ユーザー、失敗時復旧、全 trigger 経路の権限境界は未確認。

pthread object の初期化

症状:

fatal: _atfork_child: pthread_rwlock_init(): Resource busy
scancel: fatal: _add_delay: pthread_mutex_lock(): Invalid argument

修正:

  • fork 後の macOS child では inherited rwlock を
    PTHREAD_RWLOCK_INITIALIZER で置換。
  • scancelmax_delay_lockPTHREAD_MUTEX_INITIALIZER で静的初期化。
  • slurmstepd の io_condio_mutex を明示的に初期化。

状態: 確認済み(観測した経路)。Job 11 は実行中に scancel 11 で停止し、
sacct では job が CANCELLED、batch step が signal 15 で CANCELLED
記録された。高並行度での繰り返し cancel は未確認。

macOS の uptime

症状:

UpTime=20704-06:25:51

原因:

kern.boottime が返す値は経過秒数ではなく Epoch の boot timestamp だが、
旧処理はそれを uptime として扱っていた。

修正:

  • sysctlbyname("kern.boottime") で boot time を取得。
  • time(NULL) - boot_time.tv_sec を経過秒数として返す。
  • future timestamp、型サイズ不一致、UINT32_MAX overflow を検査。

状態: 確認済み。修正後の slurmd ログでは Uptime=2742627
Uptime=2800027 の現実的な経過秒数が登録された。

/proc OOM adjustment と memory rlimit

症状:

error: /proc/self/oom_adj not found
fatal: _prlimit(RLIMIT_RSS, 131072 MB): Invalid argument
error: opendir(/proc): No such file or directory

修正:

  • macOS では Linux /proc の OOM adjustment を no-op とする。
  • Darwin で意味が異なり有限値を拒否する RLIMIT_RSS / RLIMIT_AS
    job memory limit 設定を行わない。
  • process group 列挙は proctrack/pgidsysctl(KERN_PROC_PGRP) を使う。

状態: 部分確認。修正後に batch job、cancel job、MLX GPU job が完走した
ため、観測した fatal error は解消した。一方、macOS では Linux cgroup 相当の
memory enforcement を実装していない。--mem は scheduler 上の割当値であり、
プロセスの実メモリ使用量を kernel で強制制限するものではない。

PTY と macOS header 差分

修正:

  • macOS では PTY API 用に <util.h> を使用。
  • get_current_dir_name()getcwd() へ置換。
  • signal 上限を SIGRTMAX 固定ではなく SLURM_SIGNAL_MAX で抽象化。
  • DNS resolver の C_IN / T_SRVns_c_in / ns_t_srv へ変更。
  • BSD 系の SOL_TCPIPPROTO_TCP へ対応付け。
  • 非 Linux の dev_tuint64_t へ明示変換して format warning を解消。

状態: ビルド確認または部分確認。通常 batch は動作したが、修正後の
srun --pty bash、PMI/PMIx、scrun、全 signal 番号は未確認。

Mach-O plugin の未解決 symbol

症状:

topology_flat.so: symbol not found in flat namespace '_idle_node_bitmap'
accounting_storage_slurmdbd.so: symbol not found in flat namespace '_assoc_cache_cond'

修正:

  • topology/common/eval_nodes.cidle_node_bitmap を macOS では
    weak_import 宣言。
  • slurmdbd_agent.crunning_cacheassoc_cache_mutex
    assoc_cache_cond も、client command に plugin がロードされる場合を考慮し
    weak_import 宣言。

状態: 部分確認

  • topology/flat は slurmd でロード成功。
  • nm -m -u accounting_storage_slurmdbd.so では3 symbol が weak external。
  • sinfo / squeue は plugin をロードして正常表示。
  • sacct は SlurmDBD 接続後に結果を表示。

ただし、これは観測された symbol を個別に弱参照へした修正であり、Slurm の
全 plugin が親 process と同一 global state を正しく共有することの証明では
ない。dyld、flat namespace、plugin state sharing は本移植の重要な未完了課題。

SlurmDBD と MariaDB

症状:

failed to send persistent connection init message to ubuntu2504:6819
Connection refused

切り分け結果:

  • macOS client の plugin load 問題と、TCP 6819 の connection refused は別問題。
  • Ubuntu 上の MariaDB は 127.0.0.1 では接続できたが、当初 hostname
    ubuntu2504 宛てでは接続できなかった。
  • SlurmDBD の DB 接続先と listener を修正・再起動した後、
    0.0.0.0:6819 LISTEN と Mac からの TCP 接続に成功。

状態: 確認済み(現在の単一環境)

slurmdbd(primary) at ubuntu2504 is UP

sacctSLURM_CONF=/opt/slurm/26.11.0/etc/slurm.conf を明示した場合に成功。
環境変数なしでは localhost:6819 を参照した事例があり、default config path
探索または利用環境の統一は未解決。

GRES と Apple Metal GPU

GPU検証の目的

GPU検証では、次の3段階を分けて確認しました。

  1. Slurmが gpu:apple:1 をschedulable resourceとして認識する。
  2. job内へ割当結果が SLURM_JOB_GPUS として渡される。
  3. 既存OSSのMLXがApple M5 MaxのMetal GPUを認識し、実際に行列積を完了する。

独自のGPU実行ツールは作成せず、Apple Machine Learning Researchが公開している
MLX 0.32.2を使用しました。Python 3.14.6と
MLXのversionは pyproject.tomluv.lock で固定しています。

ジョブスクリプト

実際に使用した mlx_gpu_smoke.sbatch は次の内容です。

#!/bin/bash
#SBATCH --job-name=mlx_gpu
#SBATCH --partition=debug
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=2
#SBATCH --mem=4G
#SBATCH --time=00:02:00
#SBATCH --output=mlx-gpu-%j.out
#SBATCH --error=mlx-gpu-%j.err
## After registering the Mac GPU as a Slurm GRES, enable this directive:
##SBATCH --gres=gpu:apple:1

set -euo pipefail

readonly JOB_ROOT="${MLX_JOB_ROOT:-/opt/slurm/26.11.0/share/macos-gpu-job}"
readonly PYTHON="${JOB_ROOT}/.venv/bin/python"

if [[ ! -x "${PYTHON}" ]]; then
    echo "MLX uv environment not found: ${PYTHON}" >&2
    exit 2
fi

echo "job_id=${SLURM_JOB_ID:-unknown}"
echo "node=$(hostname)"
echo "python=${PYTHON}"
echo "slurm_job_gpus=${SLURM_JOB_GPUS:-not-configured}"

"${PYTHON}" <<'PY'
import platform
import math
import time

import mlx.core as mx

if not mx.metal.is_available():
    raise SystemExit("Metal backend is not available")

mx.set_default_device(mx.gpu)
mx.random.seed(42)
print(f"machine={platform.machine()}")
print(f"mlx_version={mx.__version__}")
print(f"default_device={mx.default_device()}")
print(f"metal_device={mx.device_info(mx.gpu)}")

n = 4096
a = mx.random.uniform(shape=(n, n), dtype=mx.float16)
b = mx.random.uniform(shape=(n, n), dtype=mx.float16)
mx.eval(a, b)

# Warm up Metal kernel compilation before measuring.
c = mx.matmul(a, b, stream=mx.gpu)
mx.eval(c)
mx.synchronize(mx.gpu)

started = time.perf_counter()
for _ in range(5):
    c = mx.matmul(a, b, stream=mx.gpu)
    mx.eval(c)
mx.synchronize(mx.gpu)
elapsed = time.perf_counter() - started

mean_value = float(mx.mean(c.astype(mx.float32)).item())
if not math.isfinite(mean_value):
    raise SystemExit(f"GPU result is not finite: {mean_value}")

print(f"matrix_shape={n}x{n}")
print("iterations=5")
print(f"elapsed_seconds={elapsed:.6f}")
print(f"mean_value={mean_value:.6e}")
print("gpu_smoke_test=PASS")
PY

検証条件は次のとおりです。

条件
Python 3.14.6、uv管理環境
MLX 0.32.2
device指定 mx.set_default_device(mx.gpu)
行列shape 4096 × 4096
dtype float16
random seed 42
warm-up 行列積1回
計測 行列積5回の合計時間
完了同期 mx.eval()mx.synchronize(mx.gpu)
最低成功条件 Metal使用可能、結果の平均が有限値、exit status 0

このスクリプトはGPUの smoke test です。CPUとの比較、反復間の分散、
消費電力、GPU使用率、memory帯域、温度、長時間のthermal throttlingは測定して
いないため、性能benchmarkとしては扱いません。

GRES登録前: Job 12

まず --gres を指定せず、Slurm jobからMLX/Metalを実行できるか確認しました。
次は同じ条件を再現する投入コマンドです。

SLURM_CONF=/opt/slurm/26.11.0/etc/slurm.conf \
  /opt/slurm/26.11.0/bin/sbatch \
  /opt/slurm/26.11.0/share/macos-gpu-job/mlx_gpu_smoke.sbatch

結果:

job_id=12
node=PC-210.local
python=/opt/slurm/26.11.0/share/macos-gpu-job/.venv/bin/python
slurm_job_gpus=not-configured
machine=arm64
mlx_version=0.32.2
default_device=Device(gpu, 0)
metal_device={'device_name': 'Apple M5 Max', 'max_recommended_working_set_size': 115448725504, 'memory_size': 137438953472, 'architecture': 'applegpu_g17s', 'max_buffer_length': 86586540032, 'resource_limit': 499000}
matrix_shape=4096x4096
iterations=5
elapsed_seconds=0.019517
mean_value=1.023572e+03
gpu_smoke_test=PASS

この時点で分かったのは、slurmstepd から起動された testuser のprocessが
MLXをimportし、Metal GPUで計算できることです。しかし
slurm_job_gpus=not-configured なので、SlurmはGPUをresourceとして割り当てて
いません。複数jobが同時にGPUを利用できる状態でした。

GRES設定時に発生したエラー

最初は PartitionNameGres=gpu:apple:1 を記述し、次のparse errorに
なりました。

Parsing error at unrecognized key: Gres
Parse error ... PartitionName=debug ... Gres=gpu:apple:1

GresTypes=gpu はglobal設定、Gres=gpu:apple:1NodeName=PC-210
resource設定として分離しました。GRES pluginの変更は scontrol reconfigure
だけでは反映されず、今回の環境ではslurmctld restartも必要でした。

その後の最初の投入では、controller側にGRESがまだ反映されておらず、次の
エラーになりました。

sbatch: error: Invalid generic resource (gres) specification

controllerが要求を受理する段階まで進んだ後も、Job 13は PD、PC-210は
INVAL になりました。

JOBID PARTITION NAME    USER     ST NODELIST(REASON)
13    debug     mlx_gpu testuser PD (Nodes required for job are DOWN, DRAINED ...)

PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
debug*    up    infinite  1     inval PC-210

slurmdログでは、原因が次のように記録されていました。

Can not stat gres.conf file (/opt/slurm/26.11.0/etc/gres.conf), using slurm.conf data
Ignoring file-less GPU gpu:apple from final GRES list

Slurm の特別な gres/gpu plugin は File のないconfig-only GPUを削除します。
公式gres.confマニュアルにも、typed
GPU GRESでは File が必須と記載されています。
Metal GPU は Unix device node を公開しないため、PC-210 の gres.conf に次を
設定した。

NodeName=PC-210 Name=gpu Type=apple File=/dev/null

/dev/null は Slurm に1件のGPU allocation recordを保持させるために今回採用
した PoC固有のplaceholder であり、公式にApple GPU向けとして推奨された
設定ではありません。実際のMetal deviceでもsecurity boundaryでもありません。

slurmd -G の確認結果:

Gres Name=gpu Type=apple Count=1 Index=0 ID=7696487 File=/dev/null Links=(null) Flags=HAS_FILE,HAS_TYPE,ENV_NVML,ENV_RSMI,ENV_ONEAPI,ENV_OPENCL,ENV_DEFAULT

Ignoring file-less GPU が消え、gpu:apple:1 がIndex 0として保持されました。

GRES登録後: Job 15

GPUをSlurm resourceとして要求して投入しました。スクリプト側のGRES directive
はコメントのままとし、今回の要求はCLIから指定しています。次は同じ条件を
再現する投入コマンドです。

SLURM_CONF=/opt/slurm/26.11.0/etc/slurm.conf \
  /opt/slurm/26.11.0/bin/sbatch \
  --gres=gpu:apple:1 \
  /opt/slurm/26.11.0/share/macos-gpu-job/mlx_gpu_smoke.sbatch

結果:

job_id=15
node=PC-210.local
python=/opt/slurm/26.11.0/share/macos-gpu-job/.venv/bin/python
slurm_job_gpus=0
machine=arm64
mlx_version=0.32.2
default_device=Device(gpu, 0)
metal_device={'device_name': 'Apple M5 Max', 'max_recommended_working_set_size': 115448725504, 'memory_size': 137438953472, 'architecture': 'applegpu_g17s', 'max_buffer_length': 86586540032, 'resource_limit': 499000}
matrix_shape=4096x4096
iterations=5
elapsed_seconds=0.014450
mean_value=1.023572e+03
gpu_smoke_test=PASS

状態: 確認済み(GPU 1 jobのsmoke test)。SlurmがGPU 0を割り当て、
MLXがApple M5 Max / Metalで行列積を実行しました。

Job 12とJob 15の比較

項目 Job 12: GRESなし Job 15: GRESあり
SLURM_JOB_GPUS not-configured 0
MLX default device GPU 0 GPU 0
device name Apple M5 Max Apple M5 Max
4096×4096 matmul 5回 5回
elapsed 0.019517秒 0.014450秒
mean 1.023572e+03 1.023572e+03
判定 PASS PASS

elapsedはJob 15の方が短いものの、各条件1回しか測定しておらず、background
loadやGPU clock、thermal stateも記録していません。また、GRESはresource
allocationを管理する機能であり、行列積を高速化する機能ではありません。
したがって、この差を性能改善とは評価しません。

結果の考察

今回の結果から直接確認できることは次のとおりです。

  1. Slurm jobからMetalへ到達できる

    mx.metal.is_available() を通過し、default_device=Device(gpu, 0)
    Apple M5 Maxのdevice情報を取得しました。さらに mx.eval()
    mx.synchronize() の後に有限値の結果を得ているため、単なるdevice列挙では
    なくGPU計算が完了しています。

  2. GRES割当がjob環境へ渡っている

    Job 12では SLURM_JOB_GPUS が未設定、Job 15では 0 でした。この差から、
    --gres=gpu:apple:1 によるSlurm側の割当がjob environmentへ反映されたことを
    確認できます。

  3. GPU使用とGRES割当は別の仕組み

    Job 12もGPUで成功したため、MLXがMetalを使うためにGRESは必須では
    ありません。実際のGPU選択は mx.set_default_device(mx.gpu) が行い、GRESは
    schedulerが「このjobへGPUを1つ割り当てた」と管理するために使われます。

  4. 同一seedで結果の平均は一致した

    Job 12と15はどちらも mean_value=1.023572e+03 でした。ただし、参照CPU
    実装との全要素比較や誤差評価は行っていないため、数値計算の厳密なcorrectness
    testではありません。今回の判定はfinite resultを確認するsmoke testです。

  5. MLXが報告するmemoryはdedicated VRAMではない

    memory_size=137438953472 は128 GiBに相当し、Apple Siliconのunified memory
    を表しています。Linux/NVIDIAの専用VRAMと同じ意味として比較してはいけません。

  6. /dev/null はGPU deviceではない

    File=/dev/null はtyped GPU GRESをSlurm内部に保持させるplaceholderです。
    macOSにはLinux cgroup device isolationがないため、Slurm外のprocessやGRESを
    要求していないjobによるMetal利用を技術的に遮断できません。

未確認:

  • 同時に2件以上を投入した際、gpu:apple:1 が確実に直列化すること。
  • sacct --format=AllocTRESgres/gpu=1 が保存されること。
  • 長時間 GPU job、cancel、timeout、異常終了後に GRES が解放されること。
  • Slurm 外の process からの GPU 利用は隔離できない。
  • Apple GPU の自動検出はなく、台数・型は静的設定。
  • Job 15のstderr全文とprocess exit codeを、記事用Evidenceとして別ファイルへ
    保存すること。
  • CPU実装との数値誤差比較、複数回測定、平均・中央値・標準偏差。

現在の主要設定

PC-210 の /opt/slurm/26.11.0/etc/slurm.conf で確認した主要値:

ClusterName=cluster
SlurmctldHost=ubuntu2504
GresTypes=gpu
ProctrackType=proctrack/pgid
SlurmUser=slurm
SlurmdUser=root
SelectType=select/cons_tres
AccountingStorageHost=ubuntu2504
AccountingStorageType=accounting_storage/slurmdbd
JobAcctGatherType=jobacct_gather/none
NodeName=PC-210 CPUs=18 Boards=1 SocketsPerBoard=1 CoresPerSocket=18 ThreadsPerCore=1 RealMemory=131072 Gres=gpu:apple:1
PartitionName=debug Nodes=PC-210 Default=YES MaxTime=INFINITE State=UP
AuthType=auth/slurm
CredType=cred/slurm

gres.conf:

NodeName=PC-210 Name=gpu Type=apple File=/dev/null

注意点:

  • TaskPlugin=task/none は現在の実ファイルではコメントアウトされている。
    現在の effective default を scontrol show config で保存していないため、
    PoC 方針を明確化するなら明示設定が必要。
  • slurm.conf の現在の mode は 0755 で、実行 bit は不要。通常は 0644
    よい。slurm.key0600 であり、内容は記録しない。
  • slurmd は local -f を指定している一方、controller は configless operation
    を設定しており、毎回 warning が出ている。設定配布方式は統一されていない。

Git上の変更範囲

初稿作成前のsnapshotでは、origin/master からのtracked差分は次の規模です。

71 files changed, 2201 insertions(+), 192 deletions(-)

この中にはコミット済み a77367bb48 と、その後の未コミット修正が含まれる。
さらに次の未追跡成果物がある。

  • etc/launchd/: launchd service 用 plist、installer、設定例
  • contribs/macos-gpu-job/: MLX smoke job、uv lock、GRES 設定例、README
  • .kiro/specs/macos-build-compatibility-fix/: 設計・task 資料
  • doc/要件定義.md: 初期要件資料

パッチへ含めない生成物・ローカル状態:

  • .DS_Store
  • contribs/macos-gpu-job/.venv/
  • src/swait/swait(configure/build 生成物)
  • config.log と build tree の中間生成物
  • /opt/slurm/... の実設定、ログ、spool、key

動作確認マトリクス

対象 状態 根拠または不足
configure 確認済み config.log が exit 0
make / make install 部分確認 インストール済み実体と job 成功あり。ただし clean tree からの最終再ビルド記録なし
slurmd -C CPU/Memory 確認済み macOS workerで18 CPU、131072 MBを認識
uptime 確認済み Epoch 誤表示が現実的な経過秒数へ修正
serializer/json 確認済み serializer_json.so load log
auth/slurm / slurm.key 確認済み daemon と step の認証処理が成功
SACK /var/run 確認済み step が /var/run/slurm/sack.socket へ接続
slurmd → slurmctld 登録 確認済み Ubuntu headへPC-210を登録し、jobを割当
sinfo / squeue 確認済み client plugin load 後に正常表示
sbatch 確認済み Job 11、12、15 の実行経路
scancel 確認済み Job 11 が CANCELLED
sacctmgr ping 確認済み SlurmDBD UP
sacct 確認済み Job 11 の job/step record を表示
srun hostname 未確認 以前の Job 5 は実行されず、修正後の再試験結果なし
srun --pty bash 未確認 hang 後の最終再試験結果なし
user identity 部分確認 testuser job は動作。head/worker の ユーザ UID/GID 不一致は残る
proctrack/pgid 部分確認 cancel は成功。孫 process、zombie、大量 process は未試験
CPU binding 対象外 xsetaffinity() は ENOTSUP、task/affinity 未対応
memory enforcement 対象外 cgroup なし、RLIMIT_RSS/AS を macOS では設定しない
job accounting metrics 対象外/未確認 JobAcctGatherType=none
topology/flat 部分確認 slurmd load 成功。全 plugin state sharing は未証明
SlurmDBD plugin 部分確認 client と sacct は動作。全 daemon context は未検証
Metal GPU job 確認済み Job 15、SLURM_JOB_GPUS=0、MLX PASS
GPU 排他 scheduling 未確認 同時投入試験なし
GPU accounting 未確認 Job 15 の AllocTRES 未保存
launchd service 未確認 plist の構文検査のみ。system domain へ未登録
MPI / PMI2 / PMIx 未確認 build portability 修正のみ
scrun / OCI 未確認 build portability 修正のみ
salloc 未確認 event channel 修正後の実行記録なし
slurmrestd 対象外 configure で disabled
HTTP parser 未確認 plugin 不在で HTTP listen disabled の startup log が残る
Linux regression 未確認 Linux 上の build/test 証跡なし
長時間安定性 未確認 restart、負荷、通信断、再登録を含む soak test なし
macOS版 slurmctld 対象外 controllerはUbuntu 24.04 / x86-64
macOS版 slurmdbd 対象外 accounting daemonはUbuntu 24.04 / x86-64

launchdの現状

次のファイルは作成済みで、plist の plutil -lint は成功した。

  • etc/launchd/org.schedmd.slurmd.plist
  • etc/launchd/install-slurmd-launchdaemon.sh

しかし、2026-09-09 時点で system/org.schedmd.slurmd は登録されておらず、
/Library/LaunchDaemons/org.schedmd.slurmd.plist も存在しない。

さらに現在の template は次の古い値を含む。

  • prefix: /opt/slurm/26.05
  • node override: -N pc210
  • 現在の実 node: PC-210
  • 現在の prefix: /opt/slurm/26.11.0

したがって launchd は 未導入・未確認。導入前に prefix、NodeName、設定
directory、log/spool ownership、configless/local config 方針を更新する必要が
ある。

自動・静的検査

2026-09-09 に実行した静的検査:

検査 結果
git diff --check PASS
sh -n testsuite/macos_build_compatibility.sh PASS
zsh -n etc/launchd/install-slurmd-launchdaemon.sh PASS
bash -n contribs/macos-gpu-job/mlx_gpu_smoke.sbatch PASS
plutil -lint etc/launchd/org.schedmd.slurmd.plist PASS
uv lock --check --project contribs/macos-gpu-job PASS、3 packages resolved

これは構文と lock consistency の検査であり、daemon 運用や regression test の
代わりではない。

既知の制約

  1. macOS には Linux cgroup がなく、CPU・memory・device の kernel 強制隔離を
    提供していない。
  2. CPU affinity は内部 bitmap のみ。実 process pinning は行わない。
  3. proctrack/pgid は Linux cgroup の process tree tracking と同等ではない。
  4. Metal GPU の /dev/null は count management 用 placeholder であり、GPU
    device access の隔離ではない。
  5. P-core/E-core を均質な18 CPUとして扱っている。
  6. jobacct_gather/none のため、CPU/RSS/I/O の詳細 accounting は取得しない。
  7. 個別 weak_import 修正だけでは plugin architecture 全体の正しさを保証
    できない。
  8. local config と configless が混在しており、設定の正本が一意でない。

優先して行う追加確認

P0: パッチ化前に必須

  1. 現在の dirty worktree から clean build と install をやり直し、使用中 binary
    と source revision の対応を hash で記録する。
  2. origin/master の clean worktree にパッチを適用し、git apply --check
    configure、build を実行する。
  3. Linux で configure/build/client smoke test を行い、既存動作に回帰がない
    ことを確認する。
  4. testsuite/macos_build_compatibility.sh の Darwin fix、aggregate diagnostics、
    Linux preservation の各モードを実行し、manifest を保存する。
  5. generated configure / Makefile.inautoreconf で再生成可能か確認する。
  6. ヘッドノードで次を実行し、Ubuntu 24.04 / x86-64の一次出力を記事Evidence
    として保存する。
uname -m
. /etc/os-release
printf '%s\n' "$PRETTY_NAME"
/usr/local/slurm/26.11.0/sbin/slurmctld -V
/usr/local/slurm/26.11.0/sbin/slurmdbd -V

P1: PoC の機能完了確認

  1. 修正後の srun --partition=debug /bin/hostname
  2. 修正後の srun --pty /bin/bash と端末 resize、Ctrl-C、exit。
  3. 同じ gpu:apple:1 を要求する2 job の同時投入による直列化。
  4. GPU job の正常終了、cancel、timeout、異常終了後の GRES 再利用。
  5. sacct -j 15 --format=JobID,State,AllocTRES,ExitCode,NodeList による GPU
    accounting 確認。
  6. testuser と必要な実利用者について controller/worker の UID、primary GID、
    supplementary groups を比較する。
  7. SlurmDBD、slurmctld、slurmd の再起動後にも認証・accounting・job 実行が
    回復することを確認する。

P2: 運用・設計上の追加課題

  1. launchd ファイルを 26.11.0 / PC-210 に更新して service 化する。
  2. configless を採用するか local -f を採用するか決定し、設定正本を一本化。
  3. plugin ごとの親 process global state 共有をテストし、weak import 依存を
    体系的な ABI/API へ置き換える方針を設計。
  4. timer fallback と FD wrapper の concurrency/stress test。
  5. proctrack/macostask/macosjobacct_gather/macos の要否と実装設計。
  6. Apple Silicon の P-core/E-core と memory pressure を扱う resource model。
  7. HTTP parser の warning を、機能無効時に許容するか build/config で除去するか
    決定。

まとめ

Apple M5 Max / macOS上で、Slurm 26.11.0-0rc1のconfigure、build/install、
auth/slurm、Ubuntu controllerへの登録、batch job、cancel、SlurmDBD接続、
Metal GPU jobまでの slurmd 側PoC経路は成立しました。

ヘッドノードの slurmctld / slurmdbd はUbuntu 24.04 / x86-64で動かして
います。したがって本記事が示したのは、macOSをSlurmクラスタの compute
node
として組み込める可能性であり、Slurmクラスタ全体をmacOSへ移植した
結果ではありません。

ただし、以下をもって Linux と同等の正式対応が完了したとは判断できない。

  • CPU affinity、cgroup、memory enforcement、詳細 job accounting は未実装。
  • interactive srun / PTY の最終成功確認がない。
  • plugin global state sharing の一般解はなく、観測された symbol の個別対応。
  • Linux regression と clean patch reproduction が未実施。
  • launchd service は古い prefix の draft で、まだ導入されていない。
  • GPU は scheduling count と Metal 実行までで、device isolation や長時間安定性
    は未確認。

したがって現在の到達点は、macOS compute nodeとしてbatch/Metal jobを
実行できる実証済みPoC
です。production readyまたはupstream readyでは
ありません。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?