Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MPI gather/reduce operation confusion?

In the boost tutorial there are examples of gather and reduce operations. The code for gather is as follows:

#include <boost/mpi.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
namespace mpi = boost::mpi;

int main(int argc, char* argv[])
{
  mpi::environment env(argc, argv);
  mpi::communicator world;

  std::srand(time(0) + world.rank());
  int my_number = std::rand();
  if (world.rank() == 0) {
    std::vector<int> all_numbers;
    gather(world, my_number, all_numbers, 0);
    for (int proc = 0; proc < world.size(); ++proc)
      std::cout << "Process #" << proc << " thought of "
                << all_numbers[proc] << std::endl;
  } else {
    gather(world, my_number, 0);
  }

  return 0;
}

And the example for reduce is as follows:

#include <boost/mpi.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::mpi;

int main(int argc, char* argv[])
{
  mpi::environment env(argc, argv);
  mpi::communicator world;

  std::srand(time(0) + world.rank());
  int my_number = std::rand();

  if (world.rank() == 0) {
    int minimum;
    reduce(world, my_number, minimum, mpi::minimum<int>(), 0);
    std::cout << "The minimum value is " << minimum << std::endl;
  } else {
    reduce(world, my_number, mpi::minimum<int>(), 0);
  }

  return 0;
}

In both of these examples we have an if/else conditional as follows:

if(world.rank() == 0){
  //gather or reduce operation
  //Output
}else{
  //gather or reduce operation
}

What I fail to understand here is the difference between the collective operation in the if vs. whats in the else? There's a difference in the number of parameters but I don't quite understand how the logic works out.

Thanks

like image 641
sc_ray Avatar asked Jul 11 '12 18:07

sc_ray


People also ask

What does MPI Gather do?

MPI_Gather is the inverse of MPI_Scatter . Instead of spreading elements from one process to many processes, MPI_Gather takes elements from many processes and gathers them to one single process. This routine is highly useful to many parallel algorithms, such as parallel sorting and searching.

How does MPI reduce work?

MPI_Reduce is called with a root process of 0 and using MPI_SUM as the reduction operation. The four numbers are summed to the result and stored on the root process. It is also useful to see what happens when processes contain multiple elements. The illustration below shows reduction of multiple numbers per process.

Which of the following function reduces values on all processes to a single value?

The min and max functions are examples of a functional-style programming concept called reduction. They reduce a collection of values to a single value.


1 Answers

MPI has two types of collective operations - ones that have a designated "root" process and others that have not. Operations with designated root are broadcast (root process sends the same data to all processes), scatters (root process scatters its data to all processes), gathers (root process collects data from all processes) and reductions (root process gathers data from all processes while applying reduction over it). In the MPI standard those operations typically have forms similar to:

MPI_SCATTER(sendbuf, sendcount, sendtype,
            recvbuf, recvcount, recvtype, root, comm)

This MPI call has both input and output arguments and it has to be used in all processes, including the root one, but the input arguments (sendbuf, sendcount, sendtype) are only significant in the process whose rank equals root and are ignored in all other processes.

MPI was designed for portability and thus MPI calls were designed so that they can be implemented in the same way in both C and Fortran 77 - both languages did not support function overloading or optional arguments at the time when the MPI standard was designed. (Un-)fortunately C++ libraries like boost::mpi have taken on the liberty that C++ provides in overloading functions by providing versions of those calls that effectively hide the unused arguments. Now it is immediately obvious that a call to gather(world, my_number, 0) has no output argument and hence it has to be used in processes that are not the root of the operation while gather(world, my_number, all_numbers, 0) has an output argument and hence has to be used only in the root. This creates some asymmetry in writing the code - you have to do things like if (world.rank() == root) { ... } else { ... }.

I as a hardcore MPI user consider this ugly but there are other people who do not share my opinion. I guess... it depends.

like image 178
Hristo Iliev Avatar answered Sep 28 '22 16:09

Hristo Iliev