Skip to content

Commit 262c841

Browse files
dennisYatuninclaude
andcommitted
Report IndexLinear for contiguous-order DataLayouts [perf]
A DataLayout's IndexStyle now reports IndexLinear directly whenever a point's linear index equals its parent array's linear index -- when there is at most one dimension, a single component, or the F axis and every axis after it are singleton -- instead of deferring to the parent array's IndexStyle in the latter two cases. This is determined by the logical column-major shape, so it holds for any parent array type. A contiguous property-view SubArray reports IndexCartesian even though its linear order matches the layout's, so deferring to it routed every linear point access through a needless CartesianIndices conversion; reporting IndexLinear directly removes that conversion, which shrinks the typed IR of each access and lowers compilation memory. The change does not affect operator inlining, so it introduces no runtime regression, and it never reports IndexLinear where a point's order differs from its parent's (e.g. a multi-component layout with a non-singleton axis after F), which is verified by a new correctness test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ef0a74e commit 262c841

2 files changed

Lines changed: 44 additions & 4 deletions

File tree

src/DataLayouts/indexing.jl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@ const PointIndex = Union{Integer, CartesianIndex}
33

44
all_ones(params...) = params isa Tuple{Vararg{Integer}} && unrolled_all(isone, params)
55

6-
# Allow linear indexing if parent(data)[1:length(data)] has one value per point.
6+
# Use linear indexing whenever a point's linear index equals its parent's linear
7+
# index: when there is at most one dimension, when there is a single component
8+
# (one parent entry per point), or when the F axis and every axis after it are
9+
# singleton (so points are stored contiguously). This is determined by the
10+
# logical column-major shape, so it holds for any parent array type, and we
11+
# report IndexLinear directly rather than deferring to the parent's IndexStyle.
12+
# A contiguous property-view SubArray reports IndexCartesian even though its
13+
# linear order matches the layout's, and deferring to it would route every
14+
# linear access through a needless CartesianIndices conversion.
715
Base.IndexStyle(::Type{D}) where {D <: DataLayout} =
8-
ndims(D) <= 1 ? IndexLinear() :
9-
ncomponents(D) <= 1 || all_ones(inferred_size(D)[f_dim(D):end]...) ?
10-
IndexStyle(parent_type(D)) : IndexCartesian()
16+
ndims(D) <= 1 || ncomponents(D) <= 1 ||
17+
all_ones(inferred_size(D)[f_dim(D):end]...) ? IndexLinear() : IndexCartesian()
1118

1219
Base.IndexStyle(bc::MaybeFusedDataLayoutBroadcast) = IndexStyle(layout_args(bc)...)
1320

test/DataLayouts/unit_loops.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,36 @@ end
175175
end
176176
@test data.unit != test_data(device, T, 1, 11).unit
177177
end
178+
179+
@testset "linear indexing style and correctness" begin
180+
device = ClimaComms.device()
181+
arr(dims...) = device_array(device, Float64.(rand(1:(2^20), dims...)))
182+
S = Tuple{Float64, Float64}
183+
184+
# A point's linear index equals its parent's linear index (so IndexLinear is
185+
# valid) whenever there is a single component, or the F axis and everything
186+
# after it are singleton. Multi-component layouts with a non-singleton axis
187+
# after F must use Cartesian indexing.
188+
linear = [
189+
DataLayouts.VIJFH{Float64, 10, 4, 4, 5}(arr(10, 4, 4, 1, 5)), # 1 component
190+
DataLayouts.VIJHF{S, 10, 4, 4, 5}(arr(10, 4, 4, 5, 2)), # F axis last
191+
DataLayouts.VIJFH{S, 10, 4, 4, 1}(arr(10, 4, 4, 2, 1)), # Nh = 1
192+
DataLayouts.VIJFH{S, 10, 4, 4, 5}(arr(10, 4, 4, 2, 5)).:1, # property view
193+
]
194+
cartesian = [DataLayouts.VIJFH{S, 10, 4, 4, 5}(arr(10, 4, 4, 2, 5))] # F axis interior
195+
196+
for data in linear
197+
@test IndexStyle(data) == IndexLinear()
198+
end
199+
for data in cartesian
200+
@test IndexStyle(data) == IndexCartesian()
201+
end
202+
# Linear and Cartesian accesses must return identical values everywhere, so
203+
# that choosing IndexLinear never silently reads the wrong element.
204+
for data in vcat(linear, cartesian)
205+
@test all(
206+
data[i] == data[I] for
207+
(i, I) in enumerate(CartesianIndices(size(data)))
208+
)
209+
end
210+
end

0 commit comments

Comments
 (0)