通过示例优化 Julia 代码

k1n*_*ext 1 optimization performance numerical-methods julia

我目前正在用 Julia 编写一个数值求解器。我认为其背后的数学并不重要。这一切都归结为这样一个事实:特定操作会执行多次并占用很大比例(~80%)的运行时间。

我尝试尽可能地减少它并向您展示这段代码,它可以保存为dummy.jl然后通过include("dummy.jl")后跟dummy(10)(用于编译)然后执行dummy(1000)。

function dummy(N::Int64)
    A = rand(N,N)
    @time timethis(A)
end

function timethis(A::Array{Float64,2})
    dummyvariable = 0.0
    for k=1:100 # just repeat a few times
        for i=2:size(A)[1]-1
            for j=2:size(A)[2]-1
                    dummyvariable += slopefit(A[i-1,j],A[i,j],A[i+1,j],2.0)
                    dummyvariable += slopefit(A[i,j-1],A[i,j],A[i,j+1],2.0)
            end
        end
    end
    println(dummyvariable) 
end

@inline function minmod(x::Float64, y::Float64)
    return sign(x) * max(0.0, min(abs(x),y*sign(x) ) );
end

@inline function slopefit(left::Float64,center::Float64,right::Float64,theta::Float64)
    # arg=ccall((:minmod,"libminmod"),Float64,(Float64,Float64),0.5*(right-left),theta*(center-left));
    # result=ccall((:minmod,"libminmod"),Float64,(Float64,Float64),theta*(right-center),arg);
    # return result

    tmp = minmod(0.5*(right-left),theta*(center-left));
    return minmod(theta*(right-center),tmp);
    #return 1.0
end
Run Code Online (Sandbox Code Playgroud)

这里,timethis将模仿我花费大量时间的代码部分。我注意到,slopefit执行起来非常昂贵。

例如,dummy(1000)在我的机器上大约需要 4 秒。相反,如果slopefit总是返回1而不计算任何内容,则时间会减少到总时间的十分之一。

现在,显然没有免费的午餐。

我知道,这只是一次代价高昂的手术。但我仍然会尝试尽可能地优化它,因为很多时间都花在看起来可以轻松优化它的事情上,因为它只是几行代码。

到目前为止,我尝试将minmodand实现slopefit为 C 函数并调用它们,但这只是增加了计算时间(也许我做错了)。

所以我的问题是,我有哪些可能性来优化 的调用slopefit?

请注意,在实际代码中, 的参数slopefit不是此处提到的参数,而是依赖于条件语句,这使得所有内容都难以矢量化(我不确定这是否会带来任何性能提升)。

Bog*_*ski 5

我能想到的优化有两个级别。

首先:以下实现minmod会更快,因为它避免了分支(我知道这是您想要的功能):

@inline minmod(x::Float64, y::Float64) = ifelse(x<0, clamp(y, x, 0.0), clamp(y, 0.0, x))
Run Code Online (Sandbox Code Playgroud)

第二:你可以使用@inbounds来加快循环速度:

 @inbounds for i=2:size(A)[1]-1
Run Code Online (Sandbox Code Playgroud)