Performance regression with indexing a `reinterpret`ed array in v0.7


#1

Hi,

while updating a package of mine I stumbled into what I think is a regression associated to indexing a reinterpreted array. Basically I have a custom array-like type as

struct MyArray{T<:Real, V1<:AbstractArray{Complex{T}}, V2<:AbstractArray{T}}
    data::V1
    linear_data::V2
    function MyArray(data::AbstractArray{Complex{T}}) where {T}
        linear_data = reinterpret(T, data)
        new{T, typeof(data), typeof(linear_data)}(data, linear_data)
    end
end

where the second field holds a linear view of the first. I then implement indexing for this type, like

Base.@propagate_inbounds @inline getindex(a::MyArray, i) = (@inbounds ret = a.linear_data[i]; ret)

and so on for setindex!.

A much more complicated code using this type is now significantly (4x) slower on v0.7 than it was on v0.6. Profiling the code shows that quite a bit of time is spent in indexing the new ReinterpretArray type, that is returned in v0.7 from reinterpret(T, data).

A quick test on the REPL shows that on 2 days old master

using BenchmarkTools

julia> a = im*[1.0, 2.0, 3.0]
3-element Array{Complex{Float64},1}:
 0.0 + 1.0im
 0.0 + 2.0im
 0.0 + 3.0im

julia> b = reinterpret(Float64, a)
6-element reinterpret(Float64, ::Array{Complex{Float64},1}):
 0.0
 1.0
 0.0
 2.0
 0.0
 3.0

julia> @btime @inbounds getindex($b, 1)
  7.791 ns (0 allocations: 0 bytes)
0.0

while on v0.6 I get

julia> a = im*[1.0, 2.0, 3.0]
3-element Array{Complex{Float64},1}:
 0.0+1.0im
 0.0+2.0im
 0.0+3.0im

julia> b = reinterpret(Float64, a)
6-element Array{Float64,1}:
 0.0
 1.0
 0.0
 2.0
 0.0
 3.0

julia> @btime @inbounds getindex($b, 1)
  1.276 ns (0 allocations: 0 bytes)

Is this worth reporting?


#2

BTW, I have just tried replacing the reinterpreted array with a pointer to the data of the right type plus using unsafe_load and unsafe_store!. With this fix I recover the original performance of 0.6 (actually slightly better).


#3

See https://github.com/JuliaLang/julia/pull/27213