17.2.294. MPI_Reduce_local
MPI_Reduce_local — 执行本地归约操作
17.2.294.1. 语法
17.2.294.1.1. C语法
#include <mpi.h>
int MPI_Reduce_local(const void *inbuf, void *inoutbuf, int count,
MPI_Datatype datatype, MPI_Op op)
17.2.294.1.2. Fortran语法
USE MPI
! or the older form: INCLUDE 'mpif.h'
MPI_REDUCE_LOCAL(INBUF, INOUTBUF, COUNT, DATATYPE, OP, IERROR)
<type> INBUF(*), INOUTBUF(*)
INTEGER COUNT, DATATYPE, OP, IERROR
17.2.294.1.3. Fortran 2008 语法
USE mpi_f08
MPI_Reduce_local(inbuf, inoutbuf, count, datatype, op, ierror)
TYPE(*), DIMENSION(..), INTENT(IN) :: inbuf
TYPE(*), DIMENSION(..) :: inoutbuf
INTEGER, INTENT(IN) :: count
TYPE(MPI_Datatype), INTENT(IN) :: datatype
TYPE(MPI_Op), INTENT(IN) :: op
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
17.2.294.2. 输入参数
inbuf: 输入缓冲区的地址(选项)。count: 输入缓冲区中的元素数量(整数)。datatype: 输入缓冲区元素的数据类型(句柄)。op: 归约操作(句柄)。
17.2.294.3. 输出参数
inoutbuf: 输入/输出缓冲区的地址(选项)。ierror: 仅限Fortran:错误状态(整数)。
17.2.294.4. 描述
全局归约函数(MPI_Reduce_local、MPI_Op_create、 MPI_Op_free、MPI_Allreduce、MPI_Reduce_local_scatter、MPI_Scan)用于在 组内所有成员之间执行全局归约操作(如求和、最大值、逻辑与等)。归约操作可以是预定义操作列表中的一种, 也可以是用户自定义操作。全局归约函数有多种形式:将归约结果返回给单个节点的reduce操作、 将结果返回给所有节点的all-reduce操作,以及扫描(并行前缀)操作。此外, reduce-scatter操作结合了reduce和scatter操作的功能。
MPI_Reduce_local 将本地进程输入缓冲区和输入/输出缓冲区中的元素通过操作op进行组合,并将结果返回到inout/output缓冲区中。输入缓冲区由参数inbuf、count和datatype定义;输出缓冲区由参数inoutbuf、count和datatype定义;两者具有相同数量的元素和相同类型。该例程是一个本地调用。进程可以提供一个元素或一个元素序列,在这种情况下,组合操作会对序列中的每个条目逐个执行。例如,如果操作是MPI_MAX且输入缓冲区包含两个浮点数元素(count = 2且datatype = MPI_FLOAT),那么inoutbuf(1) = 全局最大值(inbuf(1))且inoutbuf(2) = 全局最大值(inbuf(2))。
17.2.294.5. 原地选项的使用
在MPI_Reduce_local中不允许使用MPI_IN_PLACE。
17.2.294.6. 预定义的归约操作
MPI提供的预定义操作集如下所示(预定义归约操作)。该部分还列举了每个操作可应用的数据类型。此外,用户可以定义自己的操作,这些操作可以被重载以处理多种数据类型,包括基本类型和派生类型。关于用户自定义操作的详细说明,请参阅相关手册页(参见MPI_Op_create和MPI_Op_free)。
操作op始终被假定为具有结合性。所有预定义的操作也被假定为具有交换性。用户可以定义被假定为具有结合性但不具有交换性的操作。归约操作的"规范"执行顺序由组中进程的等级决定。然而,实现可以利用结合性,或结合性和交换性来改变执行顺序。对于非严格结合和交换的操作(如浮点加法),这可能会改变归约的结果。
预定义运算符仅适用于下面列出的MPI类型(预定义归约操作,以及下方的MINLOC和MAXLOC部分)。用户自定义运算符可以操作通用的派生数据类型。在这种情况下,归约操作应用的每个参数都是由此类数据类型描述的一个元素,可能包含多个基本值。MPI标准第4.9.4节"用户自定义操作"对此有进一步说明。
以下预定义操作用于MPI_Reduce_local及相关函数MPI_Allreduce、MPI_Reduce_scatter和MPI_Scan。这些操作通过在op参数中指定以下内容来调用:
Name Meaning
--------- --------------------
MPI_MAX maximum
MPI_MIN minimum
MPI_SUM sum
MPI_PROD product
MPI_LAND logical and
MPI_BAND bit-wise and
MPI_LOR logical or
MPI_BOR bit-wise or
MPI_LXOR logical xor
MPI_BXOR bit-wise xor
MPI_MAXLOC max value and location
MPI_MINLOC min value and location
MPI_MINLOC和MPI_MAXLOC这两个操作将在下文中单独讨论(MINLOC和MAXLOC)。对于其他预定义操作,我们下面列举了允许的op和datatype参数组合。首先,按照以下方式定义MPI基本数据类型组:
C integer: MPI_INT, MPI_LONG, MPI_SHORT,
MPI_UNSIGNED_SHORT, MPI_UNSIGNED,
MPI_UNSIGNED_LONG
Fortran integer: MPI_INTEGER
Floating-point: MPI_FLOAT, MPI_DOUBLE, MPI_REAL,
MPI_DOUBLE_PRECISION, MPI_LONG_DOUBLE
Logical: MPI_LOGICAL
Complex: MPI_COMPLEX
Byte: MPI_BYTE
现在,每个选项的有效数据类型如下所示。
Op Allowed Types
---------------- ---------------------------
MPI_MAX, MPI_MIN C integer, Fortran integer,
floating-point
MPI_SUM, MPI_PROD C integer, Fortran integer,
floating-point, complex
MPI_LAND, MPI_LOR, C integer, logical
MPI_LXOR
MPI_BAND, MPI_BOR, C integer, Fortran integer, byte
MPI_BXOR
17.2.294.7. MINLOC 与 MAXLOC
操作符MPI_MINLOC用于计算全局最小值及其对应的索引。类似地,MPI_MAXLOC用于计算全局最大值及其索引。这些操作的一个应用场景是计算全局最小(最大)值以及包含该值的进程的排名。
定义MPI_MAXLOC的操作是
( u ) ( v ) ( w )
( ) o ( ) = ( )
( i ) ( j ) ( k )
where
w = max(u, v)
and
( i if u > v
(
k = ( min(i, j) if u = v
(
( j if u < v)
MPI_MINLOC的定义方式类似:
( u ) ( v ) ( w )
( ) o ( ) = ( )
( i ) ( j ) ( k )
where
w = min(u, v)
and
( i if u < v
(
k = ( min(i, j) if u = v
(
( j if u > v)
这两种操作都具有结合性和交换性。需要注意的是,如果对一系列(u(0), 0), (u(1), 1), ..., (u(n-1), n-1)这样的数值对应用MPI_MAXLOC进行归约操作,返回的结果将是(u, r),其中u= max(i) u(i),而r是该序列中第一个全局最大值的索引。因此,如果每个进程提供一个值及其在组内的排名,那么使用op = MPI_MAXLOC的归约操作将返回最大值以及第一个具有该值的进程的排名。类似地,MPI_MINLOC可用于返回最小值及其索引。更一般地说,MPI_MINLOC计算的是字典序最小值,其中元素根据每对数值的第一个分量排序,当第一个分量相同时则根据第二个分量决定顺序。
归约操作被定义为对由值和索引组成的参数对进行操作。对于Fortran和C语言,都提供了描述这种参数对的类型。这种参数可能具有混合类型的特性在Fortran中会带来问题。针对Fortran,通过让MPI提供的类型由与值相同类型的对组成,并将索引强制转换为相同类型,从而规避了这个问题。而在C语言中,MPI提供的参数对类型具有不同的类型,且索引是一个整型。
为了在归约操作中使用MPI_MINLOC和MPI_MAXLOC,必须提供一个表示值-索引对的数据类型参数。OpenMPI提供了九种这样的预定义数据类型。MPI_MAXLOC和MPI_MINLOC操作可与以下每种数据类型配合使用:
Fortran:
Name Description
MPI_2REAL pair of REALs
MPI_2DOUBLE_PRECISION pair of DOUBLE-PRECISION variables
MPI_2INTEGER pair of INTEGERs
C:
Name Description
MPI_FLOAT_INT float and int
MPI_DOUBLE_INT double and int
MPI_LONG_INT long and int
MPI_2INT pair of ints
MPI_SHORT_INT short and int
MPI_LONG_DOUBLE_INT long double and int
数据类型 MPI_2REAL 等同于:
call MPI_TYPE_CONTIGUOUS(2, MPI_REAL, MPI_2REAL)
类似的声明适用于MPI_2INTEGER、MPI_2DOUBLE_PRECISION和MPI_2INT。
MPI_FLOAT_INT 数据类型相当于通过以下指令序列定义的。
::.. 代码块:: c
type[0] = MPI_FLOAT type[1] = MPI_INT disp[0] = 0 disp[1] = sizeof(float) block[0] = 1 block[1] = 1 MPI_TYPE_STRUCT(2, block, disp, type, MPI_FLOAT_INT)
类似的声明也适用于MPI_LONG_INT和MPI_DOUBLE_INT。
所有MPI对象(例如MPI_Datatype、MPI_Comm)在Fortran中都是INTEGER类型。
17.2.294.8. 关于集合操作的注意事项
归约操作符(MPI_Op)不会返回错误值。因此,如果函数检测到错误,它们只能选择调用MPI_Abort或静默跳过该问题。因此,如果您将错误处理程序从MPI_ERRORS_ARE_FATAL更改为其他选项,例如MPI_ERRORS_RETURN,则可能不会指示任何错误。
原因在于确保所有集合例程返回相同错误值时存在的性能问题。
17.2.294.9. 错误
几乎所有MPI例程都会返回一个错误值;C语言例程通过函数返回值返回,Fortran例程则通过最后一个参数返回。
在返回错误值之前,会调用与通信对象(如通信器、窗口、文件)关联的当前MPI错误处理程序。如果MPI调用未关联任何通信对象,则该调用被视为附加到MPI_COMM_SELF,并将调用关联的MPI错误处理程序。当MPI_COMM_SELF未初始化时(即在MPI_Init/MPI_Init_thread之前、MPI_Finalize之后,或仅使用会话模型时),错误会触发初始错误处理程序。初始错误处理程序可通过在使用世界模型时调用MPI_Comm_set_errhandler来修改MPI_COMM_SELF,或通过mpiexec的mpi_initial_errhandler命令行参数,或MPI_Comm_spawn/MPI_Comm_spawn_multiple的info键来设置。如果未设置其他适当的错误处理程序,则MPI I/O函数将调用MPI_ERRORS_RETURN错误处理程序,而其他所有MPI函数将调用MPI_ERRORS_ABORT错误处理程序。
Open MPI 包含三个可使用的预定义错误处理器:
MPI_ERRORS_ARE_FATAL导致程序中止所有连接的MPI进程。MPI_ERRORS_ABORT一个可在通信器、窗口、文件或会话上调用的错误处理程序。当在通信器上调用时,其行为类似于在该通信器上调用MPI_Abort。如果在窗口或文件上调用,则行为类似于在包含对应窗口或文件中进程组的通信器上调用MPI_Abort。如果在会话上调用,则仅中止本地进程。MPI_ERRORS_RETURN向应用程序返回一个错误代码。
MPI应用程序也可以通过调用以下方式实现自己的错误处理程序:
请注意,MPI不保证MPI程序在出现错误后能够继续运行。
有关更多信息,请参阅MPI-3.1标准中的错误处理部分。