rookiehpc / rookiehpc.github.io

A website covering major HPC technologies, designed to welcome contributions.
GNU Affero General Public License v3.0
56 stars 12 forks source link

Add a program utilizing `MPI_IN_PLACE` in scattering #318

Closed Ross-Li closed 1 year ago

Ross-Li commented 1 year ago

There already exists a program using MPI_IN_PLACE in gathering. I would like to add a program utilizing MPI_IN_PLACE in scattering:

/**
 * @author RookieHPC
 * @brief Original source code at https://rookiehpc.github.io/mpi/docs/mpi_in_place/index.html
 * @brief Illustrates how to use an in-place scatter. This is a way to scatter 
 * from master process to each other process EXCEPT itself.
 * 
 * How to compile this code?
 * mpic++ MPI_IN_PLACE_scatter.cpp -o MPI_IN_PLACE_scatter
 * 
 * How to run this code?
 * mpirun -np 4 ./MPI_IN_PLACE_scatter
 * 
 * @remark {About why certain parameters can be NULL, see}
 * @link https://www.mcs.anl.gov/research/projects/mpi/mpi-standard/mpi-report-2.0/node145.htm @endlink
 * "The ``in place`` option for intracommunicators is specified by passing MPI_IN_PLACE 
 * as the value of sendbuf at the root. In such a case, sendcount and sendtype are 
 * ignored, and the contribution of the root to the gathered vector is assumed to be
 * already in the correct place in the receive buffer"
 **/

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

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

    // Get number of processes and check that 4 processes are used
    int size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    if (size != 4) {
        printf("This application is meant to be run with 4 MPI processes.\n");
        MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
    }

    // Determine root's rank
    //* Change this `root_rank` to 0, 1, 2 or 3 to see different results.
    int root_rank = 0;

    // Get my rank
    int my_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    // Declare my value in each process
    int my_value;

    if (my_rank == root_rank) {
        my_value = 999;

        // Initialize the buffer array for scattering
        int to_scatter[4] = {90, 100, 200, 300};

        printf("Root process's to_scatter: %d, %d, %d, %d \n", to_scatter[0], to_scatter[1], to_scatter[2], to_scatter[3]);

        MPI_Scatter(
            to_scatter,     // sendbuf
            1,              // sendcount
            MPI_INT,        // sendtype
            //* This is where `MPI_IN_PLACE` is used 
            MPI_IN_PLACE,   // recvbuf
            //* Can replace `recvcount` and `recvtype` to NULL. Will produce 
            //* warnings, but runs just fine
            1,              // recvcount
            MPI_INT,        // recvtype
            root_rank, 
            MPI_COMM_WORLD
        );

        printf("Value scattered on root process: %d \n", my_value);

    } else {
        MPI_Scatter(
            NULL,           // sendbuf
            //* Can replace `sendcount` and `sendtype` to NULL. Will produce 
            //* warnings, but runs just fine
            1,              // sendcount
            MPI_INT,        // sendtype
            //* `recvbuf` CAN'T be `buffer`, because slave process can't access master 
            &my_value,      // recvbuf
            1,              // recvcount
            MPI_INT,        // recvtype
            root_rank,      
            MPI_COMM_WORLD
        );
        printf("Values scattered on process %d: %d \n", my_rank, my_value);
    }

    MPI_Finalize();
    return EXIT_SUCCESS;
}

A sample print result is:

Value scattered on root process: 999 
Values scattered on process 1: 100 
Values scattered on process 2: 200 
Values scattered on process 3: 300 
rookiehpc commented 1 year ago

Hi @Ross-Li,

on the MPI process whose rank equals root_rank, the variable my_value is not used in the MPI_Scatter. The value scattered by the root MPI process to itself is 90 based on your example.

This example may come across as confusing, if you were to state its main objective, how would you describe it?

Note: do not replace integers with NULL, semantically you are mixing integral values and a constant representing the bottom value for addresses. The fact that NULL translates to 0 should not encourage you to use it in other contexts than addresses. This is one of the reason that led to the implementation of nullptr in C++ for instance.

Ross-Li commented 1 year ago

You do have a point, the objective of this program is not clear enough. This is a attempt of me trying to do something, but this program doesn't manifest nor achieve my goal. I finally achieved what I was trying to do with MPI_Scatterv() and it is a bit different from the example code you have about MPI_Scatterv() and I am considering whether to submitting another issue about it.

About do not replace integer with NULL, thanks for the advice! I won't do that in actual code though, I was just noting what is going to happen if I do so.