MasonProtter/Bumper.jl

MethodErrors caused by StrideArrays.jl overrides

MilesCranmer opened this issue · 11 comments

MWE:

In a fresh REPL:

julia> using Bumper: @no_escape, @alloc

julia> using Random: randn!

julia> T = ComplexF32
ComplexF32 (alias for Complex{Float32})

julia> @no_escape begin
           ar = @alloc(T, 100)
           randn!(ar)
           @. ar = cos(ar)
           sum(ar)
       end
109.13606f0 + 4.8591895f0im

However, if I import StrideArrays, I get an error:

julia> using Bumper: @no_escape, @alloc

julia> using StrideArrays

julia> using Random: randn!

julia> T = ComplexF32
ComplexF32 (alias for Complex{Float32})

julia> @no_escape begin
           ar = @alloc(T, 100)
           randn!(ar)
           @. ar = cos(ar)
           sum(ar)
       end
ERROR: MethodError: no method matching vmaterialize!(::PtrArray{…}, ::Base.Broadcast.Broadcasted{…}, ::Val{…}, ::Val{…}, ::Val{…})

Closest candidates are:
  vmaterialize!(::Any, ::Any, ::Val{Mod}, ::Val{UNROLL}) where {Mod, UNROLL}
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:753
  vmaterialize!(::Union{LinearAlgebra.Adjoint{T, A}, LinearAlgebra.Transpose{T, A}}, ::BC, ::Val{Mod}, ::Val{UNROLL}, ::Val{dontbc}) where {T<:Union{Bool, Float16, Float32, Float64, Int16, Int32, Int64, Int8, UInt16, UInt32, UInt64, UInt8, SIMDTypes.Bit}, N, A<:AbstractArray{T, N}, BC<:Union{Base.Broadcast.Broadcasted, LoopVectorization.Product}, Mod, UNROLL, dontbc}
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:682
  vmaterialize!(::AbstractArray{T, N}, ::BC, ::Val{Mod}, ::Val{UNROLL}, ::Val{dontbc}) where {T<:Union{Bool, Float16, Float32, Float64, Int16, Int32, Int64, Int8, UInt16, UInt32, UInt64, UInt8, SIMDTypes.Bit}, N, BC<:Union{Base.Broadcast.Broadcasted, LoopVectorization.Product}, Mod, UNROLL, dontbc}
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:673
  ...

Stacktrace:
 [1] vmaterialize!
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:759 [inlined]
 [2] _materialize!
   @ StrideArrays ~/.julia/packages/StrideArrays/PeLtr/src/broadcast.jl:181 [inlined]
 [3] materialize!(dest::PtrArray{…}, bc::Base.Broadcast.Broadcasted{…})
   @ StrideArrays ~/.julia/packages/StrideArrays/PeLtr/src/broadcast.jl:188
 [4] macro expansion
   @ REPL[5]:4 [inlined]
 [5] macro expansion
   @ ~/.julia/packages/Bumper/eoK0g/src/internals.jl:74 [inlined]
 [6] top-level scope
   @ REPL[5]:1
Some type information was truncated. Use `show(err)` to see complete types.

I think maybe a fallback methods should be used if it doesn't exist?

Hm, yeah that seems to be a problem in StrideArrays.jl's broadcast system, it's just manifesting here because Bumper uses types from StrideArrays.

julia> using StrideArrays

julia> let a = StrideArray{ComplexF32}(undef, 10)
           a .= 1
           a .= cos.(a)
       end
ERROR: MethodError: no method matching vmaterialize!(::StrideArray{…}, ::Base.Broadcast.Broadcasted{…}, ::Val{…}, ::Val{…}, ::Val{…})

Closest candidates are:
  vmaterialize!(::Any, ::Any, ::Val{Mod}, ::Val{UNROLL}) where {Mod, UNROLL}
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:753
  vmaterialize!(::Union{Adjoint{T, A}, Transpose{T, A}}, ::BC, ::Val{Mod}, ::Val{UNROLL}, ::Val{dontbc}) where {T<:Union{Bool, Float16, Float32, Float64, Int16, Int32, Int64, Int8, UInt16, UInt32, UInt64, UInt8, SIMDTypes.Bit}, N, A<:AbstractArray{T, N}, BC<:Union{Base.Broadcast.Broadcasted, LoopVectorization.Product}, Mod, UNROLL, dontbc}
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:682
  vmaterialize!(::AbstractArray{T, N}, ::BC, ::Val{Mod}, ::Val{UNROLL}, ::Val{dontbc}) where {T<:Union{Bool, Float16, Float32, Float64, Int16, Int32, Int64, Int8, UInt16, UInt32, UInt64, UInt8, SIMDTypes.Bit}, N, BC<:Union{Base.Broadcast.Broadcasted, LoopVectorization.Product}, Mod, UNROLL, dontbc}
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:673
  ...

Stacktrace:
 [1] vmaterialize!
   @ LoopVectorization ~/.julia/packages/LoopVectorization/7gWfp/src/broadcast.jl:759 [inlined]
 [2] _materialize!
   @ StrideArrays ~/.julia/packages/StrideArrays/PeLtr/src/broadcast.jl:181 [inlined]
 [3] materialize!(dest::StrideArray{…}, bc::Base.Broadcast.Broadcasted{…})
   @ StrideArrays ~/.julia/packages/StrideArrays/PeLtr/src/broadcast.jl:188
 [4] top-level scope
   @ REPL[9]:3

Could you try opening an issue in StrideArrays.jl?

It could also be Complex is maybe not supported by StrideArrays? I know that they are not by LoopVectorization at least. For such types maybe @alloc could fall back to regular allocations?

Signature:

T<:Union{Bool, Float16, Float32, Float64, Int16, Int32, Int64, Int8, UInt16, UInt32, UInt64, UInt8, SIMDTypes.Bit}

So what's going on here is that Bumper.jl uses StrideArraysCore.jl because it defines nice pointer-backed performant array types. If one loads StrideArrays.jl, then StrideArraysCore.jl will override various things like broadcasting and matrix multiplication on those types to use LoopVectorization.jl instead of the normal machinery.

That normally works fine, but there are cases where those overrides probably shouldn't be defined, such as when one encounters a Complex, but this isn't really something that Bumper.jl itself has control over, it's really just up to StrideArrays.jl

However, due to issues like this, and the fact that StrideArrays isn't being actively worked on very often, I am considering making a new pointer backed array type to use instead of those from StrideArraysCore.

Given that LoopVectorization.jl is being deprecated for 1.11, I was wondering what the status of this? I would be very eager to make Bumper.jl a hard dependency for some of my packages, as the perf has been extremely good, but I only hesitate because of the interaction with the soon-to-be-deprecated StrideArrays/LoopVectorization ecosystem. Maybe the PtrArray could simply be copied over so StrideArrays doesn't overload it?

Friendly ping @MasonProtter

Hey Miles, sorry I want to evaluate options soon. I'm considering switching to UnsafeArrays.jl or something like that, or forking StrideArraysCore or something but haven't had time or bandwidth to deal with it lately. I'm hoping I can get to this soon-ish though

Thanks!

Btw, I think @alloc should take an explicit array_type argument to avoid this sort of “spooky action at a distance” Then the user would be in charge of specifying StrideArray if they want it, rather than this being something that gets injected behind-the-scenes depending on a hidden global state of the Julia runtime.

Currently planning on just dropping StrideArrays and switching to https://github.com/LilithHafner/PtrArrays.jl/ instead. Should give us everything we need.

Awesome, looking forward to it!!

Friendly ping on this