32bit CPUと64bit CPUが混在するmpiクラスタを作成しました。
Linux上で、openmpi,Python3-mpi4pyを使っています。
32bitと64bitが混在できるよう、mpirunは./configureにて—enable-heterogeneousオプションをつけてビルドし、
mpirun —hostfile hostlist64bit python3 hello.py : —hostfile hostlist32bit python3 hello.py
にて、 いわゆるハローワールドが動作するところまでは確認できました。
次に円周率を計算しようと思ったのですが、どうもcomm.sendとcomm.recvにおけるnp.array(dtype=object)のやりとりに起因してエラーが発生しているようです。
クラスタの構造は2分木転送方式であり、broadcastやreduceは使っていません。
ちなみに、hostlistに64bitPCのみ、32bitPCのみを指定した場合は円周率がうまく計算できるので、
32bitノードと64bitノードがデータをやりとりする時に問題が起こっている可能性が高いと思います。
np.array作成時にdtype=int32などと指定すると混在でもうまくいくのですが、桁数を増やすためには、桁数制限のないobject型を使う必要があります。
numpyのobject型は、32bit版と64bit版で仕様が違うのでしょうか。
ご教示いただけますと幸いです。
よろしくお願いいたします。
<円周率計算プログラムの情報>
実行コマンド:
$mpirun --hostfile host64 -n 14 python3 pi_chudnovsky.py 13 : --hostfile host32 -n 2 python3 pi_chudnovsky.py 13
↑ちなみに、13のところを12以下にするとエラーなく実行できます。
pi_chudnovsky.pyについて:
https://github.com/kemusiro/openmpi-sample/からダウンロード
ライセンス
MIT License
Copyright (c) 2021 Kenichi Miyata
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
コード本文
python
1from mpi4py import MPI 2import gmpy2 as mp 3from gmpy2 import mpz 4import numpy as np 5import mmap 6import sys 7import os 8 9# 円周率を並列に計算する。 10def calc_PQT_root(n): 11 # まず自分の割り当て分を計算する。 12 alloc = int(n / size) 13 PQT2 = calc_PQT_local(rank * alloc, (rank + 1) * alloc) 14 15 # 各ノードの計算結果をマージする。 16 level = int(mp.ceil(mp.log2(size))) 17 k = 1 18 for _ in range(level): 19 if (rank & k) == k: 20 PQT1 = comm.recv(source=rank-k, tag=0) 21 PQT2 = np.array([PQT1[0] * PQT2[0], 22 PQT1[1] * PQT2[1], 23 PQT1[2] * PQT2[1] + PQT1[0] * PQT2[2]]) 24 k *= 2 25 else: 26 comm.send(PQT2, dest=rank+k, tag=0) 27 break 28 return PQT2 29 30# ノード内でP(n1, n2), Q(n1, n2), T(n1, n2)を計算する。 31def calc_PQT_local(n1, n2): 32 if n1 + 1 == n2: 33 P = mpz((-1) * (2 * n2 - 1) * (6 * n2 - 5) * (6 * n2 - 1)) 34 return np.array([P, C3over24 * n2 ** 3, (A + B * n2) * P]) 35 else: 36 m = int((n1 + n2) / 2) 37 PQT1 = calc_PQT_local(n1, m) 38 PQT2 = calc_PQT_local(m, n2) 39 return np.array([PQT1[0] * PQT2[0], 40 PQT1[1] * PQT2[1], 41 PQT1[2] * PQT2[1] + PQT1[0] * PQT2[2]]) 42 43# 円周率が何桁まで一致するかを判定する。 44def check_pi(outfile, pifile): 45 with open(pifile, 'rb') as f0, \ 46 open(outfile, 'rb') as f1: 47 # 2つのファイルをメモリにマップして比較する。 48 with mmap.mmap(f0.fileno(), 0, flags=mmap.MAP_PRIVATE) as mm0, \ 49 mmap.mmap(f1.fileno(), 0, flags=mmap.MAP_PRIVATE) as mm1: 50 index = mpz(0) 51 length = 1024 * 1024 # 一度にチェックする桁数 52 found = False 53 while not found: 54 ans = mm0.read(length) 55 calc = mm1.read(length) 56 if ans != calc: 57 maxlen = min(len(ans), len(calc)) 58 for i in range(maxlen): 59 if ans[i] != calc[i]: 60 n = index + i - 2 61 found = True 62 break 63 else: 64 n = index + maxlen - 3 65 break 66 else: 67 index += length 68 return n 69 70if __name__ == '__main__': 71 comm = MPI.COMM_WORLD 72 rank = comm.Get_rank() 73 size = comm.Get_size() 74 75 if len(sys.argv) < 2: 76 if rank == size - 1: 77 print('python3 pi_chudnovsky.py <power> [pifile]') 78 sys.exit(0) 79 80 if not sys.argv[1].isdecimal(): 81 if rank == size - 1: 82 print('not decimal value: {}'.format(sys.argv[1])) 83 print('python3 pi_chudnovsky.py power [pifile]') 84 sys.exit(0) 85 power = int(sys.argv[1]) 86 87 if len(sys.argv) == 2: 88 pifile = '/share/common/pi-10oku.txt' 89 else: 90 pifile = sys.argv[2] 91 if not os.path.exists(pifile): 92 if rank == size - 1: 93 print('{} does not exist'.format(pifile)) 94 print('python3 pi_chudnovsky.py <power> [pifile]') 95 sys.exit(0) 96 outfile = 'pi.txt' 97 98 A = mpz(13591409) 99 B = mpz(545140134) 100 C = mpz(640320) 101 C3over24 = mpz(C**3 / 24) 102 103 n = 2 ** power 104 digits = n * 14 105 # gmpy2の浮動小数の精度として、求められる円周率の桁数を設定する。 106 mp.get_context().precision = int(digits * mp.log2(10)) 107 108 if rank == size - 1: 109 print('calculating...') 110 start = MPI.Wtime() 111 PQT = calc_PQT_root(n) 112 if rank == size - 1: 113 temp1 = C * mp.sqrt(C) * PQT[1] 114 temp2 = 12 * (PQT[2] + A * PQT[1]) 115 pi = temp1 / temp2 116 end = MPI.Wtime() 117 with open(outfile, 'w') as f: 118 f.write(str(pi)) 119 print('checking...') 120 n = check_pi(outfile, pifile) 121 print('time = {:.2f} sec.'.format(end - start)) 122 print(f'match = {n}')