Skip to content

Commit 20b704a

Browse files
mbaumanKristofferC
authored andcommitted
Faster view creation (#19259)
* Ensure SubArray constructor inlines * Don't bother calculating the size of the SubArray during creation All it needs is the dimensionality of the indexing result. * Deprecate three-argument `SubArray` constructor * Wrap long lines
1 parent e22198b commit 20b704a

File tree

3 files changed

+39
-15
lines changed

3 files changed

+39
-15
lines changed

base/deprecated.jl

+3
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,9 @@ function convert(::Type{UpperTriangular}, A::Bidiagonal)
831831
end
832832
end
833833

834+
# Deprecate three-arg SubArray since the constructor doesn't need the dims tuple
835+
@deprecate SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple) SubArray(parent, indexes)
836+
834837
# Deprecate vectorized unary functions over sparse matrices in favor of compact broadcast syntax (#17265).
835838
for f in (:sin, :sinh, :sind, :asin, :asinh, :asind,
836839
:tan, :tanh, :tand, :atan, :atanh, :atand,

base/multidimensional.jl

+10
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ end
215215
end
216216
index_ndims() = ()
217217

218+
# combined dimensionality of all indices
219+
# rather than returning N, it returns an NTuple{N,Bool} so the result is inferrable
220+
@inline index_dimsum(i1, I...) = (index_dimsum(I...)...)
221+
@inline index_dimsum(::Colon, I...) = (true, index_dimsum(I...)...)
222+
@inline index_dimsum(::AbstractArray{Bool}, I...) = (true, index_dimsum(I...)...)
223+
@inline function index_dimsum{_,N}(::AbstractArray{_,N}, I...)
224+
(ntuple(x->true, Val{N})..., index_dimsum(I...)...)
225+
end
226+
index_dimsum() = ()
227+
218228
# Recursively compute the lengths of a list of indices, without dropping scalars
219229
# These need to be inlined for more than 3 indexes
220230
# Trailing CartesianIndex{0}s and arrays thereof are strange when used as

base/subarray.jl

+26-15
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@ immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N}
1212
offset1::Int # for linear indexing and pointer, only valid when L==true
1313
stride1::Int # used only for linear indexing
1414
function SubArray(parent, indexes, offset1, stride1)
15+
@_inline_meta
1516
check_parent_index_match(parent, indexes)
1617
new(parent, indexes, offset1, stride1)
1718
end
1819
end
1920
# Compute the linear indexability of the indices, and combine it with the linear indexing of the parent
20-
function SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple)
21-
SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, dims)
21+
function SubArray(parent::AbstractArray, indexes::Tuple)
22+
@_inline_meta
23+
SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, index_dimsum(indexes...))
2224
end
23-
function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, dims::NTuple{N})
25+
function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, ::NTuple{N})
26+
@_inline_meta
2427
SubArray{eltype(P), N, P, I, false}(parent, indexes, 0, 0)
2528
end
26-
function SubArray{P, I, N}(::LinearFast, parent::P, indexes::I, dims::NTuple{N})
29+
function SubArray{P, I, N}(::LinearFast, parent::P, indexes::I, ::NTuple{N})
30+
@_inline_meta
2731
# Compute the stride and offset
2832
stride1 = compute_stride1(parent, indexes)
2933
SubArray{eltype(P), N, P, I, true}(parent, indexes, compute_offset1(parent, stride1, indexes), stride1)
@@ -92,7 +96,7 @@ view(A::AbstractArray, I::Union{ViewIndex, AbstractCartesianIndex}...) = view(A,
9296
function unsafe_view(A::AbstractArray, I::ViewIndex...)
9397
@_inline_meta
9498
J = to_indexes(I...)
95-
SubArray(A, J, map(unsafe_length, index_shape(A, J...)))
99+
SubArray(A, J)
96100
end
97101
# When we take the view of a view, it's often possible to "reindex" the parent
98102
# view's indices such that we can "pop" the parent view and keep just one layer
@@ -103,15 +107,15 @@ end
103107
unsafe_view(V::SubArray, I::ViewIndex...) = (@_inline_meta; _maybe_reindex(V, to_indexes(I...)))
104108
_maybe_reindex(V, I) = (@_inline_meta; _maybe_reindex(V, I, I))
105109
_maybe_reindex{C<:AbstractCartesianIndex}(V, I, ::Tuple{AbstractArray{C}, Vararg{Any}}) =
106-
(@_inline_meta; SubArray(V, I, map(unsafe_length, index_shape(V, I...))))
110+
(@_inline_meta; SubArray(V, I))
107111
# But allow arrays of CartesianIndex{1}; they behave just like arrays of Ints
108112
_maybe_reindex{C<:AbstractCartesianIndex{1}}(V, I, A::Tuple{AbstractArray{C}, Vararg{Any}}) =
109113
(@_inline_meta; _maybe_reindex(V, I, tail(A)))
110114
_maybe_reindex(V, I, A::Tuple{Any, Vararg{Any}}) = (@_inline_meta; _maybe_reindex(V, I, tail(A)))
111115
function _maybe_reindex(V, I, ::Tuple{})
112116
@_inline_meta
113117
idxs = reindex(V, V.indexes, to_indexes(I...))
114-
SubArray(V.parent, idxs, map(unsafe_length, (index_shape(V.parent, idxs...))))
118+
SubArray(V.parent, idxs)
115119
end
116120

117121
## Re-indexing is the heart of a view, transforming A[i, j][x, y] to A[i[x], j[y]]
@@ -222,7 +226,7 @@ substrides(s, parent, dim, I::Tuple{Any, Vararg{Any}}) = throw(ArgumentError("st
222226
stride(V::SubArray, d::Integer) = d <= ndims(V) ? strides(V)[d] : strides(V)[end] * size(V)[end]
223227

224228
compute_stride1{N}(parent::AbstractArray, I::NTuple{N}) =
225-
compute_stride1(1, fill_to_length(indices(parent), OneTo(1), Val{N}), I)
229+
(@_inline_meta; compute_stride1(1, fill_to_length(indices(parent), OneTo(1), Val{N}), I))
226230
compute_stride1(s, inds, I::Tuple{}) = s
227231
compute_stride1(s, inds, I::Tuple{Real, Vararg{Any}}) =
228232
(@_inline_meta; compute_stride1(s*unsafe_length(inds[1]), tail(inds), tail(I)))
@@ -252,11 +256,15 @@ end
252256
# If the result is one-dimensional and it's a Colon, then linear
253257
# indexing uses the indices along the given dimension. Otherwise
254258
# linear indexing always starts with 1.
255-
compute_offset1(parent, stride1::Integer, I::Tuple) = (@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(I)..., I))
256-
compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Colon}, I::Tuple) = compute_linindex(parent, I) - stride1*first(indices(parent, dims[1])) # index-preserving case
257-
compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) = compute_linindex(parent, I) - stride1 # linear indexing starts with 1
259+
compute_offset1(parent, stride1::Integer, I::Tuple) =
260+
(@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(I)..., I))
261+
compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Colon}, I::Tuple) =
262+
(@_inline_meta; compute_linindex(parent, I) - stride1*first(indices(parent, dims[1]))) # index-preserving case
263+
compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) =
264+
(@_inline_meta; compute_linindex(parent, I) - stride1) # linear indexing starts with 1
258265

259266
function compute_linindex{N}(parent, I::NTuple{N})
267+
@_inline_meta
260268
IP = fill_to_length(indices(parent), OneTo(1), Val{N})
261269
compute_linindex(1, 1, IP, I)
262270
end
@@ -278,10 +286,13 @@ end
278286
compute_linindex(f, s, IP::Tuple, I::Tuple{}) = f
279287

280288
find_extended_dims(I) = (@_inline_meta; _find_extended_dims((), (), 1, I...))
281-
_find_extended_dims(dims, inds, dim) = dims, inds
282-
_find_extended_dims(dims, inds, dim, ::Real, I...) = _find_extended_dims(dims, inds, dim+1, I...)
283-
_find_extended_dims(dims, inds, dim, i1::AbstractCartesianIndex, I...) = _find_extended_dims(dims, inds, dim, i1.I..., I...)
284-
_find_extended_dims(dims, inds, dim, i1, I...) = _find_extended_dims((dims..., dim), (inds..., i1), dim+1, I...)
289+
_find_extended_dims(dims, inds, dim) = (@_inline_meta; return (dims, inds))
290+
_find_extended_dims(dims, inds, dim, ::Real, I...) =
291+
(@_inline_meta; _find_extended_dims(dims, inds, dim+1, I...))
292+
_find_extended_dims(dims, inds, dim, i1::AbstractCartesianIndex, I...) =
293+
(@_inline_meta; _find_extended_dims(dims, inds, dim, i1.I..., I...))
294+
_find_extended_dims(dims, inds, dim, i1, I...) =
295+
(@_inline_meta; _find_extended_dims((dims..., dim), (inds..., i1), dim+1, I...))
285296

286297
unsafe_convert{T,N,P,I<:Tuple{Vararg{RangeIndex}}}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) =
287298
unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T)

0 commit comments

Comments
 (0)