14

This is a pretty basic MPI question, but I can't wrap my head around it. I have a main function that calls another function that uses MPI. I want the main function to execute in serial, and the other function to execute in parallel. My code is like this:

int main (int argc, char *argv[])
{
    //some serial code goes here
    parallel_function(arg1, arg2);
    //some more serial code goes here
}

void parallel_function(int arg1, int arg2)
{
    //init MPI and do some stuff in parallel
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &p);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    //now do some parallel stuff
    //....
    //finalize to end MPI??
    MPI_Finalize();
}

My code runs fine and gets the expected output, but the issue is that the main function is also being run in separate processes and so the serial code executes more than once. I don't know how it's running multiple times, because I haven't even called MPI_Init yet (if I printf in main before I call parallel_function, I see multiple printf's)

How can I stop my program running in parallel after I'm done?

Thanks for any responses!

Alex Aylwin
  • 195
  • 1
  • 8

2 Answers2

10

Have a look at this answer.

Short story: MPI_Init and MPI_Finalize do not mark the beginning and end of parallel processing. MPI processes run in parallel in their entirety.

Community
  • 1
  • 1
suszterpatt
  • 8,187
  • 39
  • 60
  • Thanks, that makes more sense. I can't believe I didn't check that answer, I looked at all the MPI posts. I must've ignored it because it said 'windows'. – Alex Aylwin Jan 31 '12 at 18:51
  • That's not entirely true. The MPI standard *does not specify* the state before init or after finalize. It could be 1 proc or n proc. In practice, all modern implementations give you n, but there have been hosted implementations where that's not the case. – Jeff Hammond Sep 05 '15 at 21:01
10

@suszterpatt is correct to state that "MPI processes run in parallel in their entirety". When you run a parallel program using, for example, mpirun or mpiexec this starts the number of processes you requested (with the -n flag) and each process begins execution at the start of main. So in your example code

int main (int argc, char *argv[])
{
    //some serial code goes here
    parallel_function(arg1, arg2);
    //some more serial code goes here
}

every process will execute the //some serial code goes here and //some more serial code goes here parts (and of course they will all call parallel_function). There isn't one master process which calls parallel_function and then spawns other processes once MPI_Init is called.

Generally it is best to avoid doing what you are doing: MPI_Init should be one of the first function calls in your program (ideally it should be the first). In particular, take note of the following (from here):

The MPI standard does not say what a program can do before an MPI_INIT or after an MPI_FINALIZE. In the MPICH implementation, you should do as little as possible. In particular, avoid anything that changes the external state of the program, such as opening files, reading standard input or writing to standard output.

Not respecting this can lead to some nasty bugs.

It is better practice to rewrite your code to something like the following:

int main (int argc, char *argv[])
{

    // Initialise MPI
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &p);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    // Serial part: executed only by process with rank 0
    if (my_rank==0)
    {
        // Some serial code goes here
    }

    // Parallel part: executed by all processes.

    // Serial part: executed only by process with rank 0
    if (my_rank==0)
    {
        // Some more serial code goes here
    }

    // Finalize MPI
    MPI_Finalize();

    return 0;

}

Note: I am not a C programmer, so use the above code with care. Also, shouldn't main always return something, especially when defined as int main()?

Chris
  • 44,602
  • 16
  • 137
  • 156
  • Just noticed that my example code follows the template given in the accepted answer to http://stackoverflow.com/questions/2015673/mpi-usage-problem/2291105#2291105 – Chris Feb 01 '12 at 11:29
  • 1
    "each process begins execution at the start of main.": *technically*, they begin with the initialization of static objects and whatnot. http://stackoverflow.com/questions/4652855/what-runs-before-main ;) – suszterpatt Feb 02 '12 at 03:20
  • @suszterpatt Of course, but from a programmers point of view you can assume that the OS does something (e.g. gets command line arguments and populates `argc` and `argv`) and then the stuff you coded begins at `main`. What the OS does shouldn't affect how you program. – Chris Feb 02 '12 at 09:31
  • 1
    I was being overly pedantic of course, though it may be worth noting that the constructors of static objects, which are possibly user-written, also run before `main`. This is only relevant inasmuch as MPI calls must be avoided in such constructors, even if `MPI_Init` is the first line of `main`. – suszterpatt Feb 02 '12 at 12:03
  • @Chris, Is there a way I can have the MPI part of the code in a seperate file (Say a .DLL) and have a Master C/C++ which will load this .DLL? I also wanted to know if without using`mpirun` or `mpiexec` can I run my MPI program and pass message specifically with any other system (Meaning MPI_Send (.. /* specific to an IP Adress */) and MPI_Recv (/*Specifically from an IP */)? – programmer Jul 20 '15 at 14:23
  • @programmer I'm not sure if there is, but I would question why you would want to do this. The portion of the MPI specification I quote states that you should do as little as possible before a call to `MPI_Init`, this includes loading in external dlls. As to your second question, I have no idea, you will have to look at the specification for those functions to see if what you want to do is possible. If you have a new question, it is better to post this as a new question, rather than as a comment to an old question or answer. – Chris Jul 20 '15 at 14:46
  • @Chris thanks. I actually wanted to create a server which waits for a request. Once I get the request I want to load a dll which will contain mpi related code and will execute in parallel. Once the execution is over the read the value and send the response back. Second question I will open a new issue. – programmer Jul 20 '15 at 14:54