1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 MPY stands for "MPi for pYthon", is a single-module wrapper for any MPI
21 library. Just copy the mpy.py then it works (needless to say, after you have
22 MPI installed on a cluster). MPY has no external dependency other than a
23 working MPI installation and a standard Python. The MPI installation has to
24 be built with shared object since MPY uses ctypes as interface.
25
26 All the functions in the MPI library can be accessed by
27 MPI().Name_Without_Leading_MPI(), and you must manually convert the arguments
28 from Python objects to ctypes objects. Shorthand APIs and Pythonic APIs are
29 also provided. Shorthand APIs use Python objects and can return Python
30 objects, with the same naming convention as MPI, but all lower-cased. Pythonic
31 APIs are Pythonic.
32
33 You can verify the "installation" of MPY by running::
34
35 $ mpiexec -n 2 python mpy.py
36
37 """
38
39 __version__ = '0.1+'
40
41 __description__ = """MPI for Python."""
42
43 _libs = dict()
45 from ctypes import CDLL
46 if path in _libs:
47 lib = _libs[path]
48 else:
49 lib = _libs[path] = CDLL('libmpich.so')
50 return lib
51
53 """
54 Wrapper for MPI library. The leading 'MPI_' is stripped off from the
55 name of all MPI entities. Shorthand and Pythonic APIs are provided with
56 all lower-cased name. All MPI constants are Python int() and filled
57 according to the mpi.h of MVAPICH2-1.5. ctypes is used for calling
58 dynamically linked MPI libraries.
59 """
60
61
62 COMM_NULL = 0x04000000
63 OP_NULL = 0x18000000
64 GROUP_NULL = 0x08000000
65 DATATYPE_NULL = 0x0c000000
66 REQUEST_NULL = 0x2c000000
67 ERRHANDLER_NULL = 0x14000000
68
69
70 IDENT = 0
71 CONGRUENT = 1
72 SIMILAR = 2
73 UNEQUAL = 3
74
75
76 CHAR = 0x4c000101
77 SIGNED_CHAR = 0x4c000118
78 UNSIGNED_CHAR = 0x4c000102
79 BYTE = 0x4c00010d
80 WCHAR = 0x4c00040e
81 SHORT = 0x4c000203
82 UNSIGNED_SHORT = 0x4c000204
83 INT = 0x4c000405
84 UNSIGNED = 0x4c000406
85 LONG = 0x4c000807
86 UNSIGNED_LONG = 0x4c000808
87 FLOAT = 0x4c00040a
88 DOUBLE = 0x4c00080b
89 LONG_DOUBLE = 0x4c00080c
90 LONG_LONG_INT = 0x4c000809
91 UNSIGNED_LONG_LONG = 0x4c000819
92 LONG_LONG = LONG_LONG_INT
93
94 PACKED = 0x4c00010f
95 LB = 0x4c000010
96 UB = 0x4c000011
97
98 FLOAT_INT = 0x8c000000
99 DOUBLE_INT = 0x8c000001
100 LONG_INT = 0x8c000002
101 SHORT_INT = 0x8c000003
102 _2INT = 0x4c000816
103 LONG_DOUBLE_INT = 0x8c000004
104
105 COMPLEX = 1275070494
106 DOUBLE_COMPLEX = 1275072546
107 LOGICAL = 1275069469
108 REAL = 1275069468
109 DOUBLE_PRECISION = 1275070495
110 INTEGER = 1275069467
111 _2INTEGER = 1275070496
112 _2COMPLEX = 1275072548
113 _2DOUBLE_COMPLEX = 1275076645
114 _2REAL = 1275070497
115 _2DOUBLE_PRECISION = 1275072547
116 CHARACTER = 1275068698
117
118 REAL4 = 0x4c000427
119 REAL8 = 0x4c000829
120 REAL16 = DATATYPE_NULL
121 COMPLEX8 = 0x4c000828
122 COMPLEX16 = 0x4c00102a
123 COMPLEX32 = DATATYPE_NULL
124 INTEGER1 = 0x4c00012d
125 INTEGER2 = 0x4c00022f
126 INTEGER4 = 0x4c000430
127 INTEGER8 = 0x4c000831
128 INTEGER16 = DATATYPE_NULL
129
130 INT8_T = 0x4c000137
131 INT16_T = 0x4c000238
132 INT32_T = 0x4c000439
133 INT64_T = 0x4c00083a
134 UINT8_T = 0x4c00013b
135 UINT16_T = 0x4c00023c
136 UINT32_T = 0x4c00043d
137 UINT64_T = 0x4c00083e
138
139 C_BOOL = 0x4c00013f
140 C_FLOAT_COMPLEX = 0x4c000840
141 C_COMPLEX = C_FLOAT_COMPLEX
142 C_DOUBLE_COMPLEX = 0x4c001041
143 C_LONG_DOUBLE_COMPLEX = 0x4c001042
144
145 AINT = 0x4c000843
146 OFFSET = 0x4c000844
147
148 TYPECLASS_REAL = 1
149 TYPECLASS_INTEGER = 2
150 TYPECLASS_COMPLEX = 3
151
152
153 COMM_WORLD = 0x44000000
154 COMM_SELF = 0x44000001
155
156
157 GROUP_EMPTY = 0x48000000
158
159
160 WIN_NULL = 0x20000000
161
162
163 FILE_NULL = 0
164
165
166 MAX = 0x58000001
167 MIN = 0x58000002
168 SUM = 0x58000003
169 PROD = 0x58000004
170 LAND = 0x58000005
171 BAND = 0x58000006
172 LOR = 0x58000007
173 BOR = 0x58000008
174 LXOR = 0x58000009
175 BXOR = 0x5800000a
176 MINLOC = 0x5800000b
177 MAXLOC = 0x5800000c
178 REPLACE = 0x5800000d
179
180
181 TAG_UB = 0x64400001
182 HOST = 0x64400003
183 IO = 0x64400005
184 WTIME_IS_GLOBAL = 0x64400007
185 UNIVERSE_SIZE = 0x64400009
186 LASTUSEDCODE = 0x6440000b
187 APPNUM = 0x6440000d
188
189
190 WIN_BASE = 0x66000001
191 WIN_SIZE = 0x66000003
192 WIN_DISP_UNIT = 0x66000005
193
194
195 MAX_PROCESSOR_NAME = 128
196 MAX_ERROR_STRING = 1024
197 MAX_PORT_NAME = 256
198 MAX_OBJECT_NAME = 128
199
200
201 UNDEFINED = -32766
202 KEYVAL_INVALID = 0x24000000
203
204
205 BSEND_OVERHEAD = 88
206
207
208 BOTTOM = 0
209 UNWEIGHTED = 0
210
211 PROC_NULL = -1
212 ANY_SOURCE = -2
213 ROOT = -3
214 ANY_TAG = -1
215
216 LOCK_EXCLUSIVE = 234
217 LOCK_SHARED = 235
218
219
220 ERRORS_ARE_FATAL = 0x54000000
221 ERRORS_RETURN = 0x54000001
222
223
224 NULL_COPY_FN = 0
225 NULL_DELETE_FN = 0
226
227 COMM_NULL_COPY_FN = 0
228 COMM_NULL_DELETE_FN = 0
229 WIN_NULL_COPY_FN = 0
230 WIN_NULL_DELETE_FN = 0
231 TYPE_NULL_COPY_FN = 0
232 TYPE_NULL_DELETE_FN = 0
233
234
235 INFO_NULL = 0x1c000000
236 MAX_INFO_KEY = 255
237 MAX_INFO_VAL = 1024
238
239
240 ORDER_C = 56
241 ORDER_FORTRAN = 57
242 DISTRIBUTE_BLOCK = 121
243 DISTRIBUTE_CYCLIC = 122
244 DISTRIBUTE_NONE = 123
245 DISTRIBUTE_DFLT_DARG = -49767
246
247 IN_PLACE = -1
248
249
250 MODE_NOCHECK = 1024
251 MODE_NOSTORE = 2048
252 MODE_NOPUT = 4096
253 MODE_NOPRECEDE = 8192
254 MODE_NOSUCCEED = 16384
255
256 STATUS_IGNORE = 1
257 STATUSES_IGNORE = 1
258 ERRCODES_IGNORE = 0
259
260 ARGV_NULL = 0
261 ARGVS_NULL = 0
262
263
264 THREAD_SINGLE = 0
265 THREAD_FUNNELED = 1
266 THREAD_SERIALIZED = 2
267 THREAD_MULTIPLE = 3
268
269
270 SUCCESS = 0
271
272 ERR_BUFFER = 1
273 ERR_COUNT = 2
274 ERR_TYPE = 3
275 ERR_TAG = 4
276 ERR_COMM = 5
277 ERR_RANK = 6
278 ERR_ROOT = 7
279 ERR_TRUNCATE = 14
280
281 ERR_GROUP = 8
282 ERR_OP = 9
283 ERR_REQUEST = 19
284
285 ERR_TOPOLOGY = 10
286 ERR_DIMS = 11
287
288 ERR_ARG = 12
289
290 ERR_OTHER = 15
291 ERR_UNKNOWN = 13
292 ERR_INTERN = 16
293
294 ERR_IN_STATUS = 17
295 ERR_PENDING = 18
296
297 ERR_FILE = 27
298 ERR_ACCESS = 20
299 ERR_AMODE = 21
300 ERR_BAD_FILE = 22
301 ERR_FILE_EXISTS = 25
302 ERR_FILE_IN_USE = 26
303 ERR_NO_SPACE = 36
304 ERR_NO_SUCH_FILE = 37
305 ERR_IO = 32
306 ERR_READ_ONLY = 40
307 ERR_CONVERSION = 23
308 ERR_DUP_DATAREP = 24
309 ERR_UNSUPPORTED_DATAREP = 43
310
311 ERR_INFO = 28
312 ERR_INFO_KEY = 29
313 ERR_INFO_VALUE = 30
314 ERR_INFO_NOKEY = 31
315
316 ERR_NAME = 33
317 ERR_NO_MEM = 34
318 ERR_NOT_SAME = 35
319 ERR_PORT = 38
320 ERR_QUOTA = 39
321 ERR_SERVICE = 41
322 ERR_SPAWN = 42
323 ERR_UNSUPPORTED_OPERATION = 44
324 ERR_WIN = 45
325
326 ERR_BASE = 46
327 ERR_LOCKTYPE = 47
328 ERR_KEYVAL = 48
329 ERR_RMA_CONFLICT = 49
330 ERR_RMA_SYNC = 50
331 ERR_SIZE = 51
332 ERR_DISP = 52
333 ERR_ASSERT = 53
334
335 ERR_LASTCODE = 0x3fffffff
336
337 CONVERSION_FN_NULL = 0
338
340 self.lib = get_lib('libmpich.so')
341 if initlib:
342 self.Init(None, None)
344 return getattr(self.lib, 'MPI_'+key)
345 @classmethod
347 """
348 Make up communicator c_int based on input.
349 """
350 from ctypes import c_int
351 return c_int(cls.COMM_WORLD if comm == None else comm)
352
353
354
356 from ctypes import c_int, byref
357 val = c_int(-1)
358 self.Comm_rank(self._make_comm(comm), byref(val))
359 return val.value
361 from ctypes import c_int, byref
362 val = c_int(-1)
363 self.Comm_size(self._make_comm(comm), byref(val))
364 return val.value
365
366
367
368 @property
370 from ctypes import c_int, byref
371 val = c_int(-1)
372 self.Initialized(byref(val))
373 return bool(val.value)
374 @property
376 from ctypes import c_int, byref
377 val = c_int(-1)
378 self.Comm_rank(self._make_comm(None), byref(val))
379 return val.value
380 @property
381 - def size(self, comm=None):
382 from ctypes import c_int, byref
383 val = c_int(-1)
384 self.Comm_size(self._make_comm(None), byref(val))
385 return val.value
386
387 - def send(self, obj, dst, tag, comm=None):
388 from cPickle import dumps
389 from ctypes import c_int, c_char_p, byref
390 comm = self.COMM_WORLD if comm is None else comm
391
392 dat = dumps(obj, -1)
393 self.Send(byref(c_int(len(dat))), c_int(1), c_int(self.INT),
394 c_int(dst), c_int(tag), c_int(comm))
395 self.Send(c_char_p(dat), c_int(len(dat)), c_int(self.BYTE),
396 c_int(dst), c_int(tag), c_int(comm))
397 - def recv(self, src, tag, comm=None):
398 from cPickle import loads
399 from ctypes import c_int, byref, create_string_buffer
400 comm = self.COMM_WORLD if comm is None else comm
401
402 dlen = c_int()
403 status = c_int(0)
404 self.Recv(byref(dlen), c_int(1), c_int(self.INT),
405 c_int(src), c_int(tag), c_int(comm), byref(status))
406 status.value = 0
407 dat = create_string_buffer(dlen.value)
408 self.Recv(byref(dat), dlen, c_int(self.BYTE),
409 c_int(src), c_int(tag), c_int(comm), byref(status))
410 obj = loads(dat.raw)
411 return obj
412
413 - def sendarr(self, arr, dst, tag, comm=None):
419 - def recvarr(self, arr, src, tag, comm=None):
420 from ctypes import c_int, c_void_p, byref
421 comm = self.COMM_WORLD if comm is None else comm
422 status = c_int(0)
423 self.Recv(arr.ctypes.data_as(c_void_p),
424 c_int(arr.nbytes), c_int(self.BYTE),
425 c_int(src), c_int(tag), c_int(comm), byref(status))
426
428 import os, sys
429 from random import choice, randint
430 from socket import gethostname
431 mpi = MPI()
432 sys.stdout.write('rank %d/(%d-1) on %s %s\n' % (
433 mpi.rank, mpi.size, gethostname(),
434 'initialized' if mpi.initialized else 'uninitialized'))
435 if mpi.rank == 0:
436 msg = ''.join([choice('abcdefghijklmnopqrstuvwxyz')
437 for it in range(randint(2, 20))])
438 sys.stdout.write('rank %d on %s send: %s\n' % (
439 mpi.rank, gethostname(), msg))
440 mpi.send(msg, 1, 99)
441 elif mpi.rank == 1:
442 buf = mpi.recv(0, 99)
443 sys.stdout.write('rank %d on %s recv: %s\n' % (
444 mpi.rank, gethostname(), buf))
445 else:
446 sys.stdout.write('rank %d on %s do nothing\n' % (
447 mpi.rank, gethostname()))
448 mpi.Finalize()
449
450 if __name__ == '__main__':
451 main()
452