squ*_*bar 6 performance julia fixed-size-types
我想写一个以矩阵作为输入的函数.这是一个复杂项目中的频繁低级调用,因此尽可能快地使这个功能具有潜在的严重性能影响.因为速度对我来说非常重要,我正在使用类型,FixedSizeArrays因为我知道这将节省内存使用量.但我经常知道输入矩阵的某些属性,我不确定我是否正在充分利用它.
这是一个简单的例子.想象一下,我希望尽可能快地完成以下功能:
using FixedSizeArrays
function foo( input::Mat )
# NB: Mat is the FixedSizeArrays matrix type
return 2 * input
end
Run Code Online (Sandbox Code Playgroud)
显然这是一个微不足道的例子,但这不是重点.关键是我对矩阵的维度有所了解input:它总是只有两列,我总是可以在运行时指定行数.这似乎是可以传递给编译器以使我的代码更快的信息.我可以将它作为定义大小的参数传递input吗?这是一个不起作用的例子,但应该让你知道我正在尝试做什么.
function bar( int::N, thismat::Mat{N,2,Float64} )
return 2 * thismat
end
Run Code Online (Sandbox Code Playgroud)
有这样的东西我可以做吗?如果可以的话,这会发挥作用吗?也许FixedSizeArrays已经做了所有可以完成的事情.谢谢你的想法!
固定大小的数组已经专门用于大小.N在您的情况下,行数可能会有所不同时,这些数组不适合.您注意到的任何性能问题都可能是因为过度专业化.
让我更具体一点.
Julia编译器能够通过对参数类型的积极专业化来实现零成本抽象.所以一般情况下(也就是说,除了少数专业化过于昂贵或明确禁用的情况),如果使用两种不同类型的签名调用函数,则将编译此函数的两个版本.
由于a的大小Mat是其类型的一部分,这意味着将为每个可能的大小编译版本Mat.所以你所寻求的专业化已经完成.
然而,专业化不是免费的.它有两个成本:
因此,如果你的矩阵是大小(2, N),其中N各不相同,在编译的时候不知道,性能成本的动态调度会发生.这种性能成本可以通过使用功能屏障技术来限制:我们只为每个类型不稳定的呼叫产生一次成本,因此限制此类呼叫的数量可以提高性能.
但是,更能提高性能的是完全避免这种动态调度.可以构造一个仅对该类型中的列数进行编码的数组类型,并将行数作为运行时的字段.也就是说,您的性能问题可能是由于过度专业化,您需要创建类型以减少专业化的数量.
找到适当的平衡对于从应用程序中挤出尽可能多的性能至关重要.专门研究数组的大小实际上非常有用 - 例如,即使C和C++代码也倾向于将数组大小作为运行时参数传递,而不是专门针对特定的数组大小.这并不贵.在更多情况下,不会,FixedSizeArrays.jl不会提高性能,而是会伤害它.当然有一些情况会有所帮助 - 但你的可能不是其中之一.
在您的情况下,为了获得最佳性能,我怀疑这样的类型会最快:
immutable TwoColumnMatrix{T, BaseType} <: AbstractArray{T, 2}
height::Int
base::BaseType
end
function TwoColumnMatrix(A::Matrix)
size(A, 2) == 2 || throw(ArgumentError("must be two columns"))
TwoColumnMatrix{eltype(A), typeof(A)}(size(A, 1), A)
end
Base.@propagate_inbounds function getindex(M::TwoColumnMatrix, n::Int)
M.base[n]
end
size(M::TwoColumnMatrix) = (M.height, 2)
Run Code Online (Sandbox Code Playgroud)
您可能需要定义其他方法以获得最佳性能,并且一如既往地定义基准.包装器的开销可能不值得编译器了解尺寸.