Fortran 广度优先搜索 运行 慢

Fortran breadth first search running slowly

背景: 我编写了一个 Fortran 子例程,它根据未加权的有向网络的邻接矩阵计算最短路径长度矩阵。该子例程使用广度优先搜索算法。最短路径长度矩阵的对角元素为最短环路长度。

我也在MATLAB中实现了这个算法。我正在迁移到 Fortran,希望减少 运行 次(请注意,我是 Fortran 的新手)。然而,这个子例程 运行 在 MATLAB 中比在 Fortran 实现中稍微快一点(对于相同的 ~1000 节点网络,在 MATLAB 中大约 44 秒,在 Fortran 中大约 46 秒)。这对我来说没有意义,因为我的理解是 Fortran 对于基于循环的操作应该明显更快。我的一些其他子例程在 Fortran 中快 1-2 个数量级。

我在 OSX 10.10.2 上编译,安装了最新的 gfortran 二进制文件,没有优化标志。 (打开优化标志实际上似乎进一步降低了代码速度。)

问题: 谁能看到我的 fortan 代码中可能导致 运行 效率低下的缺陷? (对于 Fortran 新手的任何其他一般提示也将不胜感激)。或者,这个任务有更快的算法吗?

代码:

subroutine spl(a,splmat)
implicit none

! Input: Adjacency matrix a
logical, intent(in) :: a(:,:)

! Output: Shortest path length matrix
integer, dimension (:,:), allocatable :: splmat

integer, dimension (:), allocatable :: stk

! Variables: nnodes (size of network); s (source node); r (read ptr);
! w (write pointer) ; d (distance from s to node n), n (the node
! pointed to by the value of the stack at r); j (loop variable);
integer :: nnodes,s,r,w,d,n,j

nnodes = size(a,1)

allocate(splmat(nnodes,nnodes))
splmat = 0

allocate (stk(nnodes))

! Outer loop over each node
do s = 1,nnodes
    stk = 0
    stk(1) = s
    r = 1
    w = 2

    ! Inner loop
    do while (r/=w)
        n = stk(r)
        r = r+1

        d = splmat(s,n)

        do j=1,nnodes
            if (a(n,j).and.(splmat(s,j)==0)) then
                splmat(s,j) = d+1
                stk(w) = j
                w = w+1
            end if
        end do
    end do
end do
end subroutine spl

我不知道您使用的是什么算法,但我立即注意到一个非常简单的问题,即您的索引顺序错误,无法在 Fortran 中获得最佳性能。

我的意思是这通常不好:

do i = 1, m
    do j = 1, n
        ! Do something with a(i,j)
    end do
end do

而这要好得多:

do j = 1, n
    do i = 1, m
        ! Do something with a(i,j)
    end do
end do

对于小问题通常没有太大区别(除非在某些情况下您严重依赖 SIMD 向量化来提高性能)。然而,对于更大的问题,缓存使用效率可能会有很大差异。