-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Performance regression in summing over StepRange and UnitRange (no longer O(1)) #39700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Bisected to 17a3c77 cc @johnnychen94 |
Just FYI, the same workaround as #38086 is available. However, this issue is not the issue with SIMD ( function perf_sumcartesian_simd(A)
s = zero(eltype(A))
@inbounds @simd for I in CartesianIndices(size(A))
val = Base.unsafe_getindex(A, I)
s += val
end
return s
end julia> @btime perf_sumcartesian_simd($A)
6.000 ns (0 allocations: 0 bytes) |
Changing the implementation of the iterator will change the optimization result. using Base.IteratorsMD: __inc
@inline function Base.iterate(iter::CartesianIndices{1}, state) # FIXME: this is just for experimentation
next = iterate(iter.indices[1], state.I[1])
next === nothing && return nothing
return CartesianIndex(next[1]), CartesianIndex(next[1])
end Edit |
It does not seem to be optimized when using julia/base/multidimensional.jl Lines 412 to 420 in 7853ddd
julia> iterate(1:10, -100)
(-99, -99)
julia> iterate(1:10, 100)
(101, 101) Edit: |
The implementation is quite simple. However, it is unclear whether this breaking change could be widely accepted. (Edit: Of course, I won't be proposing this for v1.6.) cc: @johnnychen94, @timholy Edit2: my original intentionimport Base: iterate
using Base: tail, heads
using Base.Iterators: Reverse
# in this style,
# state = ((ind1, state1), (ind2, state2), ..., (indN, stateN))
@inline function iterate(iter::CartesianIndices)
next = _iterate_nested_iters(iter.indices)
next === nothing && return nothing
return CartesianIndex(map(n -> n[1], next)), next
end
@inline function iterate(iter::CartesianIndices, state)
next = _iterate_nested_iters(iter.indices, state)
next === nothing && return nothing
return CartesianIndex(map(n -> n[1], next)), next
end
# please use `reverse()` instead of `Reverse()`
@inline function iterate(r::Reverse{<:CartesianIndices})
iterate(reverse(r.itr))
end
@inline function iterate(r::Reverse{<:CartesianIndices}, state)
iterate(reverse(r.itr), state)
end
function _iterate_nested_iters(indices)
next = iterate(indices[1])
next === nothing && return nothing
length(indices) == 1 && return (next, )
tnext = _iterate_nested_iters(tail(indices))
tnext === nothing && return nothing
return (next, tnext...)
end
function _iterate_nested_iters(indices, state)
next = iterate(indices[1], state[1][2])
if next === nothing
length(indices) == 1 && return nothing
tnext = _iterate_nested_iters(tail(indices), tail(state))
tnext === nothing && return nothing
h = iterate(indices[1])
h === nothing && return nothing
return (h, tnext...)
end
return (next, tail(state)...)
end 😅 using Base.Iterators
using Base.Iterators: ProductIterator
@inline function iterate(iter::CartesianIndices, state=nothing)
p = ProductIterator(iter.indices)
next = state === nothing ? iterate(p) : iterate(p, state)
next === nothing && return nothing
return CartesianIndex(next[1]), next[2]
end |
Still reproduces on 1.8.3 and 1.9.0-alpha1 |
I believe no longer reproduces |
Code to repro:
On master:
On 1.5:
The text was updated successfully, but these errors were encountered: