2021.05.13版クラウドシステム向けのプロセス・スレッド配置方法(Type II c Intelコンパイラ+Intel MPIを使う場合も参考にしてください) • 2020.08.27初版公開• 2021.03.05一部更新• 2021.03.26 細かい修正• 2021.05.11 cx-shareおよびcl-share利用時の注意点を追加• 2021.05.13 I_MPI_DEBUG出力情報を追加2
変数等で指定する資源割り当て情報に齟齬があると問題が起きます–性能が低下したり、プログラムが実行できなかったりすることがあります
ようにしてください•ジョブ実行時にはプログラム実行前に unset I_MPI_PIN_DOMAIN を実行するようにしてください#!/bin/bash -x #PJM -L rscgrp=cx-share #PJM -L elapse=00:10:00 #PJM -j #PJM -S module load intel unset I_MPI_PIN_DOMAIN mpiexec -n …… #!/bin/bash -x #PJM -L rscgrp=cl-share #PJM -L elapse=00:10:00 #PJM -j #PJM -S module load intel unset I_MPI_PIN_DOMAIN mpiexec -n ……
• Intel Xeon CPUのみ搭載のクラウドシステムではIntelコンパイラ+Intel MPIの利用が基本• 20コアXeon×4ソケット環境のため「4プロセス」×「1プロセスあたり20スレッド」が基本の実行形態となる–もちろん、80スレッドOpenMP並列実行や80プロセスMPI実行を行っても構わないが、 1プロセス中のスレッドが複数のCPUソケットにまたがらない実行が基本となる•他のソケットにつながったメモリへのアクセスは遅くなるため、ソケットローカルのメモリを優先して使いたい→ numactl -lの指定は基本•ネットワークにつながっているCPUがCPU0として扱われる
ノード間ネットワーク

•  環境変数OMP_NUM_THREADSとKMP_AFFINITYの組み合わせにより指定する.
基本の配置方法は以下の三つ
— KMP_AFFINITY=granularity=fine,compact o — KMP_AFFINITY=granularity=fine,scatter o — KMP_AFFINITY=granularity=fine,balanced_
– compactは、まずソケット0の全コアを埋める、次はソケット1、……という配置– scatterとbalancedは全ソケットに均等になるような配置、ただし配置順序が図のように異なる–実行するプログラムにあわせて選べば良い：balancedの方が隣接プロセス間通信の性能が期待できる配置と言える※コンパイラのドキュメントを見るとbalancedは使えないようなのだが、試してみたら使えた• 「This affinity type is supported on the CPU only for single socket systems.」と書かれているため、1ソケットの環境でないと使えない気がするのだが？
• verboseオプション指定時の情報出力の例
— KMP_AFFINITY=verbose,granularity=fine,compact OMP: Info #154: KMP_AFFINITY: Initial OS proc set respected: 0-79 OMP: Info #213: KMP_AFFINITY: decoding x2APIC ids. OMP: Info #276: KMP_AFFINITY: Affinity capable, using global cpuid leaf 11 info OMP: Info #156: KMP_AFFINITY: 80 available OS procs OMP: Info #157: KMP_AFFINITY: Uniform topology OMP: Info #191: KMP_AFFINITY: 4 sockets x 20 cores/socket x 1 thread/core (80 total cores) OMP: Info #215: KMP_AFFINITY: OS proc to physical thread map: OMP: Info #171: KMP_AFFINITY: OS proc 0 maps to socket 0 core 0 OMP: Info #171: KMP_AFFINITY: OS proc 1 maps to socket 0 core 1対応する部分を読み合わせればOMP: Info #171: KMP_AFFINITY: OS proc 2 maps to socket 0 core 2配置がわかるOMP: Info #171: KMP_AFFINITY: OS proc 10 maps to socket 0 core 3 OMP: Info #171: KMP_AFFINITY: OS proc 11 maps to socket 0 core 4 (省略、全80の割り当て情報が並ぶ、coreの数字は一部抜けていたりする) OMP: Info #251: KMP_AFFINITY: pid 70 tid 70 thread 0 bound to 0S proc set 0 OMP: Info #251: KMP_AFFINITY: pid 70 tid 71 thread 1 bound to OS proc set 1 OMP: Info #251: KMP_AFFINITY: pid 70 tid 72 thread 2 bound to OS proc set 2 OMP: Info #251: KMP_AFFINITY: pid 70 tid 73 thread 3 bound to OS proc set 10 6
•環境変数や引数で配置方法を指定する•よく使う設定– 引数-n数字：プロセス数– 引数-ppn数字、もしくは環境変数I_MPI_PERHOST：ノードあたり何プロセス配置したら次のノードへ行くか– 環境変数I  MPI  PIN  DOMAIN：MPIプロセス1つあたりいくつの連続したコアを確保するか•具体的な数字以外にomp（OMP_NUM_THREADSを参照）やauto（総コア数÷プロセス数を参照）も指定できる。OpenMPとのハイブリッド実行を行う場合はKMP_AFFINITYもあわせて指定しないとプロセス内の複数スレッドが同じCPUコアに配置されることがあるため注意。 •フラットMPIの場合はautoを指定すると均等間隔で配置してくれる。 – 環境変数I_MPI_PIN_ORDER：プロセスを配置する順番（compact, scatter, spread, bunch） • compactとscatterはKMP AFFINITYと同様。spreadとbunchはbalanced的な挙動。 –複数コアがL2キャッシュを共有しているとspreadとbunchの配置に差が生じる（同じL2キャッシュを使うコアに優先的に配置するのがbunch、しないのがspread）が、本環境では同じになると思われる。 – 環境変数I  MPI  DEBUG：デバッグレベル（数字を大きくするほど詳細情報が出力される、よく使われるのは5)
• mpiexecのプロセス数に直接影響するのは-nで指定した値であるため、常にmpiexecに-nオプションで本当に起動したいプロセス数を指定するようにしてください•利用手引書では--mpi procとmpiexecの-nでプロセス数を指定しているが、本当に重要な(優先される)のは後者のmpiexecの-nオプション• $PJM_MPI_PROCには--mpi procで指定した値が入ってくる• mpiexecの-nオプションを指定しないと、想定外の数のプロセス数が起動することがあるため注意が必要
• 1ソケット利用時の並列化性能を比較したい場合# 1 socket OpenMP export OMP_NUM_THREADS=2 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} export OMP_NUM_THREADS=4 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} export OMP_NUM_THREADS=8 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} export OMP_NUM_THREADS=16 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} export OMP_NUM_THREADS=20 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} • 1ソケット20スレッドを基準にソケットを増やした際の性能を比較したい場合# 1 socket OpenMP export OMP_NUM_THREADS=20 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} # 2 socket OpenMP export OMP_NUM_THREADS=40 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} # 3 socket OpenMP export OMP_NUM_THREADS=60 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} # 4 socket OpenMP export OMP_NUM_THREADS=80 export KMP_AFFINITY=granularity=fine,compact numactl -l ${BIN} ※${BIN}には実行ファイル名が入っているとするexport BIN=./a.out   などで設定しておく9
ソケットを増やした際の性能を比較したい場合# 1 socket OpenMP export OMP_NUM_THREADS=16 export KMP_AFFINITY=granularity=fine,balanced numactl -l ${BIN} # 2 socket OpenMP export OMP_NUM_THREADS=32 export KMP_AFFINITY=granularity=fine,balanced numactl -l ${BIN} # 3 socket OpenMP export OMP_NUM_THREADS=48 export KMP_AFFINITY=granularity=fine,balanced numactl -l ${BIN} # 4 socket OpenMP export OMP_NUM_THREADS=64 export KMP_AFFINITY=granularity=fine,balanced numactl -l ${BIN} . compactのままでスレッド数を20以下に減らすとソケット内のコアを埋め尽くすまで次のソケットに配置してくれないため、balancedを指定
• 1ソケット内フラットMPIの性能を比較したい場合# 1 socket MPI export I_MPI_PIN_DOMAIN=1 export I_MPI_PIN_ORDER=compact mpiexec -n 1 numactl -l ${BIN} mpiexec -n 2 numactl -l ${BIN} mpiexec -n 4 numactl -l ${BIN} mpiexec -n 8 numactl -l ${BIN} mpiexec -n 16 numactl -l ${BIN} mpiexec -n 20 numactl -l ${BIN} ...... ・ 4ソケットにまたがるフラットMPIの性能を比較したい場合# 4 socket MPI scatter export I_MPI_PIN_DOMAIN=1 export I_MPI_PIN_ORDER=scatter mpiexec -n 4 numactl -l ${BIN} mpiexec -n 8 numactl -l ${BIN} mpiexec -n 16 numactl -l ${BIN} mpiexec -n 20 numactl -l ${BIN} # 4 socket MPI, balanced? export I_MPI_PIN_DOMAIN=10 export I_MPI_PIN_ORDER=compact mpiexec -n 8 numactl -l ${BIN} export I MPI PIN DOMAIN=5 export I_MPI_PIN_ORDER=compact mpiexec -n 16 numactl -l ${BIN} ↑수I_MPI_PIN_ORDER=compactなのでソケット0のコア0から順番に使われる。20を超える場合はソケット1へ、40を超えるとソケット2へ、以下同様。 I MPI PIN ORDER=scatterなので、ソケット0のコア0→ソケット1のコア0→ソケット2のコア0……と分散して使われる。 ↑ I MPI PIN DOMAINはプロセスを配置する際に1プロセスが占有するコアの数に相当する。これをうまく指定すれば、ソケット0内で均等分散してからソケット1へ……など様々な割り当てが可能。 MPI+OpenMPハイブリッド実行の場合はこれを用いてスレッド配置範囲を調整する。 l l
・ 1ソケット20スレッドを基準にソケットを増やして性能を比較したい場合# 20 thread * 1 socket export OMP_NUM_THREADS=20 export I_MPI_PIN_DOMAIN=20 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 1 numactl -l ${BIN} # 20 thread * 2 socket export OMP_NUM_THREADS=20 export I_MPI_PIN_DOMAIN=20 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 2 numactl -l ${BIN} . # 20 thread * 3 socket export OMP_NUM_THREADS=20 export I_MPI_PIN_DOMAIN=20 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 3 numactl -l ${BIN} # 20 thread * 4 socket export OMP_NUM_THREADS=20 export I_MPI_PIN_DOMAIN=20 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 4 numactl -l ${BIN} .
# 40 thread * 2 process export OMP_NUM_THREADS=40 export I_MPI_PIN_DOMAIN=40 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 2 numactl -l ${BIN} I_MPI_PIN_DOMAIN=20にしているため1プロセスが占有するコア数は必ず20。プロセスあたりのOpenMPスレッド数を減らしたい場合はOMP_NUM_THREADSだけを減らす。（20コア分の枠を確保し、そのうちのxxコアだけを使う、という動作になる。） •補足(気になったので試してみた) I_MPI_PIN_ORDER=scatterを追加してもプロセスの配置順.序だけがscatterになったりはしないようだ。 KMP_AFFINITYをcompactからscatterにしても違いは生じな.いようだ。（プロセス内のスレッド配置順だけscatter的になったりはしなかった。）他の環境変数等との組み合わせのせいという可能性は残る。 . 12
•もっとプロセス数を増やしたハイブリッド実行の例# 10 thread * 8 process export OMP_NUM_THREADS=10 export I_MPI_PIN_DOMAIN=10 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 8 numactl -l ${BIN} # 8 thread * 8 process export OMP_NUM_THREADS=8 export I_MPI_PIN_DOMAIN=10 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 8 numactl -l ${BIN} # 5 thread * 16 process export OMP_NUM_THREADS=5 export I_MPI_PIN_DOMAIN=5 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 16 numactl -l ${BIN} # 4 thread * 16 process export OMP_NUM_THREADS=4 export I_MPI_PIN_DOMAIN=5 export KMP_AFFINITY=granularity=fine,compact mpiexec -n 16 numactl -l ${BIN} .各ソケットに2プロセス配置するなら80コア÷8プロセス=10でプロセスあたり10スレッドとなるが、スレッド数を2の冪乗数にしたいのであればI_MPI_PIN_DOMAINを10のままでOMP_NUM_THREADSを8にするのが良い。 ・各ソケットに4プロセス配置するなら80コア÷16プロセス=5でプロセスあたり5スレッドとなるが、スレッド数を2の冪乗数にしたいのであればI_MPI_PIN_DOMAINを5のままでOMP_NUM_THREADSを4にするのが良い。 13
・ノード数とプロセス数さえ指定すれば均等に分散配置してくれる。 •配置方法を調整したい場合にはパラメタで指定する必要がある。 • OMP_NUM_THREADSも指定されていれば、各プロセスは指定されたスレッド分のコア群に配置される。 •  配置情報を特に指定しないフラットMPI実行の場合、•   I_MPI_PERHOSTを変更すると、この環境変数で指定した数のプロセスを配置してから次のノードヘプまず各ノードのコア0に1プロセスずつ配置、次に各ロセスを配置するようになる。ノードのコア1に1プロセスずつ配置……となる。これはI_MPI_PIN_DOMAINとI_MPI_PERHOSTにともに1 ・ I_MPI_PIN_ORDERをscatterにすると、2周目のコ.ア配置がコア1ではなくコア20など離れた（scatterを指定した状態。的な）配置になる。 • I_MPI_DEBUG=5で確認できるexport OMP NUM THREADS=1 export I_MPI_PIN_DOMAIN=1 export I_MPI_PERHOST=1 mpiexec -n 16 numactl -l ${BIN} export OMP NUM THREADS=1 export I_MPI_PIN_DOMAIN=1 export I_MPI_PERHOST=4 mpiexec -n 16 numactl -l ${BIN} • I_MPI_PIN_DOMAINを増やすと、1プロセス配置する際に確保するコア数が増える。OpenMPのスレッドはその確保した枠内に配置する。 • 1ノードの場合と同様の挙動•次ページ以降に4ノード×8プロセスのバリエーション例を示す。
#!/bin/bash -x #PJM -L rscgrp=cl-extra #PJM -L node=4 #PJM --mpi proc=32 #PJM -L elapse=00:10:00 #PJM -i #PJM -S module load intel export OMP DISPLAY ENV=truel export I MPI DEBUG=5 BIN=./a.out export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} 4ノード、合計32プロセス利用することの宣言。 OpenMPに関する環境変数の情報を細かく表示させるオプションMPIに関する環境変数の情報を細かく表示させるオプションI MPI PIN DOMAIN=10のためプロセスが配置される際の単位は10コア、OMP NUM THREADS=8のためプロセス内のOpenMPに使われるのは8コア。 I MPI PERHOST=1のため、1プロセス配置したら次のノードヘ。 I MPI PIN ORDER=compactのため、ノードにプロセスを配置する際は前回の配置から近いところ。（ノード内のプロセス配置順序だけみたらcompact的。) • numactl -lのため、ソケットから近いメモリだけを使う。 15
Node nameはノードのID、今回は以下のように割り当たっている：
ノード3：dl100
できる。 Pid(プロセスID)はノードローカルなプロセスIDであるため、特に気にしなくて良い。
#!/bin/bash -x #PJM -L rscgrp=cl-extra #PJM -L node=4 #PJM --mpi proc=32 #PJM -L elapse=00:10:00 #PJM -i #PJM -S module load intel export OMP DISPLAY ENV=truel export I MPI DEBUG=5 BIN=./a.out export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} 4ノード、合計32プロセス利用することの宣言。 OpenMPに関する環境変数の情報を細かく表示させるオプションMPIに関する環境変数の情報を細かく表示させるオプション• I MPI PIN DOMAIN=10のためプロセスが配置される際の単位は10コア、OMP NUM THREADS=8のためプロセス内のOpenMPに使われるのは8コア。 • I MPI PERHOST=2のため、2プロセス配置したら次のノードヘ。 I MPI PIN ORDER=compactのため、ノードにプロセスを配置する際は前回の配置から近いところ。（ノード内のプロセス配置順序だけみたらcompact的。) numactl -lのため、ソケットから近いメモリだけを使う。 17
#!/bin/bash -x #PJM -L rscgrp=cl-extra #PJM -L node=4 #PJM --mpi proc=32 #PJM -L elapse=00:10:00 #PJM -i #PJM -S module load intel export OMP DISPLAY ENV=true export I MPI DEBUG=5 BIN=./a.out export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} 4ノード、合計32プロセス利用することの宣言。 OpenMPに関する環境変数の情報を細かく表示させるオプションMPIに関する環境変数の情報を細かく表示させるオプション• I MPI PIN DOMAIN=10のためプロセスが配置される際の単位は10コア、OMP NUM THREADS=8のためプロセス内のOpenMPに使われるのは8コア。 • I MPI PERHOST=1のため、1プロセス配置したら次のノードヘ。 I MPI PIN ORDER=compactのため、ノードにプロセスを配置する際は前回の配置から遠いところ。（ノード内のプロセス配置順序だけみたらscatter的。) • numactl -lのため、ソケットから近いメモリだけを使う。一般的なscatterの割り当て的にはソケット0の次はソケット2に配置されることが期待される気もするが、ソケット間の距離は均等であり、ソケットを埋め尽くす前に次のソケットへ行っているという点で確かにscatter。実際に配置されるコア番号を見てみると、ソケット内で完全に連続したコアが確保されるとは限らない。実例プロセス(ランク)0は「0,1,2,10,11,3,4,12」で8スレッド(ノード0のソケット0上)プロセス(ランク)1も「0,1,2,10,11,3,4,12」で8スレッド(ノード1のソケット0上)
#!/bin/bash -x #PJM -L rscgrp=cl-extra #PJM -L node=4 #PJM --mpi proc=32 #PJM -L elapse=00:10:00 #PJM -i #PJM -S module load intel export OMP DISPLAY ENV=truel export I MPI DEBUG=5 BIN=./a.out export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=compact export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=1 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} export I MPI PIN DOMAIN=10 export I MPI PERHOST=2 export I MPI PIN ORDER=scatter export OMP NUM THREADS=8 mpiexec -n 32 numactl -l ${BIN} 4ノード、合計32プロセス利用することの宣言。 OpenMPに関する環境変数の情報を細かく表示させるオプションMPIに関する環境変数の情報を細かく表示させるオプション• I MPI PIN DOMAIN=10のためプロセスが配置される際の単位は10コア、OMP NUM THREADS=8のためプロセス内のOpenMPに使われるのは8コア。 • I MPI PERHOST=2のため、2プロセス配置したら次のノードヘ。 I MPI PIN ORDER=compactのため、ノードにプロセスを配置する際は前回の配置から遠いところ。（ノード内のプロセス配置順序だけみたらscatter的。) numactl -lのため、ソケットから近いメモリだけを使う。一般的なscatterの割り当て的にはソケット0の次はソケット2に配置されることが期待される気もするが、ソケット間の距離は均等であり、ソケットを埋め尽くす前に次のソケットへ行っているという点で確かにscatter。実際に配置されるコア番号を見てみると、ソケット内で完全に連続したコアが確保されるとは限らない。実例プロセス(ランク)0は「0,1,2,10,11,3,4,12」で8スレッド(ノード0のソケット0上)プロセス(ランク)1は「20,21,22,30,31,23,24,32」で8スレッド（ノード0上のソケット1上） ・クラウドシステムで多く使われると思われるIntelコンパイラ+ Intel MPIに絞ってプロセスとスレッドの配置を解説した
が、「よくある割り当て方法」であれば難しくないはずである
–ある程度需要がありそうな事例であると思われる場合には本資料に追記させていただきます
/proc/{PID}/task/{TID}/statの39列目（processor情報）にコア番号が入っている確認用テストプログラムの例↑サブシステムを問わず利用可能、以下はType Iにおける4プロセス×4スレッドでの実行例（ソート済み） hostname=fx2271 rank=0 thread-id=63 omp-tid= 0 core-id=12 hostname=fx2271 rank=0 thread-id=77 omp-tid= 1 core-id=13 hostname=fx2271 rank=0 thread-id=80 omp-tid= 2 core-id=14 hostname=fx2271 rank=0 thread-id=84 omp-tid= 3 core-id=15 hostname=fx2271 rank=1 thread-id=65 omp-tid= 0 core-id=24 hostname=fx2271 rank=1 thread-id=75 omp-tid= 1 core-id=25 hostname=fx2271 rank=1 thread-id=79 omp-tid=2 core-id=26 hostname=fx2271 rank=1 thread-id=83 omp-tid=3 core-id=27 hostname=fx2271 rank=2 thread-id=64 omp-tid= 0 core-id=36 hostname=fx2271 rank=2 thread-id=78 omp-tid= 1 core-id=37 hostname=fx2271 rank=2 thread-id=82 omp-tid= 2 core-id=38 hostname=fx2271 rank=2 thread-id=86 omp-tid= 3 core-id=39 hostname=fx2271 rank=3 thread-id=66 omp-tid= 0 core-id=48 hostname=fx2271 rank=3 thread-id=76 omp-tid= 1 core-id=49 hostname=fx2271 rank=3 thread-id=81 omp-tid=2 core-id=50 hostname=fx2271 rank=3 thread-id=85 omp-tid=3 core-id=51 #include <unistd.h> #include <sys/types.h> #include <sys/syscall.h> #include <mpi.h> #include <omp.h> #define min(a,b) a<b?a:b void check_core(int rank){ char buf[0xff], buf2[4], hostname[0xff]; FILE *fp; int pid, tid, ompid, count, c1, c2; pid = getpid(); tid = (pid_t) syscall(SYS_gettid); ompid = omp_get_thread_num(); sprintf(buf, "/proc/%d/task/%d/stat", pid, tid); if ((fp = fopen(buf, "r")) != NULL) { fgets(buf, 0xff, fp); fclose(fp); count = 0; c1 = c2 = 0; ※strtokで分解したらNULLを喰らうwhile(buf[c1]!=' ¥0'){ if(buf[c1]==' ')count++;ことが度々あったため、手動で分割cl++;しているif(count==38)break; c2 = c1; while(buf[c2]!=' ¥0'){ if(buf[c2]==' ')break; c2++; strncpy(buf2, &buf[c1], min(c2-c1, 4)); buf2[min(c2-c1, 4)] = '￥0'; gethostname(hostname, 0xff); printf("hostname=%s rank=%d thread-id=%2d omp-tid=%2d core-id=%s ¥ n", hostname, rank, tid, ompid, buf2); . . 21