coll_basic_reduce.c

来自「MPI stands for the Message Passing Inter」· C语言 代码 · 共 565 行 · 第 1/2 页

C
565
字号
/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana *                         University Research and Technology *                         Corporation.  All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University *                         of Tennessee Research Foundation.  All rights *                         reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,  *                         University of Stuttgart.  All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. *                         All rights reserved. * $COPYRIGHT$ *  * Additional copyrights may follow *  * $HEADER$ */#include "ompi_config.h"#include "coll_basic.h"#include <stdio.h>#include "mpi.h"#include "ompi/constants.h"#include "ompi/mca/coll/coll.h"#include "ompi/mca/coll/base/coll_tags.h"#include "ompi/op/op.h"/* *	reduce_lin_intra * *	Function:	- reduction using O(N) algorithm *	Accepts:	- same as MPI_Reduce() *	Returns:	- MPI_SUCCESS or error code */intmca_coll_basic_reduce_lin_intra(void *sbuf, void *rbuf, int count,                                struct ompi_datatype_t *dtype,                                struct ompi_op_t *op,                                int root, struct ompi_communicator_t *comm){    int i, rank, err, size;    ptrdiff_t true_lb, true_extent, lb, extent;    char *free_buffer = NULL;    char *pml_buffer = NULL;    char *inplace_temp = NULL;    char *inbuf;    /* Initialize */    rank = ompi_comm_rank(comm);    size = ompi_comm_size(comm);    /* If not root, send data to the root. */    if (rank != root) {        err = MCA_PML_CALL(send(sbuf, count, dtype, root,                                MCA_COLL_BASE_TAG_REDUCE,                                MCA_PML_BASE_SEND_STANDARD, comm));        return err;    }    /* Root receives and reduces messages.  Allocate buffer to receive     * messages.  This comment applies to all collectives in this basic     * module where we allocate a temporary buffer.  For the next few     * lines of code, it's tremendously complicated how we decided that     * this was the Right Thing to do.  Sit back and enjoy.  And prepare     * to have your mind warped. :-)     *      * Recall some definitions (I always get these backwards, so I'm     * going to put them here):     *      * extent: the length from the lower bound to the upper bound -- may     * be considerably larger than the buffer required to hold the data     * (or smaller!  But it's easiest to think about when it's larger).     *      * true extent: the exact number of bytes required to hold the data     * in the layout pattern in the datatype.     *      * For example, consider the following buffer (just talking about     * LB, extent, and true extent -- extrapolate for UB; i.e., assume     * the UB equals exactly where the data ends):     *      * A              B                                       C     * --------------------------------------------------------     * |              |                                       |     * --------------------------------------------------------     *      * There are multiple cases:     *      * 1. A is what we give to MPI_Send (and friends), and A is where     * the data starts, and C is where the data ends.  In this case:     *      * - extent: C-A     * - true extent: C-A     * - LB: 0     *      * A                                                      C     * --------------------------------------------------------     * |                                                      |     * --------------------------------------------------------     * <=======================extent=========================>     * <======================true extent=====================>     *      * 2. A is what we give to MPI_Send (and friends), B is where the     * data starts, and C is where the data ends.  In this case:     *      * - extent: C-A     * - true extent: C-B     * - LB: positive     *      * A              B                                       C     * --------------------------------------------------------     * |              |           User buffer                 |     * --------------------------------------------------------     * <=======================extent=========================>     * <===============true extent=============>     *      * 3. B is what we give to MPI_Send (and friends), A is where the     * data starts, and C is where the data ends.  In this case:     *      * - extent: C-A     * - true extent: C-A     * - LB: negative     *      * A              B                                       C     * --------------------------------------------------------     * |              |           User buffer                 |     * --------------------------------------------------------     * <=======================extent=========================>     * <======================true extent=====================>     *      * 4. MPI_BOTTOM is what we give to MPI_Send (and friends), B is     * where the data starts, and C is where the data ends.  In this     * case:     *      * - extent: C-MPI_BOTTOM     * - true extent: C-B     * - LB: [potentially very large] positive     *      * MPI_BOTTOM     B                                       C     * --------------------------------------------------------     * |              |           User buffer                 |     * --------------------------------------------------------     * <=======================extent=========================>     * <===============true extent=============>     *      * So in all cases, for a temporary buffer, all we need to malloc()     * is a buffer of size true_extent.  We therefore need to know two     * pointer values: what value to give to MPI_Send (and friends) and     * what value to give to free(), because they might not be the same.     *      * Clearly, what we give to free() is exactly what was returned from     * malloc().  That part is easy.  :-)     *      * What we give to MPI_Send (and friends) is a bit more complicated.     * Let's take the 4 cases from above:     *      * 1. If A is what we give to MPI_Send and A is where the data     * starts, then clearly we give to MPI_Send what we got back from     * malloc().     *      * 2. If B is what we get back from malloc, but we give A to     * MPI_Send, then the buffer range [A,B) represents "dead space"     * -- no data will be put there.  So it's safe to give B-LB to     * MPI_Send.  More specifically, the LB is positive, so B-LB is     * actually A.     *      * 3. If A is what we get back from malloc, and B is what we give to     * MPI_Send, then the LB is negative, so A-LB will actually equal     * B.     *      * 4. Although this seems like the weirdest case, it's actually     * quite similar to case #2 -- the pointer we give to MPI_Send is     * smaller than the pointer we got back from malloc().     *      * Hence, in all cases, we give (return_from_malloc - LB) to MPI_Send.     *      * This works fine and dandy if we only have (count==1), which we     * rarely do.  ;-) So we really need to allocate (true_extent +     * ((count - 1) * extent)) to get enough space for the rest.  This may     * be more than is necessary, but it's ok.     *      * Simple, no?  :-)     *      */    ompi_ddt_get_extent(dtype, &lb, &extent);    ompi_ddt_get_true_extent(dtype, &true_lb, &true_extent);    if (MPI_IN_PLACE == sbuf) {        sbuf = rbuf;        inplace_temp = (char*)malloc(true_extent + (count - 1) * extent);        if (NULL == inplace_temp) {            return OMPI_ERR_OUT_OF_RESOURCE;        }        rbuf = inplace_temp - lb;    }    if (size > 1) {        free_buffer = (char*)malloc(true_extent + (count - 1) * extent);        if (NULL == free_buffer) {            return OMPI_ERR_OUT_OF_RESOURCE;        }        pml_buffer = free_buffer - lb;    }    /* Initialize the receive buffer. */    if (rank == (size - 1)) {        err = ompi_ddt_copy_content_same_ddt(dtype, count, (char*)rbuf, (char*)sbuf);    } else {        err = MCA_PML_CALL(recv(rbuf, count, dtype, size - 1,                                MCA_COLL_BASE_TAG_REDUCE, comm,                                MPI_STATUS_IGNORE));    }    if (MPI_SUCCESS != err) {        if (NULL != free_buffer) {            free(free_buffer);        }        return err;    }    /* Loop receiving and calling reduction function (C or Fortran). */    for (i = size - 2; i >= 0; --i) {        if (rank == i) {            inbuf = (char*)sbuf;        } else {            err = MCA_PML_CALL(recv(pml_buffer, count, dtype, i,                                    MCA_COLL_BASE_TAG_REDUCE, comm,                                    MPI_STATUS_IGNORE));            if (MPI_SUCCESS != err) {                if (NULL != free_buffer) {                    free(free_buffer);                }                return err;            }            inbuf = pml_buffer;        }        /* Perform the reduction */        ompi_op_reduce(op, inbuf, rbuf, count, dtype);    }    if (NULL != inplace_temp) {        err = ompi_ddt_copy_content_same_ddt(dtype, count, (char*)sbuf, inplace_temp);        free(inplace_temp);    }    if (NULL != free_buffer) {        free(free_buffer);    }    /* All done */    return MPI_SUCCESS;}/* *	reduce_log_intra * *	Function:	- reduction using O(log N) algorithm *	Accepts:	- same as MPI_Reduce() *	Returns:	- MPI_SUCCESS or error code */intmca_coll_basic_reduce_log_intra(void *sbuf, void *rbuf, int count,                                struct ompi_datatype_t *dtype,                                struct ompi_op_t *op,                                int root, struct ompi_communicator_t *comm){    int i, size, rank, vrank;    int err, peer, dim, mask;    ptrdiff_t true_lb, true_extent, lb, extent;    char *free_buffer = NULL;    char *free_rbuf = NULL;    char *pml_buffer = NULL;    char *snd_buffer = NULL;    char *rcv_buffer = (char*)rbuf;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?