 |
» |
|
|
 |
This C++ program generates a virtual topology. The class Node represents
a node in a 2-D torus. Each process is assigned a node or nothing.
Each node holds integer data, and the shift operation exchanges the
data with its neighbors. Thus, north-east-south-west shifting returns the
initial data.  |
#include <stdio.h> #include <mpi.h> #define NDIMS 2 typedef enum { NORTH, SOUTH, EAST, WEST } Direction; // A node in 2-D torus class Node { private: MPI_Comm comm; int dims[NDIMS], coords[NDIMS]; int grank, lrank; int data; public: Node(void); ~Node(void); void profile(void); void print(void); void shift(Direction); }; // A constructor Node::Node(void) { int i, nnodes, periods[NDIMS]; // Create a balanced distribution MPI_Comm_size(MPI_COMM_WORLD, &nnodes); for (i = 0; i < NDIMS; i++) { dims[i] = 0; } MPI_Dims_create(nnodes, NDIMS, dims); // Establish a cartesian topology communicator for (i = 0; i < NDIMS; i++) { periods[i] = 1; } MPI_Cart_create(MPI_COMM_WORLD, NDIMS, dims, periods, 1, &comm); // Initialize the data MPI_Comm_rank(MPI_COMM_WORLD, &grank); if (comm == MPI_COMM_NULL) { lrank = MPI_PROC_NULL; data = -1; } else { MPI_Comm_rank(comm, &lrank); data = lrank; MPI_Cart_coords(comm, lrank, NDIMS, coords); } } // A destructor Node::~Node(void) { if (comm != MPI_COMM_NULL) { MPI_Comm_free(&comm); } } // Shift function void Node::shift(Direction dir) { if (comm == MPI_COMM_NULL) { return; } int direction, disp, src, dest; if (dir == NORTH) { direction = 0; disp = -1; } else if (dir == SOUTH) { direction = 0; disp = 1; } else if (dir == EAST) { direction = 1; disp = 1; } else { direction = 1; disp = -1; } MPI_Cart_shift(comm, direction, disp, &src, &dest); MPI_Status stat; MPI_Sendrecv_replace(&data, 1, MPI_INT, dest, 0, src, 0, comm, &stat); } // Synchronize and print the data being held void Node::print(void) { if (comm != MPI_COMM_NULL) { MPI_Barrier(comm); if (lrank == 0) { puts(""); } // line feed MPI_Barrier(comm); printf("(%d, %d) holds %d\n", coords[0], coords[1], data); } } // Print object's profile void Node::profile(void) { // Non-member does nothing if (comm == MPI_COMM_NULL) { return; } // Print "Dimensions" at first if (lrank == 0) { printf("Dimensions: (%d, %d)\n", dims[0], dims[1]); } MPI_Barrier(comm); // Each process prints its profile printf("global rank %d: cartesian rank %d, coordinate (%d, %d)\n", grank, lrank, coords[0], coords[1]); } // Program body // // Define a torus topology and demonstrate shift operations. // void body(void) { Node node; node.profile(); node.print(); node.shift(NORTH); node.print(); node.shift(EAST); node.print(); node.shift(SOUTH); node.print(); node.shift(WEST); node.print(); } // // Main program---it is probably a good programming practice to call // MPI_Init() and MPI_Finalize() here. // int main(int argc, char **argv) { MPI_Init(&argc, &argv); body(); MPI_Finalize(); } |
 |
cart
output |  |
The output from running the cart executable is shown below.
The application was run with -np = 4. Dimensions: (2, 2) global rank 0: cartesian rank 0, coordinate (0, 0) global rank 1: cartesian rank 1, coordinate (0, 1) global rank 3: cartesian rank 3, coordinate (1, 1) global rank 2: cartesian rank 2, coordinate (1, 0) (0, 0) holds 0 (1, 0) holds 2 (1, 1) holds 3 (0, 1) holds 1 (0, 0) holds 2 (1, 0) holds 0 (0, 1) holds 3 (1, 1) holds 1 (0, 0) holds 3 (0, 1) holds 2 (1, 0) holds 1 (1, 1) holds 0 (0, 0) holds 1 (1, 0) holds 3 (0, 1) holds 0 (1, 1) holds 2 (0, 0) holds 0 (1, 0) holds 2 (0, 1) holds 1 (1, 1) holds 3
|
|