`modifiers/allocation/modifier.py` の `slurm_instructions()` は、起動行を `-n {n_ranks}`、`-N {n_nodes}`、および GPU がある場合の `--gpus {n_gpus}` から 組み立てる。`-c` / `--cpus-per-task` は、実験が `n_threads_per_proc` を設定して いる場合でも一切出力されない。 したがって R ランク × T スレッドの実験は srun -n R -N 1 として起動され、各ランクの cpuset はノード全体になる。R × T 本のスレッドが どこに載るかはノード側の裁量となり、実験からは何も指定されていない。 ジョブは成功し、FOM だけが変わる。すなわち失敗として表面化しない。 **測定** riken-rikyu(2 ソケット、計 144 コアの aarch64 ノード)で genesis(8 ランク × 18 スレッド、1 ノード)を実行した。 - 同一バイナリで、ノードによって FOM 194.304 と 94.252 に分かれた。前者では 144 スレッドの領域が片方のソケットに偏って配置されていた。 - スレッドを広げるノードでもランク同士が重なる。`--cpus-per-task=18` を与えた 場合、5 回の実行が 41.8〜45.0 に収まり、指定なしの最良値の 2 倍以上速い。 **効かない対処** 最初に思いつく `OMP_PROC_BIND=close` と `OMP_PLACES=cores` は解決にならない。 各ランクが依然として 144 CPU すべてを見ているため、`cores` は各ランクで同一の リストを列挙し、`close` はいずれも place 0 から開始する。結果として 8 ランクが CPU 0-17 に重なり、144 スレッドが 18 コアに載る。genesis は 112 秒から 2 時間の タイムアウトになった(3 回中 3 回)。OpenMP の束縛が意味を持つのは、各ランクが 自分の cpuset を持ってからであり、持った後には不要である。 **対応案** 実験が `n_threads_per_proc` を設定している場合に `--cpus-per-task {n_threads_per_proc}` を出力する。`--gpus {n_gpus}` を出力しているのと同じ 考え方であり、`determine_allocation()` は既に同じ値をノード数の算出に用いて いる。 現状では、実験ごとに `extra_cmd_opts` で個別に与えるほかに手段がない。これは modifier が提供する唯一の経路であるが、スレッドを使う実験すべてに同じ指定を 書き写すことになり、書き忘れても何も警告されない。 なお、本件は特定の機械に固有ではない。スレッドを広げるノードでもランクの重なり は生じるため、影響の大きさが機械によって異なるだけである。
Activity