Skip to content
Snippets Groups Projects
Select Git revision
  • 9519ff1d076e3fba54171385aa44fe3ee23b4e9e
  • master default
  • ordered_append
  • v2.0.0
  • v1.0.0
5 results

Main.java

Blame
  • fmpi_mpi.c 12.49 KiB
    // SPDX-License-Identifier: 0BSD
    /*!
     * @file
     * @license{
     * BSD Zero Clause License
     *
     * Copyright (c) 2022 by Raphael Bach
     *
     * Permission to use, copy, modify, and/or distribute this software for any
     * purpose with or without fee is hereby granted.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
     * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
     * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
     * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     * PERFORMANCE OF THIS SOFTWARE.
     * }
     */
    /*==============================================================================
        INCLUDE
    ==============================================================================*/
    // Own header
    #include "internal/fmpi_mpi.h"
    // C Standard Library
    #include <assert.h>
    #include <limits.h> // INT_MAX
    #include <stdbool.h>
    #include <stdio.h>  // printf()
    #include <stdlib.h> // NULL, free(), malloc()
    // External
    #include <mpi.h>
    // Internal
    #include "internal/fmpi_common.h"
    #include "internal/fmpi_error.h"
    #include "internal/fmpi_type.h"
    /*==============================================================================
        DEFINE
    ==============================================================================*/
    #define FMPI_MPI_ROOT 0
    /*==============================================================================
        MACRO
    ==============================================================================*/
    #define FMPI_RAISE_MPI_ERROR(ctx, ...) \
    do { \
        if((ctx)->err_handler.func != NULL) { \
            FMPI_RAISE_ERROR((ctx)->err_handler, "MPI", __VA_ARGS__); \
        } \
    } while(0)
    /*==============================================================================
        PUBLIC FUNCTION DEFINITION
    ==============================================================================*/
    /*------------------------------------------------------------------------------
        fmpi_mpi_init()
    ------------------------------------------------------------------------------*/
    struct fmpi_mpi_ctx * fmpi_mpi_init(
        int * const argc, char **  argv[],
        const struct fmpi_error_handler err_handler
    ){
        struct fmpi_mpi_ctx * ctx = malloc(sizeof(*ctx));
        if(ctx == NULL) {
            FMPI_RAISE_ERROR(err_handler, "FMPI", "malloc(fmpi_mpi_ctx) failed!");
            return NULL;
        }
        ctx->err_handler = err_handler;
        ctx->root = FMPI_MPI_ROOT;
    
        int err = MPI_Init(argc, argv);
        if(fmpi_mpi_check_error(ctx, err, "MPI_Init") != FMPI_SUCCESS) {
            free(ctx);
            return NULL;
        }
    
        err = MPI_Comm_dup(MPI_COMM_WORLD, &ctx->world);
        if(fmpi_mpi_check_error(ctx, err, "MPI_Comm_dup") != FMPI_SUCCESS) {
            fmpi_mpi_exit(&ctx);
            return NULL;
        }
    
        err = MPI_Comm_rank(ctx->world, &ctx->rank);
        if(fmpi_mpi_check_error(ctx, err, "MPI_Comm_rank") != FMPI_SUCCESS) {
            fmpi_mpi_exit(&ctx);
            return NULL;
        }
    
        err = MPI_Comm_size(ctx->world, &ctx->size);
        if(fmpi_mpi_check_error(ctx, err, "MPI_Comm_size") != FMPI_SUCCESS) {
            fmpi_mpi_exit(&ctx);
            return NULL;
        }
        // `ctx->size` is used with `malloc()` and `malloc(0)` is implementation
        // defined.
        assert(ctx->size > 0);
    
        err = MPI_Get_processor_name(ctx->cpu_name, &ctx->cpu_name_length);
        fmpi_mpi_check_error(ctx, err, "MPI_Get_processor_name");
    
        return ctx;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_exit()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_exit(struct fmpi_mpi_ctx ** const ctx)
    {
        assert(ctx != NULL);
        assert(*ctx != NULL);
    
        int err = FMPI_SUCCESS;
        if(fmpi_mpi_finalized(*ctx) == false) {
            err = MPI_Finalize();
            err = fmpi_mpi_check_error(*ctx, err, "MPI_Finalize");
        }
        free(*ctx); *ctx = NULL;
        return err;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_is_root()
    ------------------------------------------------------------------------------*/
    _Bool fmpi_mpi_is_root(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        return ctx->rank == ctx->root;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_check_error()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_check_error(
        const struct fmpi_mpi_ctx * ctx, int err, const char * const func
    ){
        assert(ctx != NULL);
        assert(func != NULL);
        if(err != MPI_SUCCESS) {
            char err_str[MPI_MAX_ERROR_STRING] = {'\0'};
            int err_str_len = 0;
            err = MPI_Error_string(err, err_str, &err_str_len);
            if(err != MPI_SUCCESS) {
                FMPI_RAISE_MPI_ERROR(ctx, "MPI_Error_string() failed!");
            }
            FMPI_RAISE_MPI_ERROR(ctx, "%s() failed! %s", func, err_str);
            return FMPI_ERR_MPI;
        }
        return FMPI_SUCCESS;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_ctx_print()
    ------------------------------------------------------------------------------*/
    void fmpi_mpi_ctx_print(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        printf("MPI size: %d\n", ctx->size);
        printf("MPI rank: %d\n", ctx->rank);
        printf("MPI CPU name: %s\n", ctx->cpu_name);
        printf("MPI root: %s\n", ctx->cpu_name);
        printf("MPI futhark error class: %d\n", ctx->futhark_err_class);
        printf("MPI futhark error code: %d\n", ctx->futhark_err_code);
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_world_rank()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_world_rank(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        int rank = FMPI_ERROR;
        int err = MPI_Comm_rank(ctx->world, &rank);
        err = fmpi_mpi_check_error(ctx, err, "MPI_Comm_rank");
        if(err != FMPI_SUCCESS) {
            return err;
        }
        return rank;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_finalized()
    ------------------------------------------------------------------------------*/
    _Bool fmpi_mpi_finalized(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        int finalized = 0;
        const int err = MPI_Finalized(&finalized);
        if(err != MPI_SUCCESS) {
            FMPI_RAISE_MPI_ERROR(ctx, "MPI_Finalized() failed with err=%d!", err);
        }
        return finalized;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_abort()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_abort(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        if(fmpi_mpi_finalized(ctx) == false) {
            const int err = MPI_Abort(ctx->world, MPI_ERR_UNKNOWN);
            return fmpi_mpi_check_error(ctx, err, "MPI_Abort");
        }
        return FMPI_ERROR;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_world_barrier()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_world_barrier(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        const int err = MPI_Barrier(ctx->world);
        return fmpi_mpi_check_error(ctx, err, "MPI_Barrier");
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_type()
    ------------------------------------------------------------------------------*/
    MPI_Datatype fmpi_mpi_type(const enum fmpi_type_base type)
    {
        static const MPI_Datatype fmpi_mpi_type_list[] = {
            [FMPI_TYPE_i8]   = MPI_INT8_T  ,
            [FMPI_TYPE_i16]  = MPI_INT16_T ,
            [FMPI_TYPE_i32]  = MPI_INT32_T ,
            [FMPI_TYPE_i64]  = MPI_INT64_T ,
            [FMPI_TYPE_u8]   = MPI_UINT8_T ,
            [FMPI_TYPE_u16]  = MPI_UINT16_T,
            [FMPI_TYPE_u32]  = MPI_UINT32_T,
            [FMPI_TYPE_u64]  = MPI_UINT64_T,
            [FMPI_TYPE_f32]  = MPI_FLOAT   ,
            [FMPI_TYPE_f64]  = MPI_DOUBLE  ,
            [FMPI_TYPE_bool] = MPI_C_BOOL
        };
        return fmpi_mpi_type_list[type];
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_gather_in_place()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_gather_in_place(
        const struct fmpi_mpi_ctx * const ctx, void * const buf, MPI_Datatype type,
        const size_t send_cnt, const size_t recv_cnt, const int root, MPI_Comm comm
    ) {
        assert(ctx != NULL);
        assert(buf != NULL);
        assert(send_cnt <= INT_MAX);
        assert(recv_cnt <= INT_MAX);
        assert(send_cnt <= recv_cnt);
    
        int err = MPI_SUCCESS;
        if(ctx->rank == root) {
            err = MPI_Gather(
                MPI_IN_PLACE, (int)send_cnt, type,
                buf         , (int)recv_cnt, type,
                root, comm
            );
        } else {
            err = MPI_Gather(
                buf, (int)send_cnt, type,
                buf, (int)recv_cnt, type,
                root, comm
            );
        }
        return fmpi_mpi_check_error(ctx, err, "MPI_Gather");
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_world_gather_in_place()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_world_gather_in_place(
        const struct fmpi_mpi_ctx * const ctx, void * const buf, MPI_Datatype type,
        const size_t send_cnt, const size_t recv_cnt
    ){
        assert(ctx != NULL);
        assert(buf != NULL);
        assert(send_cnt <= INT_MAX);
        assert(recv_cnt <= INT_MAX);
        assert(send_cnt <= recv_cnt);
    
        const int err = fmpi_mpi_gather_in_place(
            ctx, buf, type, send_cnt, recv_cnt, ctx->root, ctx->world
        );
        if(err != FMPI_SUCCESS) {
            FMPI_RAISE_ERROR(ctx->err_handler, "FMPI",
                "fmpi_mpi_gather_in_place() failed!"
            );
        }
        return err;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_reduce_in_place()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_reduce_in_place(
        const struct fmpi_mpi_ctx * const ctx, void * const buf, const size_t cnt,
        MPI_Datatype type, MPI_Op op, const int root, MPI_Comm comm
    ){
        assert(ctx != NULL);
        assert(buf != NULL);
        assert(cnt <= INT_MAX);
    
        int err = MPI_SUCCESS;
        if(ctx->rank == root) {
            err = MPI_Reduce(MPI_IN_PLACE, buf, (int)cnt, type, op, root, comm);
        } else {
            err = MPI_Reduce(buf, buf, (int)cnt, type, op, root, comm);
        }
        return fmpi_mpi_check_error(ctx, err, "MPI_Reduce");
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_world_reduce_in_place()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_world_reduce_in_place(
        const struct fmpi_mpi_ctx * const ctx, void * const buf, const size_t cnt,
        MPI_Datatype type, MPI_Op op
    ){
        assert(ctx != NULL);
        assert(buf != NULL);
        assert(cnt <= INT_MAX);
    
        const int err = fmpi_mpi_reduce_in_place(
            ctx, buf, cnt, type, op, ctx->root, ctx->world
        );
        if(err != FMPI_SUCCESS) {
            FMPI_RAISE_ERROR(ctx->err_handler, "FMPI",
                "fmpi_mpi_reduce_in_place() failed!"
            );
        }
        return err;
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_dims_create()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_dims_create(
        const struct fmpi_mpi_ctx * const ctx, size_t * const dim_len,
        const size_t dim_cnt
    ){
        assert(ctx != NULL);
        assert(dim_len != NULL);
        assert(dim_cnt <= FMPI_DIM_MAX);
        int dims[FMPI_DIM_MAX];
        for(size_t i = 0; i < dim_cnt; i++) {
            dims[i] = (int)dim_len[i];
        }
        const int err = MPI_Dims_create(ctx->size, (int)dim_cnt, dims);
        for(size_t i = 0; i < dim_cnt; i++) {
            assert(dims[i] >= 0);
            dim_len[i] = (size_t)dims[i];
        }
        return fmpi_mpi_check_error(ctx, err, "MPI_Dims_create");
    }
    /*------------------------------------------------------------------------------
        fmpi_mpi_world_size()
    ------------------------------------------------------------------------------*/
    int fmpi_mpi_world_size(const struct fmpi_mpi_ctx * const ctx)
    {
        assert(ctx != NULL);
        int size = FMPI_ERROR;
        int err = MPI_Comm_size(ctx->world, &size);
        err = fmpi_mpi_check_error(ctx, err, "MPI_Comm_size");
        if(err != FMPI_SUCCESS) {
            return err;
        }
        return size;
    }