使用 MPI 派生数据类型

2024-03-29

我正在学习 Fortran 中的 BCASTing 数据类型,并且有一个代码可以从终端获取两个值并将它们显示在每个进程上。对于整数/整数和整数/实数类型的组合 value1/value2 ,这是有效的,但是对于整数/实数*8 的组合,它会失败。

代码是:

use mpi
implicit none

integer :: ierror, pid, ncpu, root = 0

integer :: counts, newtype, extent
integer, dimension(2) :: oldtypes, blockcounts, offsets

type value
    integer :: value1 = 0
    real*8 :: value2
end type

type (value) input

call MPI_INIT(ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD, pid, ierror)
call MPI_COMM_SIZE(MPI_COMM_WORLD, ncpu, ierror)

! setup of 1 MPI_INTEGER field: value1
offsets(1) = 0
oldtypes(1) = MPI_INTEGER
blockcounts(1) = 1

! setup of 1 MPI_REAL8 field: value2
call MPI_TYPE_EXTENT(MPI_INTEGER, extent, ierror)  !determine offset of MPI_INTEGER
offsets(2) = blockcounts(1)*extent                 !offset is 1 MPI_INTEGER extents
oldtypes(2) = MPI_REAL8
blockcounts(2) = 1

! define struct type and commit
counts = 2 !for MPI_INTEGER + MPI_REAL8
call MPI_TYPE_STRUCT(counts, blockcounts, offsets, & 
                     oldtypes, newtype, ierror)
call MPI_TYPE_COMMIT(newtype, ierror)

do while (input%value1 >= 0)
    if (pid == root) then
        read(*,*) input
        write(*,*) 'input was: ', input
    end if
    call MPI_BCAST(input, 1, newtype, &
                   root, MPI_COMM_WORLD, ierror)
    write(*,*), 'process ', pid, 'received: ', input
end do

call MPI_TYPE_FREE(newtype, ierror)
call MPI_FINALIZE(ierror)

可以通过更改相应的声明和旧类型来检查整数/整数和整数/实数是否正常工作。整数/实数*8 组合失败,例如输入 -1 2.0 生成:

input was:           -1   2.0000000000000000     
process            0 received:           -1   2.0000000000000000     
process            1 received:           -1   0.0000000000000000     
process            2 received:           -1   0.0000000000000000     
process            3 received:           -1   0.0000000000000000

This https://stackoverflow.com/questions/22709015/mpi-derived-type-send具有类似问题的线程表明使用 MPI_TYPE_EXTENT 是不正确的,因为可能存在未考虑的额外填充。不幸的是我无法解决这个问题,希望这里有人能启发我。

提前谢谢


您的基本想法是正确的 - 您已经创建了结构,但您假设双精度值紧随整数值存储,而这通常是不正确的。您链接到的 Hristo 的答案在 C 中给出了一个很好的答案。

问题是编译器通常会align http://en.wikipedia.org/wiki/Data_structure_alignment您的数据结构字段。大多数系统读取/写入内存中对齐的值的速度比执行非对齐访问的速度要快得多(如果它们可以执行这些访问)。通常,要求是根据元素大小进行对齐;也就是说,8 字节双精度数必须与 8 字节边界对齐(即,其第一个字节的地址为零模 8),而整数只需 4 字节对齐。这几乎肯定意味着整数和双精度数之间有 4 个字节的填充。

在许多情况下,您可以哄骗编译器放松这种行为 - 在 fortran 中,您还可以使用sequence http://research.physics.illinois.edu/ElectronicStructure/498-s97/comp_info/derived.html关键字要求数据连续存储。无论哪种方式,从性能的角度来看(这就是您使用 Fortran 和 MPI 的原因,人们认为)这几乎从来都不是正确的做法,但它对于与其他外部强加的字节到字节兼容性很有用数据类型或格式。

考虑到出于性能原因可能强加的填充,您可以假设对齐并将其硬编码到您的程序中;但这也可能不是正确的做法;如果添加其他字段,或者将实数类型更改为 4 字节单精度数等,您的代码将再次出错。最好的是使用MPI_Get_address https://www.open-mpi.org/doc/v1.8/man3/MPI_Get_address.3.php明确地找到位置并自己计算正确的偏移量:

integer(kind=MPI_Address_kind) :: startloc, endloc    
integer :: counts, newtype
integer, dimension(2) :: oldtypes, blockcounts, offsets

type value
    integer :: value1 = 0
    double precision :: value2
end type

type (value) :: input

!...    

! setup of 1 MPI_INTEGER field: value1
call MPI_Get_address(input, startloc, ierror)
oldtypes(1) = MPI_INTEGER
blockcounts(1) = 1
call MPI_Get_address(input%value1, endloc, ierror)
offsets(1) = endloc - startloc

oldtypes(2) = MPI_DOUBLE_PRECISION
blockcounts(2) = 1
call MPI_Get_address(input%value2, endloc, ierror)
offsets(2) = endloc - startloc

if (pid == 0) then
    print *,'offsets are: ', offsets
endif

请注意,如果您有一个此类派生类型的数组,为了涵盖一个项目的最后一个元素与下一个项目的开头之间的填充情况,您还需要显式地测量它,并设置类型 - 该类型的一个成员的开头与下一个成员的开头之间的偏移量 - 其中MPI_Type_create_resized https://www.open-mpi.org/doc/v1.8/man3/MPI_Type_create_resized.3.php.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 MPI 派生数据类型 的相关文章

  • 在 Visual Studio 中获取类的程序集限定名称

    我正在为一些专门的自定义域逻辑编写一个自定义的反射库 该库将使用 XML 配置文件 该文件将在运行时动态解析 System Type 对象 然而 在编写 XML 配置文件时 编写类型有点麻烦 因为它们需要完全限定的程序集名称 以便 Type
  • 在OpenCV中,CV_8U和CV_8UC1有什么区别?

    在OpenCV中 CV 8U和CV 8UC1有区别吗 它们都是指具有一个通道的 8 位无符号类型吗 如果是的话 为什么有两个名字 如果不是 有什么区别 你可以看到从this https stackoverflow com questions
  • PostgreSQL 中是否有可用的多值字段类型?

    我想知道是否可以在 PostgreSQL 的一个字段中存储多个值 我有一张桌子叫Token与列id text and category category是一个多值字段 是否有必要为其创建一个单独的表 或者有没有办法将其存储在Token ta
  • 在 F# 列表中键入扩展名

    假设我有一个类型 let MyType some info 但是 它通常用于列表 MyType list 所以我可以定义 let MyTypeList MyType list 有没有办法在 MyTypeList 上定义类型增强 我的实际情况
  • 使用 Fortran (CLFORTRAN) 在 OpenCL 中将两个选项作为参数传递

    当我的主机程序采用 C 语言时 我可以传递两个选项作为 OpenCL 函数的参数 例如 我可以通过两个 标志到clCreateBuffer像这样的函数 clCreateBuffer context CL MEM READ ONLY CL M
  • 什么是“收到信号 15”

    什么可能导致 C MPI 程序使用名为的库日晷 CVODE https computation llnl gov casc sundials documentation documentation html 数值 ODE 求解器 在 Gen
  • Visual Studio 默认自动完成使用系统类型名称

    奇怪的问题 但我的老板有点老派 坚持在我们的编码标准中我们不使用 C 简写系统类型 他喜欢我们使用完整的系统名称 他喜欢事情变得冗长 我很乐意遵守这个标准 然而 几个月后开始让我恼火的是 Visual Studio 在完成代码时不喜欢遵守标
  • 将 C 字符串数组传递给 Fortran (iso_c_binding)

    如何传递 C 字符串数组 char cstrings 到 Fortran 子程序 问题使用 iso c binding 的 fortran C 桥接器中的字符串数组 https stackoverflow com questions 968
  • mpi.h:使用未定义的类型?

    我正在尝试将 OpenMPI 的 mpi h 的重要部分翻译为 D 编程语言 以便我可以从 D 调用它 HTOD 根本不起作用 我无法理解以下代码段 typedef struct ompi communicator t MPI Comm O
  • Fortran 读取混合文本和数字

    我正在使用 Fortran 90 读取包含以下格式数据的文件 number 125 var1 2 var2 1 var3 4 number 234 var1 3 var2 5 var3 1 我尝试了以下命令并且工作正常 read 2 tem
  • 接受任意切片的 Express 函数

    我想表达一个可以取任何切片的函数 我想我可以这样做 func myFunc list interface for i range list some other fun i where some other fun 本身需要一个interf
  • 在 JavaScript 中将浮点数转换为整数的最佳方法是什么?

    在 JavaScript 中 有多种不同的方法可以将浮点数转换为整数 我的问题是哪种方法可以提供最佳性能 最兼容或被认为是最佳实践 以下是我所知道的几种方法 var a 2 5 window parseInt a 2 Math floor
  • Haskell 中自动函数约束推导的类型约束

    出于教育目的 我在 Haskell 中摆弄树木 我有Tree a像这样定义的类型 data Tree a EmptyTree Node a Tree a Tree a 以及许多共享基本约束的函数 Ord a 所以他们有这样的类型 treeI
  • IsPrimitive 不包含可为 null 的原始值

    我想检查类型是否是原始类型并使用以下代码 return type IsValueType type IsPrimitive 只要原始 int 可为空 这就可以正常工作 例如 int 如何检查该类型是否为可为空的原始类型 供参考 type I
  • 将 A => M[B] 转换为 M[A => B]

    对于一个单子M 是否可以转A gt M B into M A gt B 我尝试过遵循这些类型 但没有成功 这让我认为这是不可能的 但我想我还是会问 另外 搜索 Hooglea gt m b gt m a gt b 没有返回任何东西 所以我没
  • 未确定的泛型类型在 ghci 的运行时中如何表示

    我很清楚通用函数和通用数据类型 在泛型类型中 data SB forall x show x gt SB x instance Show SB where show SB x show x 所以对于任何给定类型x 如果它有一个签名Show
  • 为什么最好使用 Glib 数据类型(例如 `gint` 而不是 `int`)? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么glib要重新定义类型 https stackoverflow com questions 1819561 why does glib redefine types 在 GTK 2 0 教程中
  • 类型模块中的什么类型描述了一个类?什么类型描述了一个函数?

    The new typingPython 3 5 中的 module 提供了许多用于类型注释的工具 它是否提供了封装以下思想的对象或类型class 怎么样的想法function 在下面定义装饰器的代码中 应该代表什么class 应该代表什么
  • Chrome 控制台和 Javascript 对象类型

    我想找到 Javascipt 对象的类型 构造函数的名称 但我一直只是用我尝试过的所有方法得到一个通用的 对象 我在网上搜索过 但没有找到对我有用的 Javascript 方法 它始终只返回对象构造函数类型作为通用 对象 然而当我在 Chr
  • TypeScript:使用调用签名和构造函数签名实现接口

    是否可以创建一个实现以下接口的对象 interface I string new any 我看到可以实现一个具有调用签名和这个问题的一些字段的接口 使用裸函数签名和其他字段实现 TypeScript 接口 https stackoverfl

随机推荐