/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ /* * * (C) 2001 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ #include "mpiimpl.h" #include "topo.h" /* -- Begin Profiling Symbol Block for routine MPI_Cart_create */ #if defined(HAVE_PRAGMA_WEAK) #pragma weak MPI_Cart_create = PMPI_Cart_create #elif defined(HAVE_PRAGMA_HP_SEC_DEF) #pragma _HP_SECONDARY_DEF PMPI_Cart_create MPI_Cart_create #elif defined(HAVE_PRAGMA_CRI_DUP) #pragma _CRI duplicate MPI_Cart_create as PMPI_Cart_create #elif defined(HAVE_WEAK_ATTRIBUTE) int MPI_Cart_create(MPI_Comm comm_old, int ndims, const int dims[], const int periods[], int reorder, MPI_Comm *comm_cart) __attribute__((weak,alias("PMPI_Cart_create"))); #endif /* -- End Profiling Symbol Block */ /* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build the MPI routines */ #ifndef MPICH_MPI_FROM_PMPI #undef MPI_Cart_create #define MPI_Cart_create PMPI_Cart_create #endif /* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build the MPI routines */ #ifndef MPICH_MPI_FROM_PMPI #undef FUNCNAME #define FUNCNAME MPIR_Cart_create #undef FCNAME #define FCNAME MPL_QUOTE(FUNCNAME) int MPIR_Cart_create( MPID_Comm *comm_ptr, int ndims, const int dims[], const int periods[], int reorder, MPI_Comm *comm_cart ) { int i, newsize, rank, nranks, mpi_errno = MPI_SUCCESS; MPID_Comm *newcomm_ptr = NULL; MPIR_Topology *cart_ptr = NULL; MPIU_CHKPMEM_DECL(4); /* Set this as null incase we exit with an error */ *comm_cart = MPI_COMM_NULL; /* Check for invalid arguments */ newsize = 1; for (i=0; i comm_ptr->remote_size), mpi_errno, MPI_ERR_ARG, "**cartdim", "**cartdim %d %d", comm_ptr->remote_size, newsize); if (ndims == 0) { /* specified as a 0D Cartesian topology in MPI 2.1. Rank 0 returns a dup of COMM_SELF with the topology info attached. Others return MPI_COMM_NULL. */ rank = comm_ptr->rank; if (rank == 0) { MPID_Comm *comm_self_ptr; MPID_Comm_get_ptr(MPI_COMM_SELF, comm_self_ptr); mpi_errno = MPIR_Comm_dup_impl(comm_self_ptr, &newcomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Create the topology structure */ MPIU_CHKPMEM_MALLOC(cart_ptr,MPIR_Topology*,sizeof(MPIR_Topology), mpi_errno, "cart_ptr" ); cart_ptr->kind = MPI_CART; cart_ptr->topo.cart.nnodes = 1; cart_ptr->topo.cart.ndims = 0; /* make mallocs of size 1 int so that they get freed as part of the normal free mechanism */ MPIU_CHKPMEM_MALLOC(cart_ptr->topo.cart.dims,int*,sizeof(int), mpi_errno, "cart.dims"); MPIU_CHKPMEM_MALLOC(cart_ptr->topo.cart.periodic,int*,sizeof(int), mpi_errno, "cart.periodic"); MPIU_CHKPMEM_MALLOC(cart_ptr->topo.cart.position,int*,sizeof(int), mpi_errno, "cart.position"); } else { *comm_cart = MPI_COMM_NULL; goto fn_exit; } } else { /* Create a new communicator as a duplicate of the input communicator (but do not duplicate the attributes) */ if (reorder) { /* Allow the cart map routine to remap the assignment of ranks to processes */ mpi_errno = MPIR_Cart_map_impl( comm_ptr, ndims, (const int *)dims, (const int *)periods, &rank ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Create the new communicator with split, since we need to reorder the ranks (including the related internals, such as the connection tables */ mpi_errno = MPIR_Comm_split_impl( comm_ptr, rank == MPI_UNDEFINED ? MPI_UNDEFINED : 1, rank, &newcomm_ptr ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } else { mpi_errno = MPIR_Comm_copy( (MPID_Comm *)comm_ptr, newsize, &newcomm_ptr ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); rank = comm_ptr->rank; } /* If this process is not in the resulting communicator, return a null communicator and exit */ if (rank >= newsize || rank == MPI_UNDEFINED) { *comm_cart = MPI_COMM_NULL; goto fn_exit; } /* Create the topololgy structure */ MPIU_CHKPMEM_MALLOC(cart_ptr,MPIR_Topology*,sizeof(MPIR_Topology), mpi_errno, "cart_ptr" ); cart_ptr->kind = MPI_CART; cart_ptr->topo.cart.nnodes = newsize; cart_ptr->topo.cart.ndims = ndims; MPIU_CHKPMEM_MALLOC(cart_ptr->topo.cart.dims,int*,ndims*sizeof(int), mpi_errno, "cart.dims"); MPIU_CHKPMEM_MALLOC(cart_ptr->topo.cart.periodic,int*,ndims*sizeof(int), mpi_errno, "cart.periodic"); MPIU_CHKPMEM_MALLOC(cart_ptr->topo.cart.position,int*,ndims*sizeof(int), mpi_errno, "cart.position"); nranks = newsize; for (i=0; itopo.cart.dims[i] = dims[i]; cart_ptr->topo.cart.periodic[i] = periods[i]; nranks = nranks / dims[i]; /* FIXME: nranks could be zero (?) */ cart_ptr->topo.cart.position[i] = rank / nranks; rank = rank % nranks; } } /* Place this topology onto the communicator */ mpi_errno = MPIR_Topology_put( newcomm_ptr, cart_ptr ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_OBJ_PUBLISH_HANDLE(*comm_cart, newcomm_ptr->handle); fn_exit: return mpi_errno; fn_fail: /* --BEGIN ERROR HANDLING-- */ MPIU_CHKPMEM_REAP(); /* --END ERROR HANDLING-- */ goto fn_exit; } #undef FUNCNAME #define FUNCNAME MPIR_Cart_create_impl #undef FCNAME #define FCNAME MPL_QUOTE(FUNCNAME) int MPIR_Cart_create_impl(MPID_Comm *comm_ptr, int ndims, const int dims[], const int periods[], int reorder, MPI_Comm *comm_cart) { int mpi_errno = MPI_SUCCESS; if (comm_ptr->topo_fns != NULL && comm_ptr->topo_fns->cartCreate != NULL) { /* --BEGIN USEREXTENSION-- */ mpi_errno = comm_ptr->topo_fns->cartCreate( comm_ptr, ndims, (const int*) dims, (const int*) periods, reorder, comm_cart ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* --END USEREXTENSION-- */ } else { mpi_errno = MPIR_Cart_create( comm_ptr, ndims, (const int*) dims, (const int*) periods, reorder, comm_cart ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } fn_exit: return mpi_errno; fn_fail: goto fn_exit; } #endif #undef FUNCNAME #define FUNCNAME MPI_Cart_create #undef FCNAME #define FCNAME MPL_QUOTE(FUNCNAME) /*@ MPI_Cart_create - Makes a new communicator to which topology information has been attached Input Parameters: + comm_old - input communicator (handle) . ndims - number of dimensions of cartesian grid (integer) . dims - integer array of size ndims specifying the number of processes in each dimension . periods - logical array of size ndims specifying whether the grid is periodic (true) or not (false) in each dimension - reorder - ranking may be reordered (true) or not (false) (logical) Output Parameters: . comm_cart - communicator with new cartesian topology (handle) Algorithm: We ignore 'reorder' info currently. .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS .N MPI_ERR_TOPOLOGY .N MPI_ERR_DIMS .N MPI_ERR_ARG @*/ int MPI_Cart_create(MPI_Comm comm_old, int ndims, const int dims[], const int periods[], int reorder, MPI_Comm *comm_cart) { int mpi_errno = MPI_SUCCESS; MPID_Comm *comm_ptr = NULL; MPID_MPI_STATE_DECL(MPID_STATE_MPI_CART_CREATE); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_CART_CREATE); /* Validate parameters, especially handles needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPIR_ERRTEST_COMM(comm_old, mpi_errno); } MPID_END_ERROR_CHECKS; } # endif /* Convert MPI object handles to object pointers */ MPID_Comm_get_ptr( comm_old, comm_ptr ); /* Validate parameters and objects (post conversion) */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { /* Validate comm_ptr */ MPID_Comm_valid_ptr( comm_ptr, mpi_errno, FALSE ); if (mpi_errno != MPI_SUCCESS) goto fn_fail; /* If comm_ptr is not valid, it will be reset to null */ if (comm_ptr) { MPIR_ERRTEST_COMM_INTRA(comm_ptr,mpi_errno); } if (ndims > 0) { MPIR_ERRTEST_ARGNULL( dims, "dims", mpi_errno ); MPIR_ERRTEST_ARGNULL( periods, "periods", mpi_errno ); } MPIR_ERRTEST_ARGNULL( comm_cart, "comm_cart", mpi_errno ); if (ndims < 0) { /* Must have a non-negative number of dimensions */ mpi_errno = MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_DIMS, "**dims", "**dims %d", 0 ); goto fn_fail; } MPIR_ERRTEST_ARGNEG( ndims, "ndims", mpi_errno ); if (comm_ptr) { MPIR_ERRTEST_COMM_INTRA( comm_ptr, mpi_errno ); } } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ mpi_errno = MPIR_Cart_create_impl( comm_ptr, ndims, (const int*) dims, (const int*) periods, reorder, comm_cart ); if (mpi_errno) goto fn_fail; /* ... end of body of routine ... */ fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_CART_CREATE); MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); return mpi_errno; fn_fail: /* --BEGIN ERROR HANDLING-- */ # ifdef HAVE_ERROR_CHECKING { mpi_errno = MPIR_Err_create_code( mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_cart_create", "**mpi_cart_create %C %d %p %p %d %p", comm_old, ndims, dims, periods, reorder, comm_cart); } # endif mpi_errno = MPIR_Err_return_comm( comm_ptr, FCNAME, mpi_errno ); /* --END ERROR HANDLING-- */ goto fn_exit; }