Fortran递归和GEMM

时间:2018-04-06 19:22:38

标签: recursion fortran matrix-multiplication hpc

我正在尝试在本文CARMA Publication中找到Fortran中的CARMA GEMM算法。可以在此处找到使用C语言编写的Github上源代码的链接:CARMA CILK SGEMM

该算法使用分而治之的方法,将最大矩阵维度从m,n,k分成两个子问题,这些子问题可以通过递归并行执行。结束条件在原始矩阵的一部分上执行GEMM。这段代码使用了Cilk线程,但我对并行性还不感兴趣。

我遇到了一个问题,了解如何在使用递归时在Fortran中实现就地矩阵乘法。以下代码是我尝试仅拆分维度M,它仍处于测试阶段。代码使用ifort 16.0编译,但不能正确执行。在提供的示例中,主程序中的C1和C2将具有不同的结果。不会发生编译器警告或运行时错误。只是错误的最终答案。

! ******************************
!         MODULE 
! ******************************
MODULE RECURSION_GEMM_MOD

IMPLICIT NONE
CONTAINS

RECURSIVE SUBROUTINE GEMM_RECURSION(m,n,k,alpha,beta,A,B,C,depth,max_depth)

integer, intent(in) :: m, n, k, depth, max_depth
real, intent(in) :: alpha, beta
real, intent(in) :: A(m,k), B(k,n)
real, intent(inout) :: C(m,n)

integer :: m_half, m_remain

! End condition for recursion - compute C <- alpha*AB + beta*C
IF( depth >= max_depth ) THEN
  CALL SGEMM('N','N', m, n, k, alpha, A, m, B, k, beta, C, m)
  RETURN
END IF

m_half = m/2
m_remain = m - m_half

! Divide GEMM into two block matrix sub-problems (top and bot)

! A_top, C_top
CALL GEMM_RECURSION(m_half,n,k,alpha,beta, A,B,C,depth+1,max_depth)

! A_bot, C_bot
CALL GEMM_RECURSION(m_remain,n,k,alpha,beta,A(m_half+1,1),B,C(m_half+1,1),depth+1,max_depth)

END SUBROUTINE GEMM_RECURSION

END MODULE RECURSION_GEMM_MOD


! **********************************
!         MAIN PROGRAM 
! **********************************
PROGRAM RECURSION_GEMM

USE RECURSION_GEMM_MOD
IMPLICIT NONE

INTEGER :: m,n,k,m_half, m_remain
INTEGER :: depth, max_depth
REAL :: C1(2,4), C2(2,4)

REAL :: A(2,3) = TRANSPOSE( RESHAPE( (/ 1.0, 2.0, 3.0,&
                                    4.0, 5.0, 6.0 /), (/ 3,2 /) ) )
REAL :: B(3,4) =  TRANSPOSE( RESHAPE( (/ 5.0, 6.0, 7.0, 8.0, &
                                     1.0, 2.0, 3.0, 4.0, &
                                     9.0, 10.0, 11.0, 12.0/), (/ 4,3 /) ) )
REAL :: C(2,4) =  TRANSPOSE( RESHAPE( (/ 1.0, 0.0, 1.0, 1.0, &
                                     0.0, 1.0, 0.0, 1.0 /), (/ 4,2 /) ) )            
REAL :: alpha = 1.0, beta = 1.0

m = 2
k = 3
n = 4

! Copy C into C1 for later
C1 = C

depth = 0
max_depth = 1

! Recursion GEMM stored in C1
CALL GEMM_RECURSION(m,n,k,alpha,beta,A,B,C1,depth,max_depth)

! Reference GEMM stored in C2
C2 = alpha*MATMUL(A,B) + beta*C

PRINT*, 'C1 = '
PRINT*, C1
PRINT*, ''

PRINT*, 'C2 = '
PRINT*, C2

END PROGRAM RECURSION_GEMM

我一直在查阅关于Fortran子程序和递归的每个文档,但是那里还没有那么多。我已经检查了使用指针,但我所看到的一切都表明它们的性能非常糟糕,这对GEMM来说并不是很好。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

问题是您通过引用传递m_half,m_remain,depth和max_depth,然后在例程中分配它们。这会更改例程的每个实例中的值。

修复方法是将VALUE属性添加到这些参数的声明中。这将传递值的可写,匿名副本。