如何为 MPI 数据类型定义 uint_fast32_t?

How can you define the uint_fast32_t for MPI data types?

如何使用 C/C++ uint_fast32_t 或任何其他使用 fast 功能的整数位来定义 MPI 整数数据类型。

假设我们使用符合 MPI standard 2.2 版或更高版本的 MPI 实现。

MPI 2.2 及更高版本定义有符号整数数据类型 MPI_INT8_TMPI_INT16_TMPI_INT32_TMPI_INT64_T(对应于 C int8_tint16_tint32_tint64_t),以及无符号整数数据类型MPI_UINT8_TMPI_UINT16_TMPI_UINT32_TMPI_UINT64_T(对应于C uint8_tuint16_tuint32_tuint64_t).

这意味着您可以在 C 中的 MPI 中直接使用这些特定大小的整数类型。


最小宽度(int_leastN_tuint_leastN_t)和最快最小宽度(int_fastN_tuint_fastN_t)整数类型的情况不同。 会告诉您,您不能真正将这些类型与 MPI 一起使用,因为 C 或 MPI 标准没有提供使用它们的简洁方法。

实际上,情况要简单得多。支持 <stdint.h> 类型的所有现有 C 实现将最小宽度和最快的最小宽度整数类型定义为与精确宽度类型兼容的类型。

就我个人而言,我会创建一个头文件,例如 extra-mpi-types.h,其中包含适当的头文件,例如

/* extra_mpi_types.h */
#ifndef   EXTRA_MPI_TYPES_H

/* Use build-time generated file */
#include <extra_mpi_types_internal.h>

#endif /* EXTRA_MPI_TYPES_H */

其中 extra_mpi_types_internal.h 是在构建时通过编译和 运行 类似

生成的
/* type_generator.c */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

static inline const char *mpi_type_name(const char *const name, const size_t size, const int is_signed)
{
    if (is_signed) {
        if (size == sizeof (int8_t))  return "MPI_INT8_T";
        if (size == sizeof (int16_t)) return "MPI_INT16_T";
        if (size == sizeof (int32_t)) return "MPI_INT32_T";
        if (size == sizeof (int64_t)) return "MPI_INT64_T";
    } else {
        if (size == sizeof (uint8_t))  return "MPI_UINT8_T";
        if (size == sizeof (uint16_t)) return "MPI_UINT16_T";
        if (size == sizeof (uint32_t)) return "MPI_UINT32_T";
        if (size == sizeof (uint64_t)) return "MPI_UINT64_T";
    }
    fprintf(stderr, "%s: Unsupported %s integer type.\n", name, (is_signed) ? "signed" : "unsigned");
    exit(EXIT_FAILURE);
}

static void define(const char *const mpiname, const char *const typename, const size_t typesize, const int is_signed)
{
    printf("#ifndef  %s\n", mpiname);
    printf("# define %s  %s\n", mpiname, mpi_type_name(typename, typesize, is_signed));
    printf("#endif\n");
}

#define  DEFINE_SIGNED(mpitype, type)    define(#mpitype, #type, sizeof (type), 1)
#define  DEFINE_UNSIGNED(mpitype, type)  define(#mpitype, #type, sizeof (type), 0)

int main(void)
{
    printf("/* This is an autogenerated header file: do not modify. */\n\n");

    DEFINE_SIGNED(MPI_INT_LEAST8_T,  int_least8_t);
    DEFINE_SIGNED(MPI_INT_LEAST16_T, int_least16_t);
    DEFINE_SIGNED(MPI_INT_LEAST32_T, int_least32_t);
    DEFINE_SIGNED(MPI_INT_LEAST64_T, int_least64_t);

    DEFINE_UNSIGNED(MPI_UINT_LEAST8_T,  uint_least8_t);
    DEFINE_UNSIGNED(MPI_UINT_LEAST16_T, uint_least16_t);
    DEFINE_UNSIGNED(MPI_UINT_LEAST32_T, uint_least32_t);
    DEFINE_UNSIGNED(MPI_UINT_LEAST64_T, uint_least64_t);

    DEFINE_SIGNED(MPI_INT_FAST8_T,  int_fast8_t);
    DEFINE_SIGNED(MPI_INT_FAST16_T, int_fast16_t);
    DEFINE_SIGNED(MPI_INT_FAST32_T, int_fast32_t);
    DEFINE_SIGNED(MPI_INT_FAST64_T, int_fast64_t);

    DEFINE_UNSIGNED(MPI_UINT_FAST8_T,  uint_fast8_t);
    DEFINE_UNSIGNED(MPI_UINT_FAST16_T, uint_fast16_t);
    DEFINE_UNSIGNED(MPI_UINT_FAST32_T, uint_fast32_t);
    DEFINE_UNSIGNED(MPI_UINT_FAST64_T, uint_fast64_t);

    return EXIT_SUCCESS;
}

将其输出重定向到 extra_mpi_types_internal.h。请注意,这仅取决于 C 实现,而不完全取决于 MPI 实现。这只会找出哪些固定宽度整数类型匹配最小宽度或最小宽度快速整数类型。

在 x86-64 Linux 上,这将生成

/* This is an autogenerated header file: do not modify. */

#ifndef  MPI_INT_LEAST8_T
# define MPI_INT_LEAST8_T  MPI_INT8_T
#endif
#ifndef  MPI_INT_LEAST16_T
# define MPI_INT_LEAST16_T  MPI_INT16_T
#endif
#ifndef  MPI_INT_LEAST32_T
# define MPI_INT_LEAST32_T  MPI_INT32_T
#endif
#ifndef  MPI_INT_LEAST64_T
# define MPI_INT_LEAST64_T  MPI_INT64_T
#endif
#ifndef  MPI_UINT_LEAST8_T
# define MPI_UINT_LEAST8_T  MPI_UINT8_T
#endif
#ifndef  MPI_UINT_LEAST16_T
# define MPI_UINT_LEAST16_T  MPI_UINT16_T
#endif
#ifndef  MPI_UINT_LEAST32_T
# define MPI_UINT_LEAST32_T  MPI_UINT32_T
#endif
#ifndef  MPI_UINT_LEAST64_T
# define MPI_UINT_LEAST64_T  MPI_UINT64_T
#endif
#ifndef  MPI_INT_FAST8_T
# define MPI_INT_FAST8_T  MPI_INT8_T
#endif
#ifndef  MPI_INT_FAST16_T
# define MPI_INT_FAST16_T  MPI_INT64_T
#endif
#ifndef  MPI_INT_FAST32_T
# define MPI_INT_FAST32_T  MPI_INT64_T
#endif
#ifndef  MPI_INT_FAST64_T
# define MPI_INT_FAST64_T  MPI_INT64_T
#endif
#ifndef  MPI_UINT_FAST8_T
# define MPI_UINT_FAST8_T  MPI_UINT8_T
#endif
#ifndef  MPI_UINT_FAST16_T
# define MPI_UINT_FAST16_T  MPI_UINT64_T
#endif
#ifndef  MPI_UINT_FAST32_T
# define MPI_UINT_FAST32_T  MPI_UINT64_T
#endif
#ifndef  MPI_UINT_FAST64_T
# define MPI_UINT_FAST64_T  MPI_UINT64_T
#endif

如果您使用 Makefile 来组织您的产品,我会使用类似的东西

CC      := mpicc
CFLAGS  := -Wall -O2
LDFLAGS := -lmpi

all: your-main-program

clean:
    @rm -f *.o extra_mpi_types_internal.h

type-generator: type-generator.c
    $(CC) $(CFLAGS) $^ -o $@

extra_mpi_types_internal.h: type-generator
    ./type-generator > $@

%.o: %.c extra_mpi_types_internal.h
    $(CC) $(CFLAGS) $< -c -o $@

your-main-program: all.o needed.o object.o files.o
    $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ 

虽然这种方法确实意味着您不能为不同的体系结构交叉编译 MPI 程序。


或者,您可以使用 pre-defined compiler macros 来确定所使用的 OS、硬件架构和 C 库,以包含具有正确宏定义的预先准备好的头文件:

/* extra_mpi_types.h */
#ifndef   EXTRA_MPI_TYPES_H

#if defined(__linux__)
#if   defined(__amd64__)
#include <extra-linux-amd64.h>
#elif defined(__i386__)
#include <extra-linux-x86.h>
#elif defined(__aarch64__)
#include <extra-linux-arm64.h>
#elif defined(__ARM_ARCH_4T__)
#include <extra-linux-arm-4t.h>
#else
#error "Unsupported Linux hardware architecture"
#endif

#elif defined(_WIN64)
#include <extra-win64.h>

#elif defined(_WIN32)
#include <extra-win32.h>

#else
#error  Unsupported operating system.
#endif

#endif /* EXTRA_MPI_TYPES_H */

上述每个文件的内容(或者更确切地说,体系结构和操作系统根据需要),可以使用上面的 C 程序发现,或者通过检查C 编译器和库头文件。