万人のためのハイパフォーマンスコンピューティング

HPC Do It Yourself Club

      HOMEE5-2600v3製品情報お役立ち情報購入案内お問い合わせ会社案内
      ムービーダウンロードドキュメント最新トピックスおもしろLinkHPCノウハウ

4 Node FDR Infiniband Cluster性能評価
OpenMPIとOpenMPのHybrid実行でのMustオプション
OpenMPIで別ノードの環境変数をセットするには

mpirunでrankを自由に配置する方法

 mpiでプログラムを並列実行する際、rankがどのように配置されるかに依って、速度が異なる場合が多い。rank間の通信量が均等でない場合が多いからだ。通信量が多いランク同士はできるだけ同じマシン、可能なら同一ソケットに配置したほうが、高速実行が可能になる。プログラムの作り方にもよるが、ランクの値が隣り合っている間でしか通信を行わない場合もあるだろう。そのような場合、近いランクはできるだけ同じマシン、可能なら同一ソケット内に配置すれば、高速実行が期待できる。
 mpirunでrankがどのように配置されるかを知るために、ランク、マシン名、ソケット番号、コア番号を表示する簡単なプログラムを作った。
[hpc@hpc01 mpi]$ cat rankmap.c
/*
* Copyright (c) 2012 Kenetsu Hanabusa
* HPC Do It Yourself Club
* HPC Systems Inc.
*
* Print Ramk Map application in C
*/

#include "mpi.h"
#include 
#include 
#include 

#define SIZE (1024*1024)
#define NUM_CPUS_PER_SOCKET 8

int main(int argc, char* argv[])
{
int rank, size, cpu1, cpu2;
float *array;
int i;
char name[80];
int nlen;

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Get_processor_name(name, &nlen);
cpu1 = sched_getcpu();
array = (float *)malloc(sizeof(float)*SIZE);
for (i = 0; i < SIZE; i++)
array[i] = 0.0;
cpu2 = sched_getcpu();
printf("rank=%2d machine=%5s socket=%1d start-core=%2d end-core=%2d size=%d\n", rank, name,
cpu2/NUM_CPUS_PER_SOCKET, cpu1, cpu2, size);
MPI_Finalize();

return 0;
}

このプログラムは、ランクとマシン名、ソケット番号、コア番号を1行にプリントする。マシン名はhpc01とhpc02、ソケット番号は0と1、コア番号は0から15になる。コア番号の0から7がソケット0上に、8から15がソケット1上にある。プログラムの途中で、メモリーを確保して0クリアしている。理由は、何もしないプログラムを作ったところ、異なるランクに1つのコアが割り当てられたので、適当に何かする部分を入れて、コアの重複を回避したためだ。
 使っているマシンは、HPCDIY-SWS87-8GB8を2台接続したクラスターだ。それぞれにはCPUとしてE5-2687Wが2個、各8コアで合計16コアが搭載されている。マシン名は、hpc01とhpc02にしてある。MPIはOpenMPI1.6.2を使用している。他のMPIでは試していないので、この記事と異なる可能性があることをお断りしておく。
 上記のプログラムをコンパイルする。
[hpc@hpc01 mpi]$ mpicc rankmap.c -o rankmap
2台のマシンで全コアを使って実行してみよう。出力結果をソートして見やすくしてある。
[hpc@hpc01 mpi]$ mpirun -H hpc01,hpc02 -np 32 rankmap|sort
rank= 0 machine=hpc01 socket=0 start-core= 6 end-core= 6 size=32
rank= 1 machine=hpc02 socket=1 start-core= 8 end-core= 8 size=32
rank= 2 machine=hpc01 socket=0 start-core= 5 end-core= 5 size=32
rank= 3 machine=hpc02 socket=1 start-core=10 end-core=10 size=32
rank= 4 machine=hpc01 socket=0 start-core= 1 end-core= 1 size=32
rank= 5 machine=hpc02 socket=0 start-core= 7 end-core= 7 size=32
rank= 6 machine=hpc01 socket=0 start-core= 7 end-core= 7 size=32
rank= 7 machine=hpc02 socket=1 start-core= 9 end-core= 9 size=32
rank= 8 machine=hpc01 socket=0 start-core= 4 end-core= 4 size=32
rank= 9 machine=hpc02 socket=0 start-core= 5 end-core= 5 size=32
rank=10 machine=hpc01 socket=0 start-core= 7 end-core= 7 size=32
rank=11 machine=hpc02 socket=0 start-core= 3 end-core= 3 size=32
rank=12 machine=hpc01 socket=1 start-core=12 end-core=12 size=32
rank=13 machine=hpc02 socket=0 start-core= 2 end-core= 2 size=32
rank=14 machine=hpc01 socket=1 start-core= 8 end-core= 8 size=32
rank=15 machine=hpc02 socket=1 start-core=10 end-core=10 size=32
rank=16 machine=hpc01 socket=1 start-core=11 end-core=11 size=32
rank=17 machine=hpc02 socket=1 start-core=13 end-core=13 size=32
rank=18 machine=hpc01 socket=0 start-core= 2 end-core= 2 size=32
rank=19 machine=hpc02 socket=0 start-core= 4 end-core= 4 size=32
rank=20 machine=hpc01 socket=0 start-core= 3 end-core= 3 size=32
rank=21 machine=hpc02 socket=0 start-core= 6 end-core= 6 size=32
rank=22 machine=hpc01 socket=1 start-core=10 end-core=10 size=32
rank=23 machine=hpc02 socket=0 start-core= 0 end-core= 0 size=32
rank=24 machine=hpc01 socket=0 start-core= 3 end-core= 3 size=32
rank=25 machine=hpc02 socket=1 start-core=14 end-core=14 size=32
rank=26 machine=hpc01 socket=0 start-core= 2 end-core= 2 size=32
rank=27 machine=hpc02 socket=1 start-core=12 end-core=12 size=32
rank=28 machine=hpc01 socket=1 start-core= 9 end-core= 9 size=32
rank=29 machine=hpc02 socket=1 start-core=11 end-core=11 size=32
rank=30 machine=hpc01 socket=0 start-core= 0 end-core= 0 size=32
rank=31 machine=hpc02 socket=1 start-core=15 end-core=15 size=32

mpirunで何も指定しないと、rank0はhpc01に、rank1はhpc02に、以下同様に割り当てられている。これだと隣接ランクが別のマシンになって、速度向上の目的を達成できないかもしれない。
 隣接ランクを出来れば同一マシン、可能なら同一ソケットに配置するには、mpirunのオプションの-npersocketを使ってみたらうまく行った。-npersocketオプションを使う場合、-num-sockets 2で1マシン中に2ソケットが存在することをmpirunに教えてあげないといけないようだ。
[hpc@hpc01 mpi]$ mpirun -H hpc01,hpc02 -np 32 -npersocket 8 -num-sockets 2 rankmap|sort
rank= 0 machine=hpc01 socket=0 start-core= 0 end-core= 0 size=32
rank= 1 machine=hpc01 socket=0 start-core= 7 end-core= 7 size=32
rank= 2 machine=hpc01 socket=0 start-core= 1 end-core= 1 size=32
rank= 3 machine=hpc01 socket=0 start-core= 2 end-core= 2 size=32
rank= 4 machine=hpc01 socket=0 start-core= 3 end-core= 3 size=32
rank= 5 machine=hpc01 socket=0 start-core= 4 end-core= 4 size=32
rank= 6 machine=hpc01 socket=0 start-core= 3 end-core= 3 size=32
rank= 7 machine=hpc01 socket=0 start-core= 6 end-core= 6 size=32
rank= 8 machine=hpc01 socket=1 start-core=13 end-core=13 size=32
rank= 9 machine=hpc01 socket=1 start-core=11 end-core=11 size=32
rank=10 machine=hpc01 socket=1 start-core= 9 end-core= 9 size=32
rank=11 machine=hpc01 socket=1 start-core=12 end-core=12 size=32
rank=12 machine=hpc01 socket=1 start-core=14 end-core=14 size=32
rank=13 machine=hpc01 socket=1 start-core=10 end-core=10 size=32
rank=14 machine=hpc01 socket=1 start-core=15 end-core=15 size=32
rank=15 machine=hpc01 socket=1 start-core= 8 end-core= 8 size=32
rank=16 machine=hpc02 socket=0 start-core= 6 end-core= 6 size=32
rank=17 machine=hpc02 socket=0 start-core= 2 end-core= 2 size=32
rank=18 machine=hpc02 socket=0 start-core= 0 end-core= 0 size=32
rank=19 machine=hpc02 socket=0 start-core= 2 end-core= 2 size=32
rank=20 machine=hpc02 socket=0 start-core= 4 end-core= 4 size=32
rank=21 machine=hpc02 socket=0 start-core= 1 end-core= 1 size=32
rank=22 machine=hpc02 socket=0 start-core= 3 end-core= 3 size=32
rank=23 machine=hpc02 socket=0 start-core= 0 end-core= 5 size=32
rank=24 machine=hpc02 socket=1 start-core=13 end-core=13 size=32
rank=25 machine=hpc02 socket=1 start-core= 8 end-core= 8 size=32
rank=26 machine=hpc02 socket=1 start-core= 9 end-core= 9 size=32
rank=27 machine=hpc02 socket=1 start-core=11 end-core=11 size=32
rank=28 machine=hpc02 socket=1 start-core=12 end-core=12 size=32
rank=29 machine=hpc02 socket=1 start-core=15 end-core=15 size=32
rank=30 machine=hpc02 socket=1 start-core=14 end-core=14 size=32
rank=31 machine=hpc02 socket=1 start-core=10 end-core=10 size=32

rank0からrank15までがhpc01に、rank16からrank31までがhpc02上になった。更にrank0からrank7までがソケット0上、rank8からrank15までがソケット1上になり、その先も同様である。ソケット中のコアの順番は揃っていないが、実行速度には悪影響を与えない。
 私には自己満足という理由しか思いつかないが、何ら名の理由で、コアの順番も揃えたい場合があるかもしれない。その場合は、ちょっと面倒だが、ランクファイルというものを作り、mpirunの-rfオプションでランクファイルを指定すればいい。ランクファイルの内容は次のようにする。
[hpc@hpc01 mpi]$ cat rankfile
rank 0=hpc01 slot=0:0
rank 1=hpc01 slot=0:1
rank 2=hpc01 slot=0:2
rank 3=hpc01 slot=0:3
rank 4=hpc01 slot=0:4
rank 5=hpc01 slot=0:5
rank 6=hpc01 slot=0:6
rank 7=hpc01 slot=0:7
rank 8=hpc01 slot=1:0
rank 9=hpc01 slot=1:1
rank 10=hpc01 slot=1:2
rank 11=hpc01 slot=1:3
rank 12=hpc01 slot=1:4
rank 13=hpc01 slot=1:5
rank 14=hpc01 slot=1:6
rank 15=hpc01 slot=1:7
rank 16=hpc02 slot=0:0
rank 17=hpc02 slot=0:1
rank 18=hpc02 slot=0:2
rank 19=hpc02 slot=0:3
rank 20=hpc02 slot=0:4
rank 21=hpc02 slot=0:5
rank 22=hpc02 slot=0:6
rank 23=hpc02 slot=0:7
rank 24=hpc02 slot=1:0
rank 25=hpc02 slot=1:1
rank 26=hpc02 slot=1:2
rank 27=hpc02 slot=1:3
rank 28=hpc02 slot=1:4
rank 29=hpc02 slot=1:5
rank 30=hpc02 slot=1:6
rank 31=hpc02 slot=1:7

これを使い次のように実行する。
[hpc@hpc01 mpi]$ mpirun -H hpc01,hpc02 -np 32 -rf rankfile rankmap|sort
rank= 0 machine=hpc01 socket=0 start-core= 0 end-core= 0 size=32
rank= 1 machine=hpc01 socket=0 start-core= 1 end-core= 1 size=32
rank= 2 machine=hpc01 socket=0 start-core= 2 end-core= 2 size=32
rank= 3 machine=hpc01 socket=0 start-core= 3 end-core= 3 size=32
rank= 4 machine=hpc01 socket=0 start-core= 4 end-core= 4 size=32
rank= 5 machine=hpc01 socket=0 start-core= 5 end-core= 5 size=32
rank= 6 machine=hpc01 socket=0 start-core= 6 end-core= 6 size=32
rank= 7 machine=hpc01 socket=0 start-core= 7 end-core= 7 size=32
rank= 8 machine=hpc01 socket=1 start-core= 8 end-core= 8 size=32
rank= 9 machine=hpc01 socket=1 start-core= 9 end-core= 9 size=32
rank=10 machine=hpc01 socket=1 start-core=10 end-core=10 size=32
rank=11 machine=hpc01 socket=1 start-core=11 end-core=11 size=32
rank=12 machine=hpc01 socket=1 start-core=12 end-core=12 size=32
rank=13 machine=hpc01 socket=1 start-core=13 end-core=13 size=32
rank=14 machine=hpc01 socket=1 start-core=14 end-core=14 size=32
rank=15 machine=hpc01 socket=1 start-core=15 end-core=15 size=32
rank=16 machine=hpc02 socket=0 start-core= 0 end-core= 0 size=32
rank=17 machine=hpc02 socket=0 start-core= 1 end-core= 1 size=32
rank=18 machine=hpc02 socket=0 start-core= 2 end-core= 2 size=32
rank=19 machine=hpc02 socket=0 start-core= 3 end-core= 3 size=32
rank=20 machine=hpc02 socket=0 start-core= 4 end-core= 4 size=32
rank=21 machine=hpc02 socket=0 start-core= 5 end-core= 5 size=32
rank=22 machine=hpc02 socket=0 start-core= 6 end-core= 6 size=32
rank=23 machine=hpc02 socket=0 start-core= 7 end-core= 7 size=32
rank=24 machine=hpc02 socket=1 start-core= 8 end-core= 8 size=32
rank=25 machine=hpc02 socket=1 start-core= 9 end-core= 9 size=32
rank=26 machine=hpc02 socket=1 start-core=10 end-core=10 size=32
rank=27 machine=hpc02 socket=1 start-core=11 end-core=11 size=32
rank=28 machine=hpc02 socket=1 start-core=12 end-core=12 size=32
rank=29 machine=hpc02 socket=1 start-core=13 end-core=13 size=32
rank=30 machine=hpc02 socket=1 start-core=14 end-core=14 size=32
rank=31 machine=hpc02 socket=1 start-core=15 end-core=15 size=32

コアの順番も綺麗に揃った。
ランクファイルを使えば、ランクの配置を自由自在に設定できるということになる。

(次回に続く)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Copyright (C) HPCシステムズ株式会社. All Rights Reserved.