我正在尝试在本文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来说并不是很好。任何帮助表示赞赏。
答案 0 :(得分:2)
问题是您通过引用传递m_half,m_remain,depth和max_depth,然后在例程中分配它们。这会更改例程的每个实例中的值。
修复方法是将VALUE属性添加到这些参数的声明中。这将传递值的可写,匿名副本。