11.6 Fortran 77语言捆绑 |
Fortran 77实质上是ANSI/ISO标准Fortran的一个子集,因此大多数与HPF调用Fortran有关的考虑也适用于HPF调用Fortran 77外部例程。但是Fortran和Fortran 77之间的两个主要不同使得任意EXTRINSIC(LANGUAGE='F77')的说明,从HPF的接口,尤其是对于本地模型,变得复杂化:
为扩展HPF_LOCAL和FORTRAN_LOCAL外部接口,定义了一个EXTRINSIC(F77_LOCAL)接口以满足Fortran 77程序员的需要。
这个EXTRINSIC类型使用了上面所描述的调用外部子程序的语法。可将它更细致地描述为EXTRINSIC(LANGUAGE='F77',MODEL='LOCAL')接口。第11节中前面所描述的用于全局和本地例程之间的传送控制的基本惯例在这里也适合。
但是这两种语言之间参数传递和数据分配中的不同点,以及使用这种接口的不同动机,可通过允许用于传递数据和分配信息的额外选项来更好地阐述。这些选项由LAYOUT和PASS_BY属性所提供。
一个典型的Fortran 77实现是通过引用传递参数,通常传递第一个数据元素位置的基地址,同时这些元素也可被假定为顺序相联的。这些事实使从HPF向F77_LOCAL例程传递一个分布数据结构的缺省方法变得最实用,这种缺省方法是通过传递分配给局存该区域的基地址实现的。为考虑实参和哑参的顺序相联,如果有必要也应在所有处理器上对数据进行重排序或进行压缩或二者兼做。这是向EXTRINSIC(F77_LOCAL)例程传递分布数据的最安全的方法,因它应该把它作为一种缺省的方法。但是这可能导致最大的性能开销。
另一种参数传递选择是从全局HPF例程向本地F77例程传递分布数组数据,这种方法不保证哑参的顺序相联以避免当要求处理器本地数组元素压缩或重排序时所可能导致的不希望的本地数据移动。换句话说,所发生的数据移动不应比同样参数传递给另一个HPF过程更多。由于本地实参部件没有重排序或压缩,因此保证哑参顺序相联牺牲了可能的性能上的收益。本地程序员一定可以使用全局HPF程序所创建的依赖于实现的次序。
可用于从EXTRINSIC(F77_LOCAL)过程调用中允许HPF_LOCAL风格本地程序设计的第三个选择是通过描述符或句柄传递数组,就象在HPF实现中或对于Fortran 90假定形状的数组所典型做的那样。本地例程不能直接访问这个哑参元素,但或许为了获得本地或全局分配信息,可以将它传递给一个特殊的实用例程。
下列属性足够支持上面三种向EXTINSIC(F77_LOCAL)例程传递数据的选择形式:
进一步讲,INTERFACE模块中的每个参数也可具有指定的PASS_BY属性以便指明对于Fortran 77风格的访问,是否通过引用,或者通过一个特殊句柄(或许是HPF变量传递的一个描述符)进行数据传递,后者允许全局HPF单元传递特殊分配信息用于本地Fortran 77例程中。
这样,缺省的哑参属性是LAYOUT('F77_ARRAY'),并保证了顺序相联和PASS_BY('*'),这种指定使得数据可通过指向它位置的指针进行传递。
对实现者的建议:除了参数传递和数据重排序选择之外,一个好的EXTRINSIC(F77_LOCAL)实现应该解决下面的问题:定义任意大小的本地子网格且象HPF那样不需将它们描述为假定形状的数组就可访问它们的元素。在每个由外部过程调用初始化的本地过程内处理全局数组分配的本地结果,如果没有Fortran 90数组查询函数和HPF库中的查询子程序,也可能很困难。(对实现者的建议结束)
本例阐述了使用缺省LAYOUT('F77_ARRAY')和PASS_BY('*')属性的F77_LOACL程序设计,以及对于从本地级使用LAYOUT('F77_ARRAY')属性的查询例程的使用。
程序例子
!定义数据数组和一个检验拷贝
integer, parameter :: nx = 100, ny = 100
real, dimension(nx,ny) :: x, y
!hpf$ distribute(block,block) :: x, y
!通过在处理器上形成部分和,计算出全局和
real partial_sum(number_of_processors())
!hpf$ distribute partial_sum(block)
在每个处理器上为一个二维数组定义本地子网格参数
integer, dimension(number_of_processors(),2) ::
& lb, ub, number
!hpf$ distribute(block,*) :: lb, ub, number
! 定义接口
interface
extrinsic(f77_local) subroutine local1
& ( lb1, ub1, lb2, ub2, x , x_desc )
integer, dimension(:) :: lb1, ub1, lb2, ub2
real,dimension(:,:),layout('HPF_ARRAY') :: x
real,dimension(:,:),layout('HPF_ARRAY'), &
pass_by('HPF_HANDLE') :: x_desc
!hpf$ distribute(block) :: lb1, ub1, lb2, ub2
!hpf$ distribute(block,block) :: x, x_desc
end
extrinsic(f77_local) subroutine local2(n,x,r)
integer n(:)
real x(:,:), r(:)
! 缺省: layout('F77\_ARRAY'), 例如:顺序的,以列为主存储;
! pass_by('*'), 例如通过应用传送(本地地址)
!hpf$ distribute n(block)
!hpf$ distribute x(block,block)
!hpf$ distribute r(block)
end
end interface
!仅使用全局HPF确定结果
! 初始化值
forall (i=1:nx,j=1:ny) x(i,j) = i + (j-1) * nx
! 确定和报告全局和
print *, 'global HPF result: ',sum(x)
!使用本地子程序确定结果
!初始化值 (假定步长 = 1 )
call HPF_subgrid_info( y, ierr, lb=lb, ub=ub )
if (ierr.ne.0) stop 'error!'
call local1( lb(:,1), ub(:,1), lb(:,2), ub(:,2), y , y )
! 确定和报告全局和
number = ub - lb + 1
call local2 ( number(:,1) * number(:,2) , y , partial_sum )
print *, 'F77_LOCAL result #1 : ',sum(partial_sum)
end
subroutine local1( lb1, ub1, lb2, ub2, x , descrx )
real x ( lb1 : ub1 , lb2 : ub2 )
integer descrx ( * )
!得到第一维的全局范围
!这是一个具有"F77_"前缀的查询例程的HPF_LOCAL类型。
call F77_global_size ( nx , descrx , 1 )
!初始化数组元素
do j = lb2, ub2
do i = lb2, ub2
x(i,j) = i + (j-1) * nx
end do
end do
end
subroutine local2(n,x,r)
!在这里,全局索引的对应关系不重要,仅传递子网格的总大小
in real x(n)
r = 0
.do i = 1, n
r = r + x(i)
end do
end
本例仅执行上面例子的初始化。它阐述了无须重映射传递一个HPF分布数组的LAYOUT('F77_ARRAY')属性的使用,以及在F77_LOCAL子网格查询函数中传递HPF分隔描述符或句柄的PASS_BY('HPF_HANDLE')的使用。它还阐述了关于“嵌入数组“数据的寻址。
程序例子
integer, parameter :: nx = 100, ny = 100
real, dimension(nx,ny) :: y
!hpf$ distribute(block,block) :: y
!在每个处理器上为一个二维数组所定义的子网格参数
integer, dimension(number_of_processors(),2) ::
& lb, ub, lb_embed, ub_embed
!hpf$ distribute(block,*) :: lb, ub, lb_embed, ub_embed
! 定义接口
interface
extrinsic(f77_local) subroutine local1(
& lb1, ub1, lb_embed1, ub_embed1,
& lb2, ub2, lb_embed2, ub_embed2, x, x_desc )
integer, dimension(:) ::
& lb1, ub1, lb_embed1, ub_embed1,
& lb2, ub2, lb_embed2, ub_embed2
!x缺省是通过引用传递
real, dimension(:,:), layout('hpf_array') :: x
! x_desc通过它的描述符或‘句柄’传递
real, dimension(:,:), layout('hpf_array'),
& pass_by('hpf_handle') :: x_desc
!hpf$ distribute(block) :: lb1, ub1, lb_embed1, ub_embed1
!hpf$ distribute(block) :: lb2, ub2, lb_embed2, ub_embed2
!hpf$ distribute(block,block) :: x
end
end interface
!初始化值
! (假定步长=1且没有维转置 )
call HPF_subgrid_info( y, ierr,
& lb=lb, lb_embed=lb_embed,
& ub=ub, ub_embed=ub_embed)
if (ierr.ne.0) stop 'error!'
call local1(
& lb(:,1), ub(:,1), lb_embed(:,1), ub_embed(:,1),
& lb(:,2), ub(:,2), lb_embed(:,2), ub_embed(:,2), y, y )
end
subroutine local1(
& lb1, ub1, lb_embed1, ub_embed1,
& lb2, ub2, lb_embed2, ub_embed2, x, x_desc )
! 在它的“嵌入”形式中,子网格已被传递
real x ( lb_embed1 : ub_embed1 , lb_embed2 : ub_embed2 )
!这个参数仅用作查询函数的输入
integer x_desc
!得到第一维的全局范围
!这是一个具有"F77_"前缀的查询例程的HPF_LOCAL类型
call F77_global_size(nx,x_desc,1)
!否则,初始化数组元素
!仅对实数组元素进行循环
do j = lb2, ub2
do i = lb2, ub2
x(i,j) = i + (j-1) * nx
end do
end do
end
Copyright: NPACT |