在 Julia 中优化剩余堆分配
Optimising away residual heap allocation in Julia
I 运行 julia --track-allocation prof.jl
导致以下输出:
- using FixedSizeArrays
-
- immutable KernelVals{T}
- wavenumber::T
- vect::Vec{3,T}
- dist::T
- green::Complex{T}
- gradgreen::Vec{3,Complex{T}}
- end
-
- function kernelvals(k, x, y)
- r = x - y
0 R2 = r[1]*r[1]
0 R2 += r[2]*r[2]
0 R2 += r[3]*r[3]
0 R = sqrt(R2)
-
0 γ = im*k
0 expn = exp(-γ * R)
0 fctr = 1.0 / (4.0*pi*R)
0 green = fctr * expn
64 gradgreen = -(γ + 1/R) * green / R * r
-
0 KernelVals(k, r, R, green, gradgreen)
- end
-
- function payload()
- x = Vec{3,Float64}(0.47046262275611883,0.8745228524771103,-0.049820876498487966)
0 y = Vec{3,Float64}(-0.08977259509004082,0.543199687600189,0.8291184043296924)
0 k = 1.0
0 kv = kernelvals(k,x,y)
- return kv
- end
-
- function driver()
- println("Flush result: ", payload())
0 Profile.clear_malloc_data()
0 payload()
- end
-
- driver()
我无法摆脱从 gradgreen...
开始的行中的最终内存分配。我 运行 @code_warntype kernelsvals(...)
,没有显示类型不稳定或不确定性。
julia-0.4.6
和 julia-0.5.0-pre
上的分配模式相同。
这个函数将是我正在实现的边界元法中的内核。它将被调用数百万次,导致总内存分配可以增长到可用物理内存的倍数
对我来说。
我使用 FixedSizeArrays
的原因是为了避免与创建小 Array
s 有关的分配。
报告分配的准确位置以非常敏感的方式取决于代码。在某些时候,内存分析器将 1/(4*pi*R)
归咎于触发分配的行。
非常感谢任何有关如何编写可预测分配模式的代码的帮助或一般提示。
经过一些实验,我终于设法摆脱了所有分配。罪魁祸首原来是 FixedSizeArrays
中扩展的促销架构。显然,将一个复数标量和一个实数向量相乘会沿途创建一个临时值。
将 gradgreen
的定义替换为
c = -(γ + 1/R) * green / R
gradgreen = Vec(c*r[1], c*r[2], c*r[3])
导致无分配运行。在我的基准示例中,执行时间从 6.5 秒下降到 4.15 秒。总分配大小从 4.5 GB 到 1.4 GB。
EDT:已将此问题报告给 FixedSizeArrays
开发人员,他们立即修复了它(谢谢!)。分配完全消失了。
I 运行 julia --track-allocation prof.jl
导致以下输出:
- using FixedSizeArrays
-
- immutable KernelVals{T}
- wavenumber::T
- vect::Vec{3,T}
- dist::T
- green::Complex{T}
- gradgreen::Vec{3,Complex{T}}
- end
-
- function kernelvals(k, x, y)
- r = x - y
0 R2 = r[1]*r[1]
0 R2 += r[2]*r[2]
0 R2 += r[3]*r[3]
0 R = sqrt(R2)
-
0 γ = im*k
0 expn = exp(-γ * R)
0 fctr = 1.0 / (4.0*pi*R)
0 green = fctr * expn
64 gradgreen = -(γ + 1/R) * green / R * r
-
0 KernelVals(k, r, R, green, gradgreen)
- end
-
- function payload()
- x = Vec{3,Float64}(0.47046262275611883,0.8745228524771103,-0.049820876498487966)
0 y = Vec{3,Float64}(-0.08977259509004082,0.543199687600189,0.8291184043296924)
0 k = 1.0
0 kv = kernelvals(k,x,y)
- return kv
- end
-
- function driver()
- println("Flush result: ", payload())
0 Profile.clear_malloc_data()
0 payload()
- end
-
- driver()
我无法摆脱从 gradgreen...
开始的行中的最终内存分配。我 运行 @code_warntype kernelsvals(...)
,没有显示类型不稳定或不确定性。
julia-0.4.6
和 julia-0.5.0-pre
上的分配模式相同。
这个函数将是我正在实现的边界元法中的内核。它将被调用数百万次,导致总内存分配可以增长到可用物理内存的倍数 对我来说。
我使用 FixedSizeArrays
的原因是为了避免与创建小 Array
s 有关的分配。
报告分配的准确位置以非常敏感的方式取决于代码。在某些时候,内存分析器将 1/(4*pi*R)
归咎于触发分配的行。
非常感谢任何有关如何编写可预测分配模式的代码的帮助或一般提示。
经过一些实验,我终于设法摆脱了所有分配。罪魁祸首原来是 FixedSizeArrays
中扩展的促销架构。显然,将一个复数标量和一个实数向量相乘会沿途创建一个临时值。
将 gradgreen
的定义替换为
c = -(γ + 1/R) * green / R
gradgreen = Vec(c*r[1], c*r[2], c*r[3])
导致无分配运行。在我的基准示例中,执行时间从 6.5 秒下降到 4.15 秒。总分配大小从 4.5 GB 到 1.4 GB。
EDT:已将此问题报告给 FixedSizeArrays
开发人员,他们立即修复了它(谢谢!)。分配完全消失了。