2004-01-25 02:17:43 +03:00
|
|
|
/*
|
2007-03-17 02:11:45 +03:00
|
|
|
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
|
2005-11-05 22:57:48 +03:00
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
|
|
|
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
2004-11-28 23:09:25 +03:00
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
|
|
* University of Stuttgart. All rights reserved.
|
2005-03-24 15:43:37 +03:00
|
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
2012-08-03 05:09:59 +04:00
|
|
|
* Copyright (c) 2012 Los Alamos National Security, LLC. All rights
|
|
|
|
* reserved.
|
2004-11-22 04:38:40 +03:00
|
|
|
* $COPYRIGHT$
|
|
|
|
*
|
|
|
|
* Additional copyrights may follow
|
|
|
|
*
|
2004-01-25 02:17:43 +03:00
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
2004-06-07 19:33:53 +04:00
|
|
|
#include "ompi_config.h"
|
2004-01-25 02:17:43 +03:00
|
|
|
|
2006-02-12 04:33:29 +03:00
|
|
|
#include "ompi/mpi/c/bindings.h"
|
2009-04-29 05:32:14 +04:00
|
|
|
#include "ompi/runtime/params.h"
|
|
|
|
#include "ompi/communicator/communicator.h"
|
|
|
|
#include "ompi/errhandler/errhandler.h"
|
2004-01-25 02:17:43 +03:00
|
|
|
|
2009-05-07 00:11:28 +04:00
|
|
|
#if OPAL_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES
|
2004-01-25 02:17:43 +03:00
|
|
|
#pragma weak MPI_Dims_create = PMPI_Dims_create
|
|
|
|
#endif
|
|
|
|
|
2004-06-07 19:33:53 +04:00
|
|
|
#if OMPI_PROFILING_DEFINES
|
2006-02-12 04:33:29 +03:00
|
|
|
#include "ompi/mpi/c/profile/defines.h"
|
2004-04-20 22:50:43 +04:00
|
|
|
#endif
|
|
|
|
|
2004-07-30 06:58:53 +04:00
|
|
|
static const char FUNC_NAME[] = "MPI_Dims_create";
|
|
|
|
|
2004-07-31 02:06:09 +04:00
|
|
|
/* static functions */
|
|
|
|
static int assignnodes(int ndim, int nfactor, int *pfacts, int *counts, int **pdims);
|
|
|
|
static int getfactors(int num, int nprime, int *primes, int **pcounts);
|
|
|
|
static int getprimes(int num, int *pnprime, int **pprimes);
|
2004-07-30 06:58:53 +04:00
|
|
|
|
2004-07-31 02:06:09 +04:00
|
|
|
|
|
|
|
/*
|
2004-09-24 14:30:19 +04:00
|
|
|
* This is a utility function, no need to have anything in the lower
|
|
|
|
* layer for this at all
|
2004-07-31 02:06:09 +04:00
|
|
|
*/
|
2012-08-03 05:09:59 +04:00
|
|
|
int MPI_Dims_create(int nnodes, int ndims, int dims[])
|
2004-07-30 06:58:53 +04:00
|
|
|
{
|
2004-07-31 02:06:09 +04:00
|
|
|
int i;
|
|
|
|
int freeprocs;
|
|
|
|
int freedims;
|
|
|
|
int nprimes;
|
|
|
|
int *primes;
|
|
|
|
int *factors;
|
|
|
|
int *procs;
|
|
|
|
int *p;
|
|
|
|
int err;
|
2007-03-17 02:11:45 +03:00
|
|
|
|
2008-02-20 01:15:52 +03:00
|
|
|
OPAL_CR_NOOP_PROGRESS();
|
2007-03-17 02:11:45 +03:00
|
|
|
|
2004-07-31 02:06:09 +04:00
|
|
|
if (MPI_PARAM_CHECK) {
|
|
|
|
OMPI_ERR_INIT_FINALIZE(FUNC_NAME);
|
|
|
|
|
2007-07-31 13:01:39 +04:00
|
|
|
if (NULL == dims) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE (MPI_COMM_WORLD,
|
|
|
|
MPI_ERR_ARG, FUNC_NAME);
|
|
|
|
}
|
|
|
|
|
2004-07-31 02:06:09 +04:00
|
|
|
if (1 > ndims) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE (MPI_COMM_WORLD,
|
|
|
|
MPI_ERR_DIMS, FUNC_NAME);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get # of free-to-be-assigned processes and # of free dimensions */
|
|
|
|
freeprocs = nnodes;
|
|
|
|
freedims = 0;
|
|
|
|
for (i = 0, p = dims; i < ndims; ++i,++p) {
|
|
|
|
if (*p == 0) {
|
|
|
|
++freedims;
|
|
|
|
} else if ((*p < 0) || ((nnodes % *p) != 0)) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE (MPI_COMM_WORLD, MPI_ERR_DIMS,
|
|
|
|
FUNC_NAME);
|
|
|
|
} else {
|
|
|
|
freeprocs /= *p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (freedims == 0) {
|
|
|
|
if (freeprocs == 1) {
|
|
|
|
return MPI_SUCCESS;
|
|
|
|
}
|
|
|
|
return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_DIMS,
|
|
|
|
FUNC_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (freeprocs < 1) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_DIMS,
|
|
|
|
FUNC_NAME);
|
|
|
|
}
|
|
|
|
else if (freeprocs == 1) {
|
|
|
|
for (i = 0; i < ndims; ++i, ++dims) {
|
|
|
|
if (*dims == 0) {
|
|
|
|
*dims = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return MPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute the relevant prime numbers for factoring */
|
|
|
|
if (MPI_SUCCESS != (err = getprimes(freeprocs, &nprimes, &primes))) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, err,
|
|
|
|
FUNC_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Factor the number of free processes */
|
|
|
|
if (MPI_SUCCESS != (err = getfactors(freeprocs, nprimes, primes, &factors))) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, err,
|
|
|
|
FUNC_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assign free processes to free dimensions */
|
|
|
|
if (MPI_SUCCESS != (err = assignnodes(freedims, nprimes, primes, factors, &procs))) {
|
|
|
|
return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, err,
|
|
|
|
FUNC_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return assignment results */
|
|
|
|
p = procs;
|
|
|
|
for (i = 0; i < ndims; ++i, ++dims) {
|
|
|
|
if (*dims == 0) {
|
|
|
|
*dims = *p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free((char *) primes);
|
|
|
|
free((char *) factors);
|
|
|
|
free((char *) procs);
|
|
|
|
|
|
|
|
/* all done */
|
|
|
|
return MPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* assignnodes
|
|
|
|
*
|
|
|
|
* Function: - assign processes to dimensions
|
|
|
|
* - get "best-balanced" grid
|
|
|
|
* - greedy bin-packing algorithm used
|
|
|
|
* - sort dimensions in decreasing order
|
|
|
|
* - dimensions array dynamically allocated
|
|
|
|
* Accepts: - # of dimensions
|
|
|
|
* - # of prime factors
|
|
|
|
* - array of prime factors
|
|
|
|
* - array of factor counts
|
|
|
|
* - ptr to array of dimensions (returned value)
|
|
|
|
* Returns: - 0 or ERROR
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
assignnodes(int ndim, int nfactor, int *pfacts, int *counts, int **pdims)
|
|
|
|
{
|
|
|
|
int *bins;
|
|
|
|
int i, j;
|
|
|
|
int n;
|
|
|
|
int f;
|
|
|
|
int *p;
|
|
|
|
int *pmin;
|
|
|
|
|
|
|
|
if (0 >= ndim) {
|
|
|
|
return MPI_ERR_DIMS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate and initialize the bins */
|
|
|
|
bins = (int *) malloc((unsigned) ndim * sizeof(int));
|
|
|
|
if (NULL == bins) {
|
|
|
|
return MPI_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
*pdims = bins;
|
2004-07-30 06:58:53 +04:00
|
|
|
|
2004-07-31 02:06:09 +04:00
|
|
|
for (i = 0, p = bins; i < ndim; ++i, ++p) {
|
|
|
|
*p = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop assigning factors from the highest to the lowest */
|
|
|
|
for (j = nfactor - 1; j >= 0; --j) {
|
|
|
|
f = pfacts[j];
|
|
|
|
for (n = counts[j]; n > 0; --n) {
|
|
|
|
/* Assign a factor to the smallest bin */
|
|
|
|
pmin = bins;
|
|
|
|
for (i = 1, p = pmin + 1; i < ndim; ++i, ++p) {
|
|
|
|
if (*p < *pmin) {
|
|
|
|
pmin = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*pmin *= f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort dimensions in decreasing order (O(n^2) for now) */
|
|
|
|
for (i = 0, pmin = bins; i < ndim - 1; ++i, ++pmin) {
|
|
|
|
for (j = i + 1, p = pmin + 1; j < ndim; ++j, ++p) {
|
|
|
|
if (*p > *pmin) {
|
|
|
|
n = *p;
|
|
|
|
*p = *pmin;
|
|
|
|
*pmin = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-07-30 06:58:53 +04:00
|
|
|
|
2004-07-31 02:06:09 +04:00
|
|
|
return MPI_SUCCESS;
|
2004-01-25 02:17:43 +03:00
|
|
|
}
|
2004-07-31 02:06:09 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* getfactors
|
|
|
|
*
|
|
|
|
* Function: - factorize a number
|
|
|
|
* Accepts: - number
|
|
|
|
* - # of primes
|
|
|
|
* - array of primes
|
|
|
|
* - ptr to array of counts (returned value)
|
|
|
|
* Returns: - 0 or ERROR
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
getfactors(int num, int nprime, int *primes, int **pcounts)
|
|
|
|
{
|
|
|
|
int *counts;
|
|
|
|
int i;
|
|
|
|
int *p;
|
|
|
|
int *c;
|
|
|
|
|
|
|
|
if (0 >= nprime) {
|
|
|
|
return MPI_ERR_INTERN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate the factor counts array */
|
|
|
|
counts = (int *) malloc((unsigned) nprime * sizeof(int));
|
|
|
|
if (NULL == counts) {
|
|
|
|
return MPI_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pcounts = counts;
|
|
|
|
|
|
|
|
/* Loop over the prime numbers */
|
|
|
|
i = nprime - 1;
|
|
|
|
p = primes + i;
|
|
|
|
c = counts + i;
|
|
|
|
|
|
|
|
for (; i >= 0; --i, --p, --c) {
|
|
|
|
*c = 0;
|
|
|
|
while ((num % *p) == 0) {
|
|
|
|
++(*c);
|
|
|
|
num /= *p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (1 != num) {
|
|
|
|
return MPI_ERR_INTERN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* getprimes
|
|
|
|
*
|
|
|
|
* Function: - get primes smaller than number
|
|
|
|
* - array of primes dynamically allocated
|
|
|
|
* Accepts: - number
|
|
|
|
* - ptr # of primes (returned value)
|
|
|
|
* - ptr array of primes (returned values)
|
|
|
|
* Returns: - 0 or ERROR
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
getprimes(int num, int *pnprime, int **pprimes) {
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
int n;
|
|
|
|
int size;
|
|
|
|
int *primes;
|
|
|
|
|
|
|
|
/* Allocate the array of primes */
|
|
|
|
size = (num / 2) + 1;
|
|
|
|
primes = (int *) malloc((unsigned) size * sizeof(int));
|
|
|
|
if (NULL == primes) {
|
|
|
|
return MPI_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
*pprimes = primes;
|
|
|
|
|
|
|
|
/* Find the prime numbers */
|
|
|
|
i = 0;
|
|
|
|
primes[i++] = 2;
|
|
|
|
|
|
|
|
for (n = 3; n <= num; n += 2) {
|
|
|
|
for (j = 1; j < i; ++j) {
|
|
|
|
if ((n % primes[j]) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == i) {
|
|
|
|
if (i >= size) {
|
|
|
|
return MPI_ERR_DIMS;
|
|
|
|
}
|
|
|
|
primes[i++] = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*pnprime = i;
|
|
|
|
return MPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|