疯狂的空间分配随机微分方程的求解系统

时间:2020-05-09 20:53:55

标签: performance julia differentialequations.jl

第一次在这里提问。 我以前使用简单的MATLAB脚本对90个Hopf振荡器进行建模,该振荡器通过矩阵耦合,具有兰德噪声,并具有简单的Euler阶跃积分。我想对其进行升级,所以我进入了Julia,似乎具有许多令人兴奋的特性。

This is the system of equations I'm solving

我有点迷路了。我开始使用differentialequations.jl(随机求解器),找到了一个解决方案,并发现自己拥有一个基准,该基准告诉我,解决200秒占用的内存为4 Gb! (2.5 Gb,带有alg_hints = [:stiff])(我尚未修复dt,以前我使用dt = 0.1)

function Shopf(du,u,p,t)

  du[1:90,1]=(p[1:90,1]-u[1:90,1].^2.0-u[1:90,2].^2.0).*u[1:90,1]-p[1:90,2].*u[1:90,2] + 0.5*(-p[: , end].*u[:,1]+p[:,4:end-1] *u[:,1])
  du[1:90,2]=(p[1:90,1]-u[1:90,1].^2.0-u[1:90,2].^2.0).*u[1:90,1]+p[1:90,2].*u[1:90,1] + 0.5*(-p[: , end].*u[:,2]+p[:,4:end-1] *u[:,2])

end


function σ_Shopf(du,u,p,t)

du[1:90,1]=0.04*ones(90,1)
du[1:90,2]=0.04*ones(90,1)


end


#initial condition
u0=-0.1*ones(90,2);
#initial time
t0=0.0;
#final time
tend=200.0;
#setting parameter matrix
p0=[0.1 , 2*pi*0.04]
push!(p0,-p0[2])
p=p0'.*ones(90,3);
SC=SC;
p=[p SC]
p=[p sum(SC,dims=2)]
#


#col 1 :alpha
#col 2-3 : [w0 -w0]

#col 3-93 : coupling matrix
#col 94: col-wise sum of coupling matrix


@benchmark solve(prob_sde_Shopf,nlsolver=Rosenbrock23(),alg_hints=[:stiff])

BenchmarkTools.Trial: 内存估计:2.30 GiB

分配估计数:722769


最短时间:859.224毫秒(GC为13.24%)

中位时间:942.707 ms(GC为13.10%)

平均时间:975.430毫秒(GC为12.99%)

最长时间:1.223 s(13.00%GC)


样本:6

小样/样本:1

有什么想法吗?我正在检查几种解决方案,但没有一个将内存量减少到合理的数量。 预先感谢。

1 个答案:

答案 0 :(得分:5)

您正在创建数量惊人的临时数组。每个切片都会创建一个临时文件。您在此处到处都加了点,但必须点所有内容才能进行融合广播。相反,您可以只使用@.宏来帮您。另外,使用@views将确保不复制切片:

function Shopf(du, u, p, t)
    @. du[1:90, 1] = @views (p[1:90, 1] - u[1:90, 1]^2 - u[1:90, 2]^2) * u[1:90, 1] -
        p[1:90, 2] * u[1:90,2] + 0.5 * (-p[:, end] * u[:, 1] + p[:, 4:end-1] * u[:,1])
    @. du[1:90, 2] = @views (p[1:90, 1] - u[1:90, 1]^2 - u[1:90, 2]^2) * u[1:90, 1] + 
        p[1:90, 2] * u[1:90,1] + 0.5 * (-p[:, end] * u[:, 2] + p[:, 4:end-1] * u[:,2])  
end

也不要写x^2.0,而要使用x^2,前者是一个缓慢的浮动电源,而后者是一个快速的x * x。实际上,请尽可能在乘法,加法等中使用整数。

这是另一回事

function σ_Shopf(du,u,p,t)

du[1:90,1]=0.04*ones(90,1)
du[1:90,2]=0.04*ones(90,1)


end

无需在分配的右侧创建两个临时数组。只需写下:

function σ_Shopf(du, u, p, t)
    du[1:90, 1:2] .= 0.04
end

更快,更简单。请注意,我尚未对此进行测试,因此请修正所有错别字。

(最后,请使用缩进并在运算符周围放置空格,这会使您的代码更易于阅读。)

更新:我真的不知道您的代码应该做什么,使用奇怪的索引怎么做,但这是可能的改进,它仅使用循环(我认为它实际上更清洁,可以让您进行进一步的优化):

产生A的操作是矩阵乘积,因此除非您可以使用mul!传递高速缓存数组以进行处理,否则您不能避免在那里进行分配。除此之外,下面您应该没有分配。

function shopf!(du, u, p, t)
    A = @view p[:, 4:end-1] * u
    # mul!(A, view(p, 4:end-1), u)  # in-place matrix product
    for i in axes(u, 1)
        val = (p[i, 1] - u[i, 1]^2 - u[i, 2]^2) * u[i, 1]  # don't calculate this twice
        du[i, 1] = val - (p[i, 2] * u[i, 2]) - (0.5 * p[i, end] * u[i, 1]) + 
            (0.5 * A[i, 1])
        du[i, 2] = val + (p[i, 2] * u[i, 1]) - (0.5 * p[i, end] * u[i, 2]) + 
            (0.5 * A[i, 2])
    end
end

此后,如果您对LoopVectorization实验包中的数组大小,多线程,@inbounds甚至是@simd有把握,则可以添加各种优化,@avx