Skip to content

Commit eec2785

Browse files
committed
Fix silent corruption in strided mapreducedim! on the LTS stack
1 parent 65de48c commit eec2785

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

src/mapreduce.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,32 @@ function partial_mapreduce_device(f, op, neutral, maxitems, Rreduce, Rother, R,
105105
return
106106
end
107107

108+
# Coalesced reduction for when the contiguous leading dimension is NOT reduced (the reduced
109+
# axes are strided). One work-item per output slice (Rother element), grid-strided; each
110+
# serially reduces over Rreduce. Consecutive work-items map to consecutive output slices,
111+
# which are consecutive in memory, so global reads are coalesced across lanes — the access
112+
# pattern a `dims=1` reduction already uses. On the Aurora LTS stack the workgroup-per-slice
113+
# kernel above reads a *strided* reduced dimension non-coalesced, which silently corrupts
114+
# large reductions (e.g. `sum(A; dims=2)`); this path avoids that pattern entirely.
115+
function coalesced_mapreduce_device(f, op, neutral, Rreduce, Rother, R, As...)
116+
iother = (get_group_id() - 1) * get_local_size() + get_local_id()
117+
gstride = get_num_groups() * get_local_size()
118+
@inbounds while iother <= length(Rother)
119+
Iother = Rother[iother]
120+
Iout = CartesianIndex(Tuple(Iother)..., 1)
121+
neut = neutral === nothing ? R[Iout] : neutral
122+
val = op(neut, neut)
123+
for ireduce in 1:length(Rreduce)
124+
Ireduce = Rreduce[ireduce]
125+
J = max(Iother, Ireduce)
126+
val = op(val, f(_map_getindex(As, J)...))
127+
end
128+
R[Iout] = val
129+
iother += gstride
130+
end
131+
return
132+
end
133+
108134
## COV_EXCL_STOP
109135

110136
function GPUArrays.mapreducedim!(f::F, op::OP, R::oneWrappedArray{T},
@@ -133,6 +159,20 @@ function GPUArrays.mapreducedim!(f::F, op::OP, R::oneWrappedArray{T},
133159
# but allows us to write a generalized kernel supporting partial reductions.
134160
R′ = reshape(R, (size(R)..., 1))
135161

162+
# Aurora LTS workaround: the workgroup-per-slice kernel below reads a *strided* reduced
163+
# dimension non-coalesced, which silently corrupts reductions on this stack (regardless of
164+
# output count — it depends on the reduction length, not the number of slices). Whenever
165+
# the contiguous leading dimension is NOT reduced (`size(Rreduce, 1) == 1`), use the
166+
# coalesced one-work-item-per-slice kernel, whose lanes read consecutive memory. Few-slice
167+
# reductions get less parallelism but stay correct; the common many-slice case is also fast.
168+
if size(Rreduce, 1) == 1
169+
items = clamp(length(Rother), 1, 256)
170+
groups = min(cld(length(Rother), items), 1024)
171+
@oneapi items=items groups=groups coalesced_mapreduce_device(
172+
f, op, init, Rreduce, Rother, R′, A)
173+
return R
174+
end
175+
136176
# how many items do we want?
137177
#
138178
# items in a group work together to reduce values across the reduction dimensions;

0 commit comments

Comments
 (0)