X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/347996b4a10c4e8579080692afa60e0afb88b60a..36fa571a13985879dc627c70ecc2340af606aa42:/src/smpi/smpi_topo.cpp diff --git a/src/smpi/smpi_topo.cpp b/src/smpi/smpi_topo.cpp index cf596ca4a7..57b45a5a49 100644 --- a/src/smpi/smpi_topo.cpp +++ b/src/smpi/smpi_topo.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2014. The SimGrid Team. +/* Copyright (c) 2014, 2017. The SimGrid Team. * All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it @@ -7,88 +7,100 @@ #include "xbt/sysdep.h" #include "smpi/smpi.h" #include "private.h" - +#include #include typedef struct s_smpi_mpi_cart_topology { - int nnodes; - int ndims; - int *dims; - int *periodic; - int *position; + int nnodes; + int ndims; + int *dims; + int *periodic; + int *position; } s_smpi_mpi_cart_topology_t; typedef struct s_smpi_mpi_graph_topology { - int nnodes; - int nedges; - int *index; - int *edges; + int nnodes; + int nedges; + int *index; + int *edges; } s_smpi_mpi_graph_topology_t; typedef struct s_smpi_dist_graph_topology { - int indegree; - int *in; - int *in_weights; - int outdegree; - int *out; - int *out_weights; - int is_weighted; + int indegree; + int *in; + int *in_weights; + int outdegree; + int *out; + int *out_weights; + int is_weighted; } s_smpi_mpi_dist_graph_topology_t; typedef struct s_smpi_mpi_topology { - MPIR_Topo_type kind; - union topo { - MPIR_Graph_Topology graph; - MPIR_Cart_Topology cart; - MPIR_Dist_Graph_Topology dist_graph; - } topo; + MPIR_Topo_type kind; + union topo { + MPIR_Graph_Topology graph; + MPIR_Cart_Topology cart; + MPIR_Dist_Graph_Topology dist_graph; + } topo; } s_smpi_mpi_topology_t; void smpi_topo_destroy(MPI_Topology topo) { - if(topo == NULL) { - return; - } - switch (topo->kind) { - case MPI_GRAPH: - // Not implemented - // smpi_graph_topo_destroy(topo->topo.graph); - break; - case MPI_CART: - smpi_cart_topo_destroy(topo->topo.cart); - break; - case MPI_DIST_GRAPH: - // Not implemented - // smpi_dist_graph_topo_destroy(topo->topo.dist_graph); - break; - default: - return; - break; - } + if(topo == nullptr) { + return; + } + switch (topo->kind) { + case MPI_CART: + smpi_cart_topo_destroy(topo->topo.cart); + break; + case MPI_GRAPH: + // This topology is not supported by SMPI yet + smpi_graph_topo_destroy(topo->topo.graph); + break; + case MPI_DIST_GRAPH: + // This topology is not supported by SMPI yet + smpi_dist_graph_topo_destroy(topo->topo.dist_graph); + break; + default: + return; + } + xbt_free(topo); } MPI_Topology smpi_topo_create(MPIR_Topo_type kind) { - MPI_Topology newTopo = static_cast(xbt_malloc(sizeof(*newTopo))); - newTopo->kind = kind; - // Allocate and initialize the right topo should be done by the caller - return newTopo; + MPI_Topology newTopo = static_cast(xbt_malloc(sizeof(*newTopo))); + newTopo->kind = kind; + // Allocate and initialize the right topo should be done by the caller + return newTopo; +} + +void smpi_graph_topo_destroy(MPIR_Graph_Topology graph) { + if (graph) { + delete[] graph->index; + delete[] graph->edges; + xbt_free(graph); + } +} + +void smpi_dist_graph_topo_destroy(MPIR_Dist_Graph_Topology dist_graph) { + if (dist_graph) { + delete[] dist_graph->in; + delete[] dist_graph->in_weights; + delete[] dist_graph->out; + delete[] dist_graph->out_weights; + xbt_free(dist_graph); + } } /******************************************************************************* * Cartesian topologies ******************************************************************************/ void smpi_cart_topo_destroy(MPIR_Cart_Topology cart) { - if (cart) { - if(cart->dims) { - free(cart->dims); - } - if(cart->periodic) { - free(cart->periodic); - } - if(cart->position) { - free(cart->position); - } - free(cart); - } + if (cart) { + delete[] cart->dims; + delete[] cart->periodic; + delete[] cart->position; + xbt_free(cart); + } } MPI_Topology smpi_cart_topo_create(int ndims) { @@ -96,234 +108,207 @@ MPI_Topology smpi_cart_topo_create(int ndims) { MPIR_Cart_Topology newCart = static_cast(xbt_malloc(sizeof(*newCart))); newCart->nnodes = 0; newCart->ndims = ndims; - newCart->dims = xbt_new(int, ndims); - newCart->periodic = xbt_new(int, ndims); - newCart->position = xbt_new(int, ndims); + newCart->dims = new int[ndims]; + newCart->periodic = new int[ndims]; + newCart->position = new int[ndims]; newTopo->topo.cart = newCart; return newTopo; } -/* reorder is ignored, don't know what would be the consequences of a dumb - * reordering but neither do I see the point of reordering*/ -int smpi_mpi_cart_create(MPI_Comm comm_old, int ndims, int dims[], - int periods[], int reorder, MPI_Comm *comm_cart) { - int retval = MPI_SUCCESS; - int i; - MPI_Topology newCart; - MPI_Group newGroup, oldGroup; - int rank, nranks, newSize; - - rank = smpi_comm_rank(comm_old); - - newSize = 1; - if(ndims != 0) { - for (i = 0 ; i < ndims ; i++) { - newSize *= dims[i]; - } - if(rank >= newSize) { - *comm_cart = MPI_COMM_NULL; - return retval; - } - newCart = smpi_cart_topo_create(ndims); - oldGroup = smpi_comm_group(comm_old); - newGroup = smpi_group_new(newSize); - for (i = 0 ; i < newSize ; i++) { - smpi_group_set_mapping(newGroup, smpi_group_index(oldGroup, i), i); - } - - newCart->topo.cart->nnodes = newSize; - - /* memcpy(newCart->topo.cart->dims, dims, */ - /* ndims * sizeof(*newCart->topo.cart->dims)); */ - /* memcpy(newCart->topo.cart->periodic, periods, */ - /* ndims * sizeof(*newCart->topo.cart->periodic)); */ - - // FIXME : code duplication... See smpi_mpi_cart_coords - nranks = newSize; - for (i=0; itopo.cart->dims[i] = dims[i]; - newCart->topo.cart->periodic[i] = periods[i]; - nranks = nranks / dims[i]; - /* FIXME: nranks could be zero (?) */ - newCart->topo.cart->position[i] = rank / nranks; - rank = rank % nranks; - } - - *comm_cart = smpi_comm_new(newGroup, newCart); - } - else { - if (rank == 0) { - newCart = smpi_cart_topo_create(ndims); - *comm_cart = smpi_comm_new(smpi_comm_group(MPI_COMM_SELF), newCart); - } - else { - *comm_cart = MPI_COMM_NULL; - } - } - return retval; +/* reorder is ignored, don't know what would be the consequences of a dumb reordering but neither do I see the point of + * reordering*/ +int smpi_mpi_cart_create(MPI_Comm comm_old, int ndims, int dims[], int periods[], int reorder, MPI_Comm *comm_cart) { + int retval = MPI_SUCCESS; + MPI_Topology newCart; + MPI_Group newGroup; + MPI_Group oldGroup; + int nranks; + + int rank = smpi_comm_rank(comm_old); + + int newSize = 1; + if(ndims != 0) { + for (int i = 0 ; i < ndims ; i++) { + newSize *= dims[i]; + } + if(rank >= newSize) { + *comm_cart = MPI_COMM_NULL; + return retval; + } + newCart = smpi_cart_topo_create(ndims); + oldGroup = smpi_comm_group(comm_old); + newGroup = smpi_group_new(newSize); + for (int i = 0 ; i < newSize ; i++) { + smpi_group_set_mapping(newGroup, smpi_group_index(oldGroup, i), i); + } + + newCart->topo.cart->nnodes = newSize; + + // FIXME : code duplication... See smpi_mpi_cart_coords + nranks = newSize; + for (int i=0; itopo.cart->dims[i] = dims[i]; + newCart->topo.cart->periodic[i] = periods[i]; + nranks = nranks / dims[i]; + /* FIXME: nranks could be zero (?) */ + newCart->topo.cart->position[i] = rank / nranks; + rank = rank % nranks; + } + + *comm_cart = smpi_comm_new(newGroup, newCart); + } else { + if (rank == 0) { + newCart = smpi_cart_topo_create(ndims); + *comm_cart = smpi_comm_new(smpi_group_copy(smpi_comm_group(MPI_COMM_SELF)), newCart); + } else { + *comm_cart = MPI_COMM_NULL; + } + } + return retval; } int smpi_mpi_cart_sub(MPI_Comm comm, const int remain_dims[], MPI_Comm *newcomm) { - MPI_Topology oldTopo = smpi_comm_topo(comm); - int oldNDims = oldTopo->topo.cart->ndims; - int i, j = 0, newNDims, *newDims = NULL, *newPeriodic = NULL; - - if (remain_dims == NULL && oldNDims != 0) { - return MPI_ERR_ARG; - } - newNDims = 0; - for (i = 0 ; i < oldNDims ; i++) { - if (remain_dims[i]) newNDims++; - } - - if (newNDims > 0) { - newDims = xbt_new(int, newNDims); - newPeriodic = xbt_new(int, newNDims); - - // that should not segfault - for (i = 0 ; j < newNDims ; i++) { - if(remain_dims[i]) { - newDims[j] = oldTopo->topo.cart->dims[i]; - newPeriodic[j] = oldTopo->topo.cart->periodic[i]; - j++; - } - } - } - return smpi_mpi_cart_create(comm, newNDims, newDims, newPeriodic, 0, newcomm); + MPI_Topology oldTopo = smpi_comm_topo(comm); + int oldNDims = oldTopo->topo.cart->ndims; + int j = 0; + int *newDims = nullptr; + int *newPeriodic = nullptr; + + if (remain_dims == nullptr && oldNDims != 0) { + return MPI_ERR_ARG; + } + int newNDims = 0; + for (int i = 0 ; i < oldNDims ; i++) { + if (remain_dims[i]) + newNDims++; + } + + if (newNDims > 0) { + newDims = xbt_new(int, newNDims); + newPeriodic = xbt_new(int, newNDims); + + // that should not segfault + for (int i = 0 ; j < newNDims ; i++) { + if(remain_dims[i]) { + newDims[j] = oldTopo->topo.cart->dims[i]; + newPeriodic[j] = oldTopo->topo.cart->periodic[i]; + j++; + } + } + } + return smpi_mpi_cart_create(comm, newNDims, newDims, newPeriodic, 0, newcomm); } - - - -int smpi_mpi_cart_coords(MPI_Comm comm, int rank, int maxdims, - int coords[]) { - int nnodes; - int i; - MPI_Topology topo = smpi_comm_topo(comm); - - nnodes = topo->topo.cart->nnodes; - for ( i=0; i < topo->topo.cart->ndims; i++ ) { - nnodes = nnodes / topo->topo.cart->dims[i]; - coords[i] = rank / nnodes; - rank = rank % nnodes; - } - return MPI_SUCCESS; +int smpi_mpi_cart_coords(MPI_Comm comm, int rank, int maxdims, int coords[]) { + MPI_Topology topo = smpi_comm_topo(comm); + int nnodes = topo->topo.cart->nnodes; + for (int i = 0; i< topo->topo.cart->ndims; i++ ) { + nnodes = nnodes / topo->topo.cart->dims[i]; + coords[i] = rank / nnodes; + rank = rank % nnodes; + } + return MPI_SUCCESS; } int smpi_mpi_cart_get(MPI_Comm comm, int maxdims, int* dims, int* periods, int* coords) { - MPI_Topology topo = smpi_comm_topo(comm); - int i; - for(i = 0 ; i < maxdims ; i++) { - dims[i] = topo->topo.cart->dims[i]; - periods[i] = topo->topo.cart->periodic[i]; - coords[i] = topo->topo.cart->position[i]; - } - return MPI_SUCCESS; + MPI_Topology topo = smpi_comm_topo(comm); + int ndims=topo->topo.cart->ndims < maxdims ? topo->topo.cart->ndims : maxdims; + for(int i = 0 ; i < ndims ; i++) { + dims[i] = topo->topo.cart->dims[i]; + periods[i] = topo->topo.cart->periodic[i]; + coords[i] = topo->topo.cart->position[i]; + } + return MPI_SUCCESS; } int smpi_mpi_cart_rank(MPI_Comm comm, int* coords, int* rank) { - MPI_Topology topo = smpi_comm_topo(comm); - int ndims = topo->topo.cart->ndims; - int multiplier, coord,i; - *rank = 0; - multiplier = 1; - - for ( i=ndims-1; i >=0; i-- ) { - coord = coords[i]; - - /* The user can give us whatever coordinates he wants. If one of them is - * out of range, either this dimension is periodic, and then we - * consider the equivalent coordinate inside the bounds, or it is not - * and then it is an error - */ - if (coord >= topo->topo.cart->dims[i]) { - if ( topo->topo.cart->periodic[i] ) { - coord = coord % topo->topo.cart->dims[i]; - } - else { - // Should I do that ? - *rank = -1; - return MPI_ERR_ARG; - } - } - else if (coord < 0) { - if(topo->topo.cart->periodic[i]) { - coord = coord % topo->topo.cart->dims[i]; - if (coord) coord = topo->topo.cart->dims[i] + coord; - } - else { - *rank = -1; - return MPI_ERR_ARG; - } - } - - *rank += multiplier * coord; - multiplier *= topo->topo.cart->dims[i]; - } - return MPI_SUCCESS; -} - -int smpi_mpi_cart_shift(MPI_Comm comm, int direction, int disp, - int *rank_source, int *rank_dest) { - MPI_Topology topo = smpi_comm_topo(comm); - int position[topo->topo.cart->ndims]; - - - if(topo->topo.cart->ndims == 0) { + MPI_Topology topo = smpi_comm_topo(comm); + int ndims = topo->topo.cart->ndims; + int coord; + *rank = 0; + int multiplier = 1; + + for (int i=ndims-1; i >=0; i-- ) { + coord = coords[i]; + + /* The user can give us whatever coordinates he wants. If one of them is out of range, either this dimension is + * periodic, and we consider the equivalent coordinate inside the bounds, or it's not and then it's an error + */ + if (coord >= topo->topo.cart->dims[i]) { + if ( topo->topo.cart->periodic[i] ) { + coord = coord % topo->topo.cart->dims[i]; + } else { + // Should I do that ? + *rank = -1; return MPI_ERR_ARG; - } - if (topo->topo.cart->ndims < direction) { - return MPI_ERR_DIMS; - } - - smpi_mpi_cart_coords(comm, smpi_comm_rank(comm), topo->topo.cart->ndims, - position); - position[direction] += disp; - - if(position[direction] < 0 || - position[direction] >= topo->topo.cart->dims[direction]) { - if(topo->topo.cart->periodic[direction]) { - position[direction] %= topo->topo.cart->dims[direction]; - smpi_mpi_cart_rank(comm, position, rank_dest); - } - else { - *rank_dest = MPI_PROC_NULL; - } - } - else { - smpi_mpi_cart_rank(comm, position, rank_dest); + } + } else if (coord < 0) { + if(topo->topo.cart->periodic[i]) { + coord = coord % topo->topo.cart->dims[i]; + if (coord) + coord = topo->topo.cart->dims[i] + coord; + } else { + *rank = -1; + return MPI_ERR_ARG; + } } - position[direction] = topo->topo.cart->position[direction] - disp; - if(position[direction] < 0 || - position[direction] >= topo->topo.cart->dims[direction]) { - if(topo->topo.cart->periodic[direction]) { - position[direction] %= topo->topo.cart->dims[direction]; - smpi_mpi_cart_rank(comm, position, rank_source); - } - else { - *rank_source = MPI_PROC_NULL; - } - } - else { - smpi_mpi_cart_rank(comm, position, rank_source); - } + *rank += multiplier * coord; + multiplier *= topo->topo.cart->dims[i]; + } + return MPI_SUCCESS; +} - return MPI_SUCCESS; +int smpi_mpi_cart_shift(MPI_Comm comm, int direction, int disp, int *rank_source, int *rank_dest) { + MPI_Topology topo = smpi_comm_topo(comm); + int position[topo->topo.cart->ndims]; + + if(topo->topo.cart->ndims == 0) { + return MPI_ERR_ARG; + } + if (topo->topo.cart->ndims < direction) { + return MPI_ERR_DIMS; + } + + smpi_mpi_cart_coords(comm, smpi_comm_rank(comm), topo->topo.cart->ndims, position); + position[direction] += disp; + + if(position[direction] < 0 || + position[direction] >= topo->topo.cart->dims[direction]) { + if(topo->topo.cart->periodic[direction]) { + position[direction] %= topo->topo.cart->dims[direction]; + smpi_mpi_cart_rank(comm, position, rank_dest); + } else { + *rank_dest = MPI_PROC_NULL; + } + } else { + smpi_mpi_cart_rank(comm, position, rank_dest); + } + + position[direction] = topo->topo.cart->position[direction] - disp; + if(position[direction] < 0 || position[direction] >= topo->topo.cart->dims[direction]) { + if(topo->topo.cart->periodic[direction]) { + position[direction] %= topo->topo.cart->dims[direction]; + smpi_mpi_cart_rank(comm, position, rank_source); + } else { + *rank_source = MPI_PROC_NULL; + } + } else { + smpi_mpi_cart_rank(comm, position, rank_source); + } + + return MPI_SUCCESS; } int smpi_mpi_cartdim_get(MPI_Comm comm, int *ndims) { - MPI_Topology topo = smpi_comm_topo(comm); + MPI_Topology topo = smpi_comm_topo(comm); - *ndims = topo->topo.cart->ndims; - return MPI_SUCCESS; + *ndims = topo->topo.cart->ndims; + return MPI_SUCCESS; } +// Everything below has been taken from ompi, but could be easily rewritten (and partially was to follow sonar rules). - -// Everything below has been taken from ompi, but could be easily rewritten. - /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology @@ -345,79 +330,75 @@ int smpi_mpi_cartdim_get(MPI_Comm comm, int *ndims) { * $HEADER$ */ - /* static functions */ static int assignnodes(int ndim, int nfactor, int *pfacts,int **pdims); static int getfactors(int num, int *nfators, int **factors); /* - * This is a utility function, no need to have anything in the lower - * layer for this at all + * This is a utility function, no need to have anything in the lower layer for this at all */ int smpi_mpi_dims_create(int nnodes, int ndims, int dims[]) { - int i; - int freeprocs; - int freedims; - int nfactors; - int *factors; - int *procs; - int *p; - int err; - - /* 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 MPI_ERR_DIMS; - - } else { - freeprocs /= *p; - } - } - - if (freedims == 0) { - if (freeprocs == 1) { - return MPI_SUCCESS; - } - return MPI_ERR_DIMS; - } - + /* Get # of free-to-be-assigned processes and # of free dimensions */ + int freeprocs = nnodes; + int freedims = 0; + int *p = dims; + for (int i = 0; i < ndims; ++i) { + if (*p == 0) { + ++freedims; + } else if ((*p < 0) || ((nnodes % *p) != 0)) { + return MPI_ERR_DIMS; + + } else { + freeprocs /= *p; + } + p++; + } + + if (freedims == 0) { if (freeprocs == 1) { - for (i = 0; i < ndims; ++i, ++dims) { - if (*dims == 0) { - *dims = 1; - } - } - return MPI_SUCCESS; - } - - /* Factor the number of free processes */ - if (MPI_SUCCESS != (err = getfactors(freeprocs, &nfactors, &factors))) { - return err; - } - - /* Assign free processes to free dimensions */ - if (MPI_SUCCESS != (err = assignnodes(freedims, nfactors, factors, &procs))) { - return err; + return MPI_SUCCESS; } + return MPI_ERR_DIMS; + } - /* Return assignment results */ - p = procs; - for (i = 0; i < ndims; ++i, ++dims) { - if (*dims == 0) { - *dims = *p++; - } + if (freeprocs == 1) { + for (int i = 0; i < ndims; ++i) { + if (*dims == 0) { + *dims = 1; + } + dims++; } - - free((char *) factors); - free((char *) procs); - - /* all done */ return MPI_SUCCESS; + } + + /* Factor the number of free processes */ + int nfactors; + int *factors; + int err = getfactors(freeprocs, &nfactors, &factors); + if (MPI_SUCCESS != err) + return err; + + /* Assign free processes to free dimensions */ + int *procs; + err = assignnodes(freedims, nfactors, factors, &procs); + if (MPI_SUCCESS != err) + return err; + + /* Return assignment results */ + p = procs; + for (int i = 0; i < ndims; ++i) { + if (*dims == 0) { + *dims = *p++; + } + dims++; + } + + delete[] factors; + delete[] procs; + + /* all done */ + return MPI_SUCCESS; } /* @@ -434,56 +415,55 @@ int smpi_mpi_dims_create(int nnodes, int ndims, int dims[]) * - ptr to array of dimensions (returned value) * Returns: - 0 or ERROR */ -static int -assignnodes(int ndim, int nfactor, int *pfacts, int **pdims) +static int assignnodes(int ndim, int nfactor, int *pfacts, 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; - - 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]; - /* 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; - } - } - } - - return MPI_SUCCESS; + int *pmin; + + if (0 >= ndim) { + return MPI_ERR_DIMS; + } + + /* Allocate and initialize the bins */ + int *bins = new int[ndim]; + + *pdims = bins; + int *p = bins; + + for (int i = 0 ; i < ndim; ++i) { + *p = 1; + p++; + } + /* Loop assigning factors from the highest to the lowest */ + for (int j = nfactor - 1; j >= 0; --j) { + int f = pfacts[j]; + /* Assign a factor to the smallest bin */ + pmin = bins; + p = pmin + 1; + for (int i = 1; i < ndim; ++i) { + if (*p < *pmin) { + pmin = p; + } + p++; + } + *pmin *= f; + } + + /* Sort dimensions in decreasing order (O(n^2) for now) */ + pmin = bins; + for (int i = 0; i < ndim - 1; ++i) { + p = pmin + 1; + for (int j = i + 1; j < ndim; ++j) { + if (*p > *pmin) { + int n = *p; + *p = *pmin; + *pmin = n; + } + p++; + } + pmin++; + } + + return MPI_SUCCESS; } /* @@ -495,41 +475,34 @@ assignnodes(int ndim, int nfactor, int *pfacts, int **pdims) * - array of prime factors * Returns: - MPI_SUCCESS or ERROR */ -static int -getfactors(int num, int *nfactors, int **factors) { - int size; - int d; - int i; - int sqrtnum; - - if(num < 2) { - (*nfactors) = 0; - (*factors) = NULL; - return MPI_SUCCESS; - } - /* Allocate the array of prime factors which cannot exceed log_2(num) entries */ - sqrtnum = ceil(sqrt(num)); - size = ceil(log(num) / log(2)); - *factors = (int *) malloc((unsigned) size * sizeof(int)); - - i = 0; - /* determine all occurences of factor 2 */ - while((num % 2) == 0) { - num /= 2; - (*factors)[i++] = 2; - } - /* determine all occurences of uneven prime numbers up to sqrt(num) */ - for(d = 3; (num > 1) && (d < sqrtnum); d += 2) { - while((num % d) == 0) { - num /= d; - (*factors)[i++] = d; - } - } - /* as we looped only up to sqrt(num) one factor > sqrt(num) may be left over */ - if(num != 1) { - (*factors)[i++] = num; - } - (*nfactors) = i; +static int getfactors(int num, int *nfactors, int **factors) { + if(num < 2) { + (*nfactors) = 0; + (*factors) = nullptr; return MPI_SUCCESS; + } + /* Allocate the array of prime factors which cannot exceed log_2(num) entries */ + int sqrtnum = ceil(sqrt(num)); + int size = ceil(log(num) / log(2)); + *factors = new int[size]; + + int i = 0; + /* determine all occurrences of factor 2 */ + while((num % 2) == 0) { + num /= 2; + (*factors)[i++] = 2; + } + /* determine all occurrences of uneven prime numbers up to sqrt(num) */ + for(int d = 3; (num > 1) && (d < sqrtnum); d += 2) { + while((num % d) == 0) { + num /= d; + (*factors)[i++] = d; + } + } + /* as we looped only up to sqrt(num) one factor > sqrt(num) may be left over */ + if(num != 1) { + (*factors)[i++] = num; + } + (*nfactors) = i; + return MPI_SUCCESS; } -