From c0dd2a5b04f436872b84c3ab3994268bebb2d8d9 Mon Sep 17 00:00:00 2001
From: "raphael.bach" <raphael.bach@etu.hesge.ch>
Date: Sat, 14 May 2022 20:44:16 +0200
Subject: [PATCH] Add `fmpi_task` module

---
 include/fmpi_core.h | 114 +++++++++++++++++++++++++
 include/fmpi_task.h | 201 ++++++++++++++++++++++++++++++++++++++++++++
 src/fmpi_core.c     |  77 +++++++++++++++++
 src/fmpi_task.c     |  59 +++++++++++++
 4 files changed, 451 insertions(+)
 create mode 100644 include/fmpi_core.h
 create mode 100644 include/fmpi_task.h
 create mode 100644 src/fmpi_core.c
 create mode 100644 src/fmpi_task.c

diff --git a/include/fmpi_core.h b/include/fmpi_core.h
new file mode 100644
index 0000000..798833e
--- /dev/null
+++ b/include/fmpi_core.h
@@ -0,0 +1,114 @@
+// 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.
+ * }
+ */
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#ifndef FMPI_CORE_H_20211231181158
+#define FMPI_CORE_H_20211231181158
+/*==============================================================================
+    INCLUDE
+==============================================================================*/
+// C Standard Library
+// Internal
+#include "internal/fmpi_ctx.h"
+/*==============================================================================
+    PUBLIC FUNCTION
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_init()
+------------------------------------------------------------------------------*/
+/**
+ * Initializes the fmpi library.
+ *
+ * @param[in,out] argc : A pointer to the `argc` parameter of `main()`.
+ * @param[in,out] argv  : A triple pointer to the `argv` parameter of `main()`.
+ *
+ * @return
+ * - @success: A pointer to a newly allocated `fmpi_ctx`.
+ * - @failure: `NULL`.
+ *
+ * @example{
+ *  struct fmpi_ctx * ctx = fmpi_init(&argc, &argv);
+ *  if(ctx == NULL) {
+ *      fprintf(stderr, "fmpi_init() failed!\n");
+ *      fmpi_abort(NULL);
+ *  }
+ * }
+ */
+struct fmpi_ctx * fmpi_init(int * argc, char ** argv[]);
+/*------------------------------------------------------------------------------
+    fmpi_exit()
+------------------------------------------------------------------------------*/
+/**
+ * Exits the fmpi library and sets \p{ctx} to `NULL` after freeing it.
+ *
+ * @param[in,out] ctx : A double pointer to a valid `fmpi_ctx` allocated with
+ *                      `fmpi_init()`.
+ *
+ * @return
+ * - @success: `0`.
+ * - @failure: A non-zero value.
+ *
+ * @warning
+ * - \b [UB] \p{ctx} must not be `NULL`.
+ * - \b [UB] \p{*ctx} must not be `NULL`.
+ *
+ * @example{
+ *  struct fmpi_ctx * ctx = fmpi_init(&argc, &argv);
+ *  if(fmpi_exit(ctx) != 0) {
+ *      fprintf(stderr, "fmpi_exit() failed!\n");
+ *  }
+ * }
+ */
+int fmpi_exit(struct fmpi_ctx ** const ctx);
+/*------------------------------------------------------------------------------
+    fmpi_abort()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+_Noreturn void fmpi_abort(void);
+/*------------------------------------------------------------------------------
+    fmpi_is_root()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : A pointer to a fmpi_ctx.
+ *
+ * @return TODO
+ *
+ * @warning
+ * - \b [UB] \p{ctx} must not be `NULL`.
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+_Bool fmpi_is_root(const struct fmpi_ctx * ctx);
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#endif // FMPI_CORE_H_20211231181158
diff --git a/include/fmpi_task.h b/include/fmpi_task.h
new file mode 100644
index 0000000..0f64e55
--- /dev/null
+++ b/include/fmpi_task.h
@@ -0,0 +1,201 @@
+// 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.
+ * }
+ */
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#ifndef FMPI_TASK_H_20220513032517
+#define FMPI_TASK_H_20220513032517
+/*==============================================================================
+    INCLUDE
+==============================================================================*/
+// C Standard Library
+#include <stddef.h>
+// External
+// Internal
+#include "fmpi_data.h"
+#include "internal/fmpi_ctx.h"
+/*==============================================================================
+    DEFINE
+==============================================================================*/
+/**
+ * Maximum number of arguments that can be passed to a task.
+ */
+#define FMPI_TASK_ARGS_CNT_MAX 32
+/*==============================================================================
+    TYPE
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_task_args
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+typedef struct fmpi_task_args {
+    struct fmpi_data in[FMPI_TASK_ARGS_CNT_MAX]; //!< TODO
+    struct fmpi_data out;                        //!< TODO
+    size_t cnt;                                  //!< TODO
+} fmpi_task_args;
+/*------------------------------------------------------------------------------
+    fmpi_task_func
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx  : A pointer to a fmpi_ctx.
+ * @param[in] args : A pointer to a fmpi_task_args.
+ *
+ * @return Nothing.
+ *
+ * @warning
+ * - \b [UB] \p{ctx} must not be `NULL`.
+ * - \b [UB] \p{args} must not be `NULL`.
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+typedef void (*fmpi_task_func)(
+    const struct fmpi_ctx * ctx, const struct fmpi_task_args * args
+);
+/*------------------------------------------------------------------------------
+    fmpi_task
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+typedef struct fmpi_task {
+    fmpi_task_func func;        //!< TODO
+    struct fmpi_task_args args; //!< TODO
+} fmpi_task;
+/*==============================================================================
+    PUBLIC FUNCTION
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_task_register()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx  : A pointer to a fmpi_ctx.
+ * @param[in] func : A function with a fmpi_task_func signature.
+ * @param[in] args : A pointer to a fmpi_task_args.
+ *
+ * @return A fmpi_task structure.
+ *
+ * @warning
+ * - \b [UB] \p{ctx} must not be `NULL`.
+ * - \b [UB] \p{func} must not be `NULL`.
+ * - \b [UB] \p{args} must not be `NULL`.
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+struct fmpi_task fmpi_task_register(
+    const struct fmpi_ctx * ctx, const fmpi_task_func func,
+    const struct fmpi_task_args * args
+);
+/*------------------------------------------------------------------------------
+    fmpi_task_run()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx  : A pointer to a fmpi_ctx.
+ * @param[in] task : A pointer to a fmpi_task.
+ *
+ * @return Nothing.
+ *
+ * @warning
+ * - \b [UB] \p{ctx} must not be `NULL`.
+ * - \b [UB] \p{task} must not be `NULL`.
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+void fmpi_task_run(const struct fmpi_ctx * ctx, const struct fmpi_task * task);
+/*==============================================================================
+    MACRO
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    FMPI_TASK_FUTHARK_SYNC()
+------------------------------------------------------------------------------*/
+/**
+ * Declares and defines a task running a `futhark` function synchronously.
+ *
+ * @param[in] task_name : The name to give to this task.
+ * @param[in] func      : A pointer to a futhark function.
+ *
+ * @return Nothing.
+ *
+ * @warning
+ * - \b [UB] \p{func} must not be `NULL`.
+ *
+ * @example{
+ *  FMPI_TASK_FUTHARK_SYNC(fut_array_sum, futhark_entry_array_sum)
+ * }
+ */
+#define FMPI_TASK_FUTHARK_SYNC(task_name, func) \
+void task_name(const struct fmpi_ctx * ctx, const struct fmpi_task_args * args); \
+void task_name(const struct fmpi_ctx * const ctx, const struct fmpi_task_args * const args) { \
+    assert(ctx != NULL); \
+    assert(args != NULL); \
+    func(ctx->fut->ctx, args->out.start, args->in[0].start); \
+    fmpi_futhark_sync(ctx->fut); \
+}
+/*------------------------------------------------------------------------------
+    FMPI_TASK_FUTHARK_ASYNC()
+------------------------------------------------------------------------------*/
+/**
+ * Declares and defines a task running a `futhark` function asynchronously.
+ *
+ * @param[in] task_name : The name to give to this task.
+ * @param[in] func      : A pointer to a futhark function.
+ *
+ * @return Nothing.
+ *
+ * @warning
+ * - \b [UB] \p{func} must not be `NULL`.
+ *
+ * @example{
+ *  FMPI_TASK_FUTHARK_ASYNC(fut_array_sum, futhark_entry_array_sum)
+ * }
+ */
+#define FMPI_TASK_FUTHARK_ASYNC(task_name, func) \
+void task_name(const struct fmpi_ctx * ctx, const struct fmpi_task_args * args); \
+void task_name(const struct fmpi_ctx * const ctx, const struct fmpi_task_args * const args) { \
+    assert(ctx != NULL); \
+    assert(args != NULL); \
+    func(ctx->fut->ctx, args->out.start, args->in[0].start); \
+}
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#endif // FMPI_TASK_H_20220513032517
diff --git a/src/fmpi_core.c b/src/fmpi_core.c
new file mode 100644
index 0000000..64ed212
--- /dev/null
+++ b/src/fmpi_core.c
@@ -0,0 +1,77 @@
+// 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 "fmpi_core.h"
+// C Standard Library
+#include <assert.h>
+#include <stdio.h>  // fprintf()
+#include <stdlib.h> // NULL,
+// External
+#include <mpi.h>
+// Internal
+#include "internal/fmpi_ctx.h"
+#include "internal/fmpi_futhark.h"
+#include "internal/fmpi_mpi.h"
+/*==============================================================================
+    STRUCT
+==============================================================================*/
+/*==============================================================================
+    PUBLIC FUNCTION
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_init()
+------------------------------------------------------------------------------*/
+struct fmpi_ctx * fmpi_init(int * const argc, char *** const argv)
+{
+    struct fmpi_ctx * ctx = fmpi_ctx_create(argc, argv);
+    if(ctx == NULL) {
+        fprintf(stderr, "fmpi_ctx_create() failed!\n");
+        return NULL;
+    }
+    return ctx;
+}
+/*------------------------------------------------------------------------------
+    fmpi_exit()
+------------------------------------------------------------------------------*/
+int fmpi_exit(struct fmpi_ctx ** const ctx)
+{
+    assert(ctx != NULL);
+    return fmpi_ctx_destroy(ctx);
+}
+/*------------------------------------------------------------------------------
+    fmpi_abort()
+------------------------------------------------------------------------------*/
+_Noreturn void fmpi_abort(void)
+{
+    MPI_Abort(MPI_COMM_WORLD, MPI_ERR_UNKNOWN);
+    abort();
+}
+/*------------------------------------------------------------------------------
+    fmpi_is_root()
+------------------------------------------------------------------------------*/
+_Bool fmpi_is_root(const struct fmpi_ctx * ctx)
+{
+    assert(ctx != NULL);
+    return fmpi_mpi_is_root(ctx->mpi);
+}
diff --git a/src/fmpi_task.c b/src/fmpi_task.c
new file mode 100644
index 0000000..c45237d
--- /dev/null
+++ b/src/fmpi_task.c
@@ -0,0 +1,59 @@
+// 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 "fmpi_task.h"
+// C Standard Library
+#include <assert.h>
+#include <stdint.h> // int64_t
+// Internal
+#include "internal/fmpi_futhark.h"
+#include "internal/fmpi_futhark_entry.h"
+/*==============================================================================
+    PUBLIC FUNCTION DEFINITION
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_task_run()
+------------------------------------------------------------------------------*/
+struct fmpi_task fmpi_task_register(
+    const struct fmpi_ctx * const ctx, const fmpi_task_func func,
+    const struct fmpi_task_args * const args
+){
+    assert(ctx != NULL);
+    struct fmpi_task task = {
+        .func = func,
+        .args = *args
+    };
+    for(size_t i = 0; i < args->cnt; i++) {
+        task.args.in[i].start = futhark_new_i64_1d(ctx->fut->ctx, args->in[i].start, (int64_t)args->in[i].dims_length[0]);
+    }
+    futhark_context_sync(ctx->fut->ctx);
+    return task;
+}
+void fmpi_task_run(
+    const struct fmpi_ctx * const ctx, const struct fmpi_task * const  task
+){
+    assert(ctx != NULL);
+    assert(task != NULL);
+    task->func(ctx, &task->args);
+}
-- 
GitLab