简单数学函数的基准:为什么Fortran和Julia比C更快

Alb*_*ert 2 c fortran microbenchmark julia

有一些争论,在某些情况下,Fortran可能比C更快,例如,当涉及到别名时,我经常听说它比C更好地进行自动矢量化(这里有一些很好的讨论).

然而,对于简单的函数来计算Fibonaci数和Mandelbrot在一些复数时使用直接解决方案而没有任何技巧和额外的提示/关键字到编译器,我会期望他们真的执行相同.

C实施:

int fib(int n) {
    return n < 2 ? n : fib(n-1) + fib(n-2);
}

int mandel(double complex z) {
    int maxiter = 80;
    double complex c = z;
    for (int n=0; n<maxiter; ++n) {
        if (cabs(z) > 2.0) {
            return n;
        }
        z = z*z+c;
    }
    return maxiter;
}
Run Code Online (Sandbox Code Playgroud)

Fortran实现:

integer, parameter :: dp=kind(0.d0)          ! double precision

integer recursive function fib(n) result(r)
integer, intent(in) :: n
if (n < 2) then
    r = n
else
    r = fib(n-1) + fib(n-2)
end if
end function

integer function mandel(z0) result(r)
complex(dp), intent(in) :: z0
complex(dp) :: c, z
integer :: n, maxiter
maxiter = 80
z = z0
c = z0
do n = 1, maxiter
    if (abs(z) > 2) then
        r = n-1
        return
    end if
    z = z**2 + c
end do
r = maxiter
end function
Run Code Online (Sandbox Code Playgroud)

朱莉娅实施:

fib(n) = n < 2 ? n : fib(n-1) + fib(n-2)

function mandel(z)
    c = z
    maxiter = 80
    for n = 1:maxiter
        if abs(z) > 2
            return n-1
        end
        z = z^2 + c
    end
    return maxiter
end
Run Code Online (Sandbox Code Playgroud)

(可在此处找到包含其他基准功能的完整代码.)

根据Julia的主页,Julia和Fortran -O3(with -O3)在这两个函数上的表现优于C(with ).

怎么可能?

Ste*_*ski 7

老实说,我不会太认真地对待这些差异.不同的C编译器也会给出不同的结果.尝试使用GCC和Clang运行C微基准测试,您将获得与C vs. Fortran差不多的差异.为什么GCC有时比Clang更快,有时候不是?他们只是以不同的方式进行不同的优化和代码生成.不同硬件上的相对性能也不同,因为它可能取决于寄存器的确切数量,高速缓存大小,超标量吞吐量,各种指令的相对速度等.

奇怪的是,Fortran语言是如此快得多的FIB基准,所以如果有人数字,一个出来,帖子这里的答案,我会很乐意给予好评,但在曼德尔和其他基准的≤15%的差异仅仅是不是所有的非凡的.关于这些基准测试,对我来说最神秘的是Fortran在整数解析方面的速度如此之慢.我怀疑这是因为代码是愚蠢的,但我不是Fortran编码器所以我不确定应该改进什么.如果有人读这篇文章是Fortran专业版,并想看一下这段代码,我们将不胜感激.我怀疑Fortran比C慢5倍是错误的.

需要注意的一点是,在整理这些基准测试结果时,我们会拒绝零时间,以避免计算编译器只是对整个计算进行常量折叠的情况.在一些优化级别上,这正是C和Fortran编译器所做的,并且很难强迫它们不要这样做,缺少使用较低的优化级别.如果有人想弄清楚如何在不完全优化基准代码的同时强制编译器不要不断地折叠这些结果,那将是一个受欢迎的贡献.(一种可能的方法是使用完全优化将基准函数编译为共享库,然后将其链接到主程序并关闭链接时优化.这很棘手,但它可能有用.)

最终,对于确切的微基准数字过多担忧会让人眼前一亮.这些基准测试的重点是某些语言具有可靠的快速标准实现 - 如C,Fortran,Julia和Go - 而其他语言则不然.在慢速语言中,您有时不得不求助于使用不同的语言来获得所需的性能,而在可靠的快速语言中,您永远不必这样做.这就是所有这一切.快速语言的确切相对表现是一场军备竞赛:有时候一种语言可能会领先,但其他语言总会紧随其后 - 关键是它们完全处于竞争中.

  • 在检查优化的汇编程序输出(`-S`标志)时,C的函数占用大约70行,而gfortran使用115(我使用4.4.7,所以可能有些差异)?似乎`ichar`功能是一个昂贵的电话. (2认同)