Package solvcon :: Module mpy
[hide private]
[frames] | no frames]

Source Code for Module solvcon.mpy

  1  # -*- coding: UTF-8 -*- 
  2  # 
  3  # Copyright (C) 2008-2010 Yung-Yu Chen <yyc@solvcon.net>. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 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() 
44 -def get_lib(path):
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
52 -class MPI(object):
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 # Null objects. 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 # Results of the compare operations. 70 IDENT = 0 71 CONGRUENT = 1 72 SIMILAR = 2 73 UNEQUAL = 3 74 75 # Data types. 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 # FORTRAN types. 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 # Size-specific data types. 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 # C99 fixed-width data types. 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 # Other C99 data types. 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 # Address types. 145 AINT = 0x4c000843 146 OFFSET = 0x4c000844 147 # Type classes. 148 TYPECLASS_REAL = 1 149 TYPECLASS_INTEGER = 2 150 TYPECLASS_COMPLEX = 3 151 152 # Communicators. 153 COMM_WORLD = 0x44000000 154 COMM_SELF = 0x44000001 155 156 # Groups. 157 GROUP_EMPTY = 0x48000000 158 159 # RMA and Windows. 160 WIN_NULL = 0x20000000 161 162 # File. 163 FILE_NULL = 0 164 165 # Collective operations. 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 # Permanent key values. 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 # The 3 predefined window attributes for every window. 190 WIN_BASE = 0x66000001 191 WIN_SIZE = 0x66000003 192 WIN_DISP_UNIT = 0x66000005 193 194 # Guessed values. 195 MAX_PROCESSOR_NAME = 128 196 MAX_ERROR_STRING = 1024 197 MAX_PORT_NAME = 256 198 MAX_OBJECT_NAME = 128 199 200 # Predefined constants. 201 UNDEFINED = -32766 202 KEYVAL_INVALID = 0x24000000 203 204 # Upper bound on the overhead in bsend for each message buffer. 205 BSEND_OVERHEAD = 88 206 207 # Topology types: 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 # Built in error handlers. 220 ERRORS_ARE_FATAL = 0x54000000 221 ERRORS_RETURN = 0x54000001 222 223 # MPI-1. 224 NULL_COPY_FN = 0 225 NULL_DELETE_FN = 0 226 # MPI-2. 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 # Info. 235 INFO_NULL = 0x1c000000 236 MAX_INFO_KEY = 255 237 MAX_INFO_VAL = 1024 238 239 # Subarray and darray constructors. 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 # Asserts for one-sided communication. 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 # Supported thread levels. 264 THREAD_SINGLE = 0 265 THREAD_FUNNELED = 1 266 THREAD_SERIALIZED = 2 267 THREAD_MULTIPLE = 3 268 269 # Error classes. 270 SUCCESS = 0 271 # Communication argument parameters. 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 # MPI objects. 281 ERR_GROUP = 8 282 ERR_OP = 9 283 ERR_REQUEST = 19 284 # Special topology argument parameters. 285 ERR_TOPOLOGY = 10 286 ERR_DIMS = 11 287 # All other arguments. 288 ERR_ARG = 12 289 # Other erros. 290 ERR_OTHER = 15 291 ERR_UNKNOWN = 13 292 ERR_INTERN = 16 293 # Multiple completion. 294 ERR_IN_STATUS = 17 295 ERR_PENDING = 18 296 # New MPI-2 error classes. 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 # Info (oversight?). 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
339 - def __init__(self, initlib=True):
340 self.lib = get_lib('libmpich.so') 341 if initlib: 342 self.Init(None, None)
343 - def __getattr__(self, key):
344 return getattr(self.lib, 'MPI_'+key)
345 @classmethod
346 - def _make_comm(cls, comm):
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 # Shorthand API. 354 ############################################################################
355 - def comm_rank(self, comm=None):
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
360 - def comm_size(self, comm=None):
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 # Pythonic API. 367 ############################################################################ 368 @property
369 - def initialized(self):
370 from ctypes import c_int, byref 371 val = c_int(-1) 372 self.Initialized(byref(val)) 373 return bool(val.value)
374 @property
375 - def rank(self):
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 # dump obj. 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 # load obj. 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):
414 from ctypes import c_int, c_void_p 415 comm = self.COMM_WORLD if comm is None else comm 416 self.Send(arr.ctypes.data_as(c_void_p), 417 c_int(arr.nbytes), c_int(self.BYTE), 418 c_int(dst), c_int(tag), c_int(comm))
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
427 -def main():
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