source: pypar/contrib/mpi.c @ 317

Last change on this file since 317 was 85, checked in by ole, 19 years ago

Added pypar files

File size: 20.7 KB
Line 
1/************************************************************************/
2/* PyPAR - Parallel Python using MPI                                    */
3/* Copyright (C) 2001, 2002 Ole M. Nielsen, Gian Paolo Ciceri           */
4/*                                                                      */
5/* See enclosed README file for details of installation and use.        */
6/*                                                                      */   
7/* This program is free software; you can redistribute it and/or modify */
8/* it under the terms of the GNU General Public License as published by */
9/* the Free Software Foundation; either version 2 of the License, or    */
10/* (at your option) any later version.                                  */
11/*                                                                      */     
12/* This program is distributed in the hope that it will be useful,      */
13/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
14/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
15/* GNU General Public License (http://www.gnu.org/copyleft/gpl.html)    */
16/* for more details.                                                    */
17/*                                                                      */
18/* You should have received a copy of the GNU General Public License    */
19/* along with this program; if not, write to the Free Software          */
20/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307*/
21/*                                                                      */
22/*                                                                      */
23/* Contact addresses: Ole.Nielsen@anu.edu.au, gp.ciceri@acm.org         */
24/*                                                                      */
25/* version 1.2.1, 16 February 2002                                      */
26/*   Status block, MPI_ANY_TAG, MPI_ANY_SOURCE exported                 */
27/* Version 1.2, 15 February 2002                                        */   
28/*   Scatter added by Gian Paolo Ciceri                                 */
29/* Version 1.1, 14 February 2002                                        */   
30/*   Bcast added by Gian Paolo Ciceri                                   */
31/* Version 1.0.2, 10 February 2002                                      */
32/*   Modified by Gian Paulo Ciceri to allow pypar run under Python 2.2  */
33/* Version 1.0.1, 8 February 2002                                       */
34/*   Modified to install on SUN enterprise systems under Mpich          */
35/* Version 1.0, 7 February 2002                                         */
36/*   First public release for Python 2.1 (OMN)                          */
37/************************************************************************/
38
39
40#include "Python.h"
41#include "mpi.h"
42#include "Numeric/arrayobject.h"
43
44// to handle MPI constants export (shamelessly stolen from _cursesmodule.c)
45#define SetDictInt(string,ch) \
46        PyDict_SetItemString(ModDict, string, PyInt_FromLong((long) (ch)));
47
48// kludge to remap struct MPI_op to int (easier to handle by python)
49#define mpi_MAX 1
50#define mpi_MIN 2
51#define mpi_SUM 3
52#define mpi_PROD 4
53#define mpi_LAND 5
54#define mpi_BAND 6
55#define mpi_LOR 7
56#define mpi_BOR 8
57#define mpi_LXOR 9
58#define mpi_BXOR 10
59#define mpi_MAXLOC 11
60#define mpi_MINLOC 12
61#define mpi_REPLACE 13
62
63
64
65MPI_Datatype type_map(PyArrayObject *x) { 
66
67  //
68  // TYPE    py_type  mpi_type  bytes  symbol
69  // ----------------------------------------
70  // INT       4        6         4      'i'
71  // LONG      5        8         8      'l'
72  // FLOAT     6       10         4      'f' 
73  // DOUBLE    7       11         8      'd'
74 
75 
76  int py_type;
77  MPI_Datatype mpi_type;
78 
79  if (x -> nd != 1) {
80    PyErr_SetString(PyExc_ValueError, "Array must be 1 dimensional");
81    return (MPI_Datatype) 0;
82  }     
83     
84  py_type = x -> descr -> type_num;     
85  if (py_type == PyArray_DOUBLE) 
86    mpi_type = MPI_DOUBLE;
87  else if (py_type == PyArray_LONG)   
88    mpi_type = MPI_LONG; 
89  else if (py_type == PyArray_FLOAT) 
90    mpi_type = MPI_FLOAT;
91  else if (py_type == PyArray_INT) 
92    mpi_type = MPI_INT;
93  else {
94    PyErr_SetString(PyExc_ValueError, "Array must be of type int or float");
95    return 0;
96  }     
97
98  //printf("Types: %d %d.\n", py_type, mpi_type);
99 
100  return mpi_type;
101}   
102
103MPI_Op op_map(int py_op) { 
104 
105  MPI_Op mpi_op;
106 
107  if (py_op == mpi_MAX) 
108    mpi_op = MPI_MAX;
109  else if (py_op == mpi_MIN)   
110    mpi_op = MPI_MIN; 
111  else if (py_op == mpi_SUM)   
112    mpi_op = MPI_SUM; 
113  else if (py_op == mpi_PROD)   
114    mpi_op = MPI_PROD; 
115  else if (py_op == mpi_LAND)   
116    mpi_op = MPI_LAND; 
117  else if (py_op == mpi_BAND)   
118    mpi_op = MPI_BAND; 
119  else if (py_op == mpi_LOR)   
120    mpi_op = MPI_LOR; 
121  else if (py_op == mpi_BOR)   
122    mpi_op = MPI_BOR; 
123  else if (py_op == mpi_LXOR)   
124    mpi_op = MPI_LXOR; 
125  else if (py_op == mpi_BXOR)   
126    mpi_op = MPI_BXOR; 
127  else if (py_op == mpi_MAXLOC)
128    mpi_op = MPI_MAXLOC;
129  else if (py_op == mpi_MINLOC)   
130    mpi_op = MPI_MINLOC; 
131  else if (py_op == mpi_REPLACE)   
132    mpi_op = MPI_REPLACE; 
133  else {
134    PyErr_SetString(PyExc_ValueError, "Operation unknown");
135    return 0;
136  }     
137
138  //printf("Op: %d.\n", py_op);
139 
140  return mpi_op;
141} 
142
143/*********************************************************/
144/* send_string                                           */
145/* Send string of characters                             */
146/*                                                       */
147/*********************************************************/
148static PyObject *send_string(PyObject *self, PyObject *args) {
149  char *s;
150  int destination, tag, length, err;
151 
152  /* process the parameters */
153  if (!PyArg_ParseTuple(args, "s#ii", &s, &length, &destination, &tag))
154    return NULL;
155 
156  /* call the MPI routine */
157  err = MPI_Send(s, length, MPI_CHAR, destination, tag, MPI_COMM_WORLD);
158
159  return Py_BuildValue("i", err);
160}
161
162/**********************************************************/
163/* receive_string                                         */
164/* Receive string of characters                           */
165/*                                                        */
166/**********************************************************/
167static PyObject *receive_string(PyObject *self, PyObject *args) {
168  char *s;
169  int source, tag, length, err, st_length; 
170  MPI_Status status;
171
172  /* process the parameters */
173  if (!PyArg_ParseTuple(args, "s#ii", &s, &length, &source, &tag))
174    return NULL;
175   
176  /* call the MPI routine */
177  err = MPI_Recv(s, length, MPI_CHAR, source, tag, MPI_COMM_WORLD, &status);
178   
179  MPI_Get_count(&status, MPI_CHAR, &st_length); 
180  // status.st_length is not available in all MPI implementations
181  //Alternative is: MPI_Get_elements(MPI_Status *, MPI_Datatype, int *);
182
183  return Py_BuildValue("i(iiii)", err, status.MPI_SOURCE, status.MPI_TAG,
184  status.MPI_ERROR, st_length); 
185}
186
187/**********************************************************/
188/* bcast_string                                           */
189/* Broadcast string of characters                         */
190/*                                                        */
191/**********************************************************/
192static PyObject *bcast_string(PyObject *self, PyObject *args) {
193  char *s;
194  int source, length, err; 
195
196  /* process the parameters */
197  if (!PyArg_ParseTuple(args, "s#i", &s, &length, &source))
198    return NULL;
199   
200  /* call the MPI routine */
201  err = MPI_Bcast(s, length, MPI_CHAR, source, MPI_COMM_WORLD);
202   
203  return Py_BuildValue("i", err); 
204}
205
206/**********************************************************/
207/* scatter_string                                         */
208/* Scatter string of characters                           */
209/*                                                        */
210/**********************************************************/
211static PyObject *scatter_string(PyObject *self, PyObject *args) {
212  char *s;
213  char *d;
214  int source, length, err; 
215
216  /* process the parameters */
217  if (!PyArg_ParseTuple(args, "sisi", &s, &length, &d, &source))
218    return NULL;
219   
220  /* call the MPI routine */
221  err = MPI_Scatter(s, length, MPI_CHAR, d, length,  MPI_CHAR, source, MPI_COMM_WORLD);
222   
223  return Py_BuildValue("i", err); 
224}
225
226/**********************************************************/
227/* gather_string                                         */
228/* Gather string of characters                           */
229/*                                                        */
230/**********************************************************/
231static PyObject *gather_string(PyObject *self, PyObject *args) {
232  char *s;
233  char *d;
234  int source, length, err; 
235
236  /* process the parameters */
237  if (!PyArg_ParseTuple(args, "sisi", &s, &length, &d, &source))
238    return NULL;
239   
240  /* call the MPI routine */
241  err = MPI_Gather(s, length, MPI_CHAR, d, length,  MPI_CHAR, source, MPI_COMM_WORLD);
242   
243  return Py_BuildValue("i", err); 
244}
245
246
247/**********************************************************/
248/* send_array                                             */
249/* Send Numeric array of type float, double, int, or long */
250/*                                                        */
251/**********************************************************/
252static PyObject *send_array(PyObject *self, PyObject *args) {
253  PyObject *input;
254  PyArrayObject *x;
255  int destination, tag, err;
256  MPI_Datatype mpi_type;
257 
258  /* process the parameters */
259  if (!PyArg_ParseTuple(args, "Oii", &input, &destination, &tag))
260    return NULL;
261   
262  /* Make Numeric array from general sequence type (no cost if already Numeric)*/   
263  x = (PyArrayObject *)
264    PyArray_ContiguousFromObject(input, PyArray_NOTYPE, 0, 0);
265   
266  /* Input check and determination of MPI type */         
267  mpi_type = type_map(x);
268  if (!mpi_type) return NULL;
269   
270  /* call the MPI routine */
271  err = MPI_Send(x->data, x->dimensions[0], mpi_type, destination, tag,\
272           MPI_COMM_WORLD);
273           
274  Py_DECREF(x);           
275           
276  return Py_BuildValue("i", err);
277}
278
279/*************************************************************/
280/* receive_array                                             */
281/* Receive Numeric array of type float, double, int, or long */
282/*                                                           */
283/*************************************************************/
284static PyObject *receive_array(PyObject *self, PyObject *args) {
285  PyArrayObject *x;
286  int source, tag, err, st_length;
287  MPI_Datatype mpi_type;
288  MPI_Status status;
289
290  /* process the parameters */
291  if (!PyArg_ParseTuple(args, "Oii", &x, &source, &tag))
292    return NULL;
293
294  /* Input check and determination of MPI type */         
295  mpi_type = type_map(x);
296  if (!mpi_type) return NULL; 
297     
298  /* call the MPI routine */
299  err =  MPI_Recv(x->data, x->dimensions[0], mpi_type, source, tag, \
300         MPI_COMM_WORLD, &status);
301         
302  MPI_Get_count(&status, mpi_type, &st_length); 
303  // status.st_length is not available in all MPI implementations
304  //Alternative is: MPI_Get_elements(MPI_Status *, MPI_Datatype, int *);
305         
306     
307  return Py_BuildValue("i(iiii)", err, status.MPI_SOURCE, status.MPI_TAG,
308  status.MPI_ERROR, st_length); 
309}
310
311
312/*************************************************************/
313/* bcast_array                                               */
314/* Broadcast Num.  array of type float, double, int, or long */
315/*                                                           */
316/*************************************************************/
317static PyObject *bcast_array(PyObject *self, PyObject *args) {
318  PyArrayObject *x;
319  int source, err;
320  MPI_Datatype mpi_type;
321  MPI_Status status;
322
323  /* process the parameters */
324  if (!PyArg_ParseTuple(args, "Oi", &x, &source))
325    return NULL;
326
327  /* Input check and determination of MPI type */         
328  mpi_type = type_map(x);
329  if (!mpi_type) return NULL; 
330     
331  /* call the MPI routine */
332  err =  MPI_Bcast(x->data, x->dimensions[0], mpi_type, source, \
333         MPI_COMM_WORLD);
334     
335  return Py_BuildValue("i", err);
336}
337
338/*************************************************************/
339/* scatter_array                                             */
340/* Scatter Num.    array of type float, double, int, or long */
341/*                                                           */
342/*************************************************************/
343static PyObject *scatter_array(PyObject *self, PyObject *args) {
344  PyArrayObject *x;
345  PyArrayObject *d;
346  int length, source, err;
347  MPI_Datatype mpi_type;
348  MPI_Status status;
349
350  /* process the parameters */
351  if (!PyArg_ParseTuple(args, "OiOi", &x, &length, &d, &source))
352    return NULL;
353
354  /* Input check and determination of MPI type */         
355  mpi_type = type_map(x);
356  if (!mpi_type) return NULL; 
357     
358  /* call the MPI routine */
359  err =  MPI_Scatter(x->data, length, mpi_type, d->data, length, mpi_type, source, \
360         MPI_COMM_WORLD);
361     
362  return Py_BuildValue("i", err);
363}
364
365
366/*************************************************************/
367/* gather_array                                              */
368/* Gather Num.     array of type float, double, int, or long */
369/*                                                           */
370/*************************************************************/
371static PyObject *gather_array(PyObject *self, PyObject *args) {
372  PyArrayObject *x;
373  PyArrayObject *d;
374  int length, source, err;
375  MPI_Datatype mpi_type;
376  MPI_Status status;
377
378  /* process the parameters */
379  if (!PyArg_ParseTuple(args, "OiOi", &x, &length, &d, &source))
380    return NULL;
381
382  /* Input check and determination of MPI type */         
383  mpi_type = type_map(x);
384  if (!mpi_type) return NULL; 
385     
386  /* call the MPI routine */
387  err =  MPI_Gather(x->data, length, mpi_type, d->data, length, mpi_type, source, \
388         MPI_COMM_WORLD);
389     
390  return Py_BuildValue("i", err);
391}
392
393
394/*************************************************************/
395/* reduce_array                                              */
396/* Reduce Num.     array of type float, double, int, or long */
397/*                                                           */
398/*************************************************************/
399static PyObject *reduce_array(PyObject *self, PyObject *args) {
400  PyArrayObject *x;
401  PyArrayObject *d;
402  int length, source, op, err;
403  MPI_Datatype mpi_type;
404  MPI_Status status;
405  MPI_Op mpi_op;
406
407  /* process the parameters */
408  if (!PyArg_ParseTuple(args, "OOiii", &x, &d, &length, &op, &source))
409    return NULL;
410   
411  /* Input check and determination of MPI type */         
412  mpi_type = type_map(x);
413  if (!mpi_type) return NULL; 
414 
415  /* Input check and determination of MPI op */ 
416  //printf("op: %d\n", op);         
417  mpi_op = op_map(op);
418  if (!mpi_op) return NULL; 
419   
420         
421  if (op == mpi_MAXLOC || op == mpi_MINLOC) {
422    //not implemented
423    return Py_BuildValue("i", -666);
424  }
425  else {
426  /* call the MPI routine */
427  err =  MPI_Reduce(x->data, d->data, length, mpi_type, mpi_op, source, \
428         MPI_COMM_WORLD);
429  }
430         
431     
432  return Py_BuildValue("i", err);
433}
434
435
436
437/*********************************************************/
438/* MPI calls rank, size, finalize, abort                 */
439/*                                                       */
440/*********************************************************/
441
442static PyObject * rank(PyObject *self, PyObject *args) {
443  int myid;
444
445  MPI_Comm_rank(MPI_COMM_WORLD,&myid);
446  return Py_BuildValue("i", myid);
447}
448
449static PyObject * size(PyObject *self, PyObject *args) {
450  int numprocs; 
451
452  MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
453  return Py_BuildValue("i", numprocs);
454}
455 
456static PyObject * Get_processor_name(PyObject *self, PyObject *args) { 
457  char processor_name[MPI_MAX_PROCESSOR_NAME];
458  int  namelen;
459
460  MPI_Get_processor_name(processor_name,&namelen);
461  return Py_BuildValue("s#", processor_name, namelen);
462}   
463 
464static PyObject * Finalize(PyObject *self, PyObject *args) { 
465  int error;
466
467  error = MPI_Finalize();
468  return Py_BuildValue("i", error); 
469} 
470
471static PyObject * Abort(PyObject *self, PyObject *args) { 
472  int error, code=0;
473 
474  error = MPI_Abort(MPI_COMM_WORLD, code);
475  return Py_BuildValue("i", error); 
476} 
477
478static PyObject * Barrier(PyObject *self, PyObject *args) { 
479  int error;
480 
481  error = MPI_Barrier(MPI_COMM_WORLD);
482  return Py_BuildValue("i", error);   
483}   
484
485static PyObject * Wtime(PyObject *self, PyObject *args) {     
486  double t;
487 
488  t = MPI_Wtime();
489  return Py_BuildValue("d", t);     
490}     
491 
492/**********************************/
493/* Method table for python module */
494/**********************************/
495
496static struct PyMethodDef MethodTable[] = {
497  {"size", size, METH_VARARGS}, 
498  {"rank", rank, METH_VARARGS}, 
499  {"Barrier", Barrier, METH_VARARGS},         
500  {"Wtime", Wtime, METH_VARARGS},           
501  {"Get_processor_name", Get_processor_name, METH_VARARGS},             
502  {"Finalize", Finalize, METH_VARARGS},       
503  {"Abort", Abort, METH_VARARGS},         
504  {"send_string", send_string, METH_VARARGS},
505  {"receive_string", receive_string, METH_VARARGS},     
506  {"bcast_string", bcast_string, METH_VARARGS},       
507  {"scatter_string", scatter_string, METH_VARARGS},       
508  {"gather_string", gather_string, METH_VARARGS},       
509  {"send_array", send_array, METH_VARARGS},
510  {"receive_array", receive_array, METH_VARARGS},   
511  {"bcast_array", bcast_array, METH_VARARGS},             
512  {"scatter_array", scatter_array, METH_VARARGS},             
513  {"gather_array", gather_array, METH_VARARGS},             
514  {"reduce_array", reduce_array, METH_VARARGS},             
515  {NULL, NULL}
516};
517
518
519/***************************/
520/* Initialisation Function */
521/***************************/
522
523void initmpi(){
524  int error, argc = 0; //Dummy
525  char **argv;         //Dummy
526  PyObject *m, *ModDict;
527
528  //printf("Initialising MPI\n");
529  error = MPI_Init(&argc, &argv); 
530  //printf("MPI Initialised\n"); 
531 
532  //FIXME: Make a sensible errorcheck here
533 
534  m = Py_InitModule("mpi", MethodTable);
535 
536  // to handle MPI symbolic constants
537  ModDict = PyModule_GetDict(m); 
538  SetDictInt("MPI_ANY_TAG", MPI_ANY_TAG);
539  SetDictInt("MPI_ANY_SOURCE", MPI_ANY_SOURCE);
540  SetDictInt("mpi_MAX", mpi_MAX);
541  SetDictInt("mpi_MIN", mpi_MIN);
542  SetDictInt("mpi_SUM", mpi_SUM);
543  SetDictInt("mpi_PROD", mpi_PROD);
544  SetDictInt("mpi_LAND", mpi_LAND);
545  SetDictInt("mpi_BAND", mpi_BAND);
546  SetDictInt("mpi_LOR", mpi_LOR);
547  SetDictInt("mpi_BOR", mpi_BOR);
548  SetDictInt("mpi_LXOR", mpi_LXOR);
549  SetDictInt("mpi_BXOR", mpi_BXOR);
550  SetDictInt("mpi_MAXLOC", mpi_MAXLOC);
551  SetDictInt("mpi_MINLOC", mpi_MINLOC);
552  SetDictInt("mpi_REPLACE", mpi_REPLACE);
553
554  //SetDictInt("MPI_COMM_WORLD", MPI_COMM_WORLD); 
555   
556  import_array();     //Necessary for handling of NumPY structures 
557}
558
559 
560 
561 
562 
563/*********************************************************************/
564/* OBSOLETE STUFF                                                    */
565/*********************************************************************/
566
567/******************************************/
568/* keep for doc of Numeric arrays etc     */ 
569/******************************************/
570
571void print_real_array(PyArrayObject *x) { 
572  int i;
573  for (i=0; i<x->dimensions[0]; i++) {
574    printf("%f ", *(double*) (x->data + i*x->strides[0]));
575  }
576}
577
578void print_int_array(PyArrayObject *x) { 
579  int i;
580  for (i=0; i<x->dimensions[0]; i++) {
581    printf("%d ", *(int*) (x->data + i*x->strides[0]));
582  }
583}
584
585
586/*********************************************************/
587/* send_real_array                                       */
588/* Send Numeric array of double floating point numbers   */
589/*                                                       */
590/*********************************************************/
591static PyObject *send_real_array(PyObject *self, PyObject *args) {
592  PyObject *input;
593  PyArrayObject *x;
594  int destination, tag, err;
595 
596  /* process the parameters */
597  if (!PyArg_ParseTuple(args, "Oii", &input, &destination, &tag))
598    return NULL;
599
600  /* Make Numeric array from general sequence type (no cost if already Numeric)*/   
601  x = (PyArrayObject *)
602    PyArray_ContiguousFromObject(input, PyArray_DOUBLE, 0, 0);
603
604  /* call the MPI routine */
605  err = MPI_Send(x->data, x->dimensions[0], MPI_DOUBLE, destination, tag,\
606           MPI_COMM_WORLD);
607
608  Py_DECREF(x);                           
609  return Py_BuildValue("i", err);
610}
611
612/**********************************************************/
613/* receive_real_array                                     */
614/* Receive Numeric array of double floating point numbers */
615/*                                                        */
616/**********************************************************/
617static PyObject *receive_real_array(PyObject *self, PyObject *args) {
618  PyArrayObject *x;
619  int source, tag, err;
620  MPI_Status status;
621
622  /* process the parameters */
623  if (!PyArg_ParseTuple(args, "Oii", &x, &source, &tag))
624    return NULL;
625 
626  /* call the MPI routine */
627  err =  MPI_Recv(x->data, x->dimensions[0], MPI_DOUBLE, source, tag, \
628         MPI_COMM_WORLD, &status);
629
630
631  return Py_BuildValue("i", err);
632}
633 
634
635
Note: See TracBrowser for help on using the repository browser.