cumo 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +590 -152
- data/CHANGELOG.md +63 -0
- data/README.md +245 -0
- data/bench/cumo_probe.rb +1 -1
- data/cumo.gemspec +7 -1
- data/ext/cumo/cuda/cudnn.c +18 -0
- data/ext/cumo/cuda/cudnn_impl.cpp +60 -14
- data/ext/cumo/cuda/driver.c +11 -9
- data/ext/cumo/cuda/memory_pool_impl.cpp +32 -22
- data/ext/cumo/cuda/memory_pool_impl.hpp +3 -1
- data/ext/cumo/cuda/memory_pool_impl_test.cpp +19 -25
- data/ext/cumo/cuda/runtime.c +56 -0
- data/ext/cumo/cumo.c +4 -0
- data/ext/cumo/extconf.rb +2 -0
- data/ext/cumo/include/cumo/bit_reduce_kernel.h +6 -6
- data/ext/cumo/include/cumo/check.h +11 -3
- data/ext/cumo/include/cumo/cuda/cudnn.h +43 -6
- data/ext/cumo/include/cumo/cuda/runtime.h +2 -0
- data/ext/cumo/include/cumo/indexer.h +16 -0
- data/ext/cumo/include/cumo/intern.h +11 -0
- data/ext/cumo/include/cumo/narray.h +1 -0
- data/ext/cumo/include/cumo/reduce_kernel.h +283 -54
- data/ext/cumo/include/cumo/row_kernel.h +202 -0
- data/ext/cumo/include/cumo/row_method.h +149 -0
- data/ext/cumo/include/cumo/template_kernel.h +26 -0
- data/ext/cumo/include/cumo/types/bf16_def.h +82 -0
- data/ext/cumo/include/cumo/types/bf16_def_kernel.h +28 -0
- data/ext/cumo/include/cumo/types/bf16_macro.h +14 -0
- data/ext/cumo/include/cumo/types/bf16_macro_kernel.h +19 -0
- data/ext/cumo/include/cumo/types/bfloat.h +22 -0
- data/ext/cumo/include/cumo/types/bfloat_kernel.h +16 -0
- data/ext/cumo/include/cumo/types/bit.h +2 -0
- data/ext/cumo/include/cumo/types/bit_kernel.h +2 -0
- data/ext/cumo/include/cumo/types/complex_macro.h +2 -0
- data/ext/cumo/include/cumo/types/complex_macro_kernel.h +2 -0
- data/ext/cumo/include/cumo/types/f16_macro.h +191 -0
- data/ext/cumo/include/cumo/types/f16_macro_kernel.h +214 -0
- data/ext/cumo/include/cumo/types/float_def.h +8 -0
- data/ext/cumo/include/cumo/types/float_def_kernel.h +8 -0
- data/ext/cumo/include/cumo/types/float_macro.h +26 -17
- data/ext/cumo/include/cumo/types/float_macro_kernel.h +26 -19
- data/ext/cumo/include/cumo/types/half_macro.h +6 -180
- data/ext/cumo/include/cumo/types/half_macro_kernel.h +6 -185
- data/ext/cumo/include/cumo/types/robj_macro.h +2 -0
- data/ext/cumo/include/cumo/types/xint_macro.h +2 -6
- data/ext/cumo/include/cumo/types/xint_macro_kernel.h +2 -0
- data/ext/cumo/include/cumo.h +2 -2
- data/ext/cumo/narray/data.c +15 -6
- data/ext/cumo/narray/data_kernel.cu +110 -0
- data/ext/cumo/narray/gen/def/bfloat.rb +57 -0
- data/ext/cumo/narray/gen/def/bit.rb +12 -1
- data/ext/cumo/narray/gen/def/dcomplex.rb +12 -1
- data/ext/cumo/narray/gen/def/dfloat.rb +11 -1
- data/ext/cumo/narray/gen/def/hfloat.rb +11 -1
- data/ext/cumo/narray/gen/def/int16.rb +12 -1
- data/ext/cumo/narray/gen/def/int32.rb +12 -1
- data/ext/cumo/narray/gen/def/int64.rb +12 -1
- data/ext/cumo/narray/gen/def/int8.rb +12 -1
- data/ext/cumo/narray/gen/def/robject.rb +12 -1
- data/ext/cumo/narray/gen/def/scomplex.rb +12 -1
- data/ext/cumo/narray/gen/def/sfloat.rb +11 -1
- data/ext/cumo/narray/gen/def/uint16.rb +12 -1
- data/ext/cumo/narray/gen/def/uint32.rb +12 -1
- data/ext/cumo/narray/gen/def/uint64.rb +12 -1
- data/ext/cumo/narray/gen/def/uint8.rb +12 -1
- data/ext/cumo/narray/gen/narray_def.rb +35 -6
- data/ext/cumo/narray/gen/spec.rb +14 -14
- data/ext/cumo/narray/gen/tmpl/accum_arg.c +1 -1
- data/ext/cumo/narray/gen/tmpl/accum_binary.c +63 -5
- data/ext/cumo/narray/gen/tmpl/accum_binary_kernel.cu +29 -13
- data/ext/cumo/narray/gen/tmpl/accum_index.c +1 -1
- data/ext/cumo/narray/gen/tmpl/batch_norm.c +4 -4
- data/ext/cumo/narray/gen/tmpl/batch_norm_backward.c +5 -5
- data/ext/cumo/narray/gen/tmpl/binary.c +3 -9
- data/ext/cumo/narray/gen/tmpl/complex_accum_kernel.cu +15 -5
- data/ext/cumo/narray/gen/tmpl/conv.c +90 -123
- data/ext/cumo/narray/gen/tmpl/conv_grad_w.c +91 -83
- data/ext/cumo/narray/gen/tmpl/conv_transpose.c +90 -123
- data/ext/cumo/narray/gen/tmpl/cum.c +8 -7
- data/ext/cumo/narray/gen/tmpl/cum_kernel.cu +7 -6
- data/ext/cumo/narray/gen/tmpl/fixed_batch_norm.c +4 -4
- data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +22 -10
- data/ext/cumo/narray/gen/tmpl/gemm.c +11 -41
- data/ext/cumo/narray/gen/tmpl/layer_norm.c +38 -0
- data/ext/cumo/narray/gen/tmpl/layer_norm_kernel.cu +54 -0
- data/ext/cumo/narray/gen/tmpl/lib.c +1 -0
- data/ext/cumo/narray/gen/tmpl/lib_kernel.cu +1 -0
- data/ext/cumo/narray/gen/tmpl/median.c +1 -1
- data/ext/cumo/narray/gen/tmpl/poly.c +0 -3
- data/ext/cumo/narray/gen/tmpl/poly_kernel.cu +1 -1
- data/ext/cumo/narray/gen/tmpl/pooling_backward.c +3 -2
- data/ext/cumo/narray/gen/tmpl/pooling_forward.c +3 -2
- data/ext/cumo/narray/gen/tmpl/quantize_symmetric.c +74 -0
- data/ext/cumo/narray/gen/tmpl/quantize_symmetric_kernel.cu +67 -0
- data/ext/cumo/narray/gen/tmpl/rand.c +9 -9
- data/ext/cumo/narray/gen/tmpl/rand_kernel.cu +9 -9
- data/ext/cumo/narray/gen/tmpl/rand_norm.c +4 -4
- data/ext/cumo/narray/gen/tmpl/rand_norm_kernel.cu +7 -7
- data/ext/cumo/narray/gen/tmpl/real_accum_kernel.cu +6 -6
- data/ext/cumo/narray/gen/tmpl/rms_norm.c +38 -0
- data/ext/cumo/narray/gen/tmpl/rms_norm_kernel.cu +57 -0
- data/ext/cumo/narray/gen/tmpl/softmax.c +21 -0
- data/ext/cumo/narray/gen/tmpl/softmax_kernel.cu +157 -0
- data/ext/cumo/narray/gen/tmpl/sort.c +9 -32
- data/ext/cumo/narray/gen/tmpl/sort_index.c +16 -95
- data/ext/cumo/narray/gen/tmpl/store_array.c +12 -9
- data/ext/cumo/narray/gen/tmpl/store_from.c +1 -16
- data/ext/cumo/narray/gen/tmpl_bit/mask.c +11 -11
- data/ext/cumo/narray/gen/tmpl_bit/store_array.c +5 -9
- data/ext/cumo/narray/gen/tmpl_bit/where.c +50 -11
- data/ext/cumo/narray/gen/tmpl_bit/where2.c +11 -12
- data/ext/cumo/narray/gen/tmpl_bit/where_kernel.cu +1 -2
- data/ext/cumo/narray/index.c +35 -25
- data/ext/cumo/narray/index_kernel.cu +27 -0
- data/ext/cumo/narray/math.c +40 -8
- data/ext/cumo/narray/narray.c +85 -15
- data/ext/cumo/narray/ndloop.c +210 -5
- data/ext/cumo/narray/sort_kernel.cu +61 -41
- data/ext/cumo/narray/struct.c +3 -0
- data/lib/cumo/cuda/cudnn.rb +1 -1
- data/lib/cumo/narray/extra.rb +2 -2
- data/test/bfloat_test.rb +238 -0
- data/test/bit_test.rb +52 -14
- data/test/cuda/memory_pool_test.rb +8 -7
- data/test/cuda/runtime_test.rb +25 -0
- data/test/cudnn_test.rb +108 -24
- data/test/extra_test.rb +1 -1
- data/test/fused_test.rb +587 -0
- data/test/math_test.rb +182 -2
- data/test/narray_alt_coverage_test.rb +1 -0
- data/test/narray_test.rb +344 -22
- data/test/test_helper.rb +1 -0
- metadata +32 -5
- data/ext/cumo/narray/gen/tmpl/qsort.c +0 -205
|
@@ -69,6 +69,11 @@ typedef struct {
|
|
|
69
69
|
bool out_flat;
|
|
70
70
|
bool out2_flat;
|
|
71
71
|
bool out_inner; // the out axis, not the reduce axis, runs along memory
|
|
72
|
+
// How many consecutive indices share one address, for a range that is flat
|
|
73
|
+
// once a trailing run of broadcast axes is taken off it. Zero when the
|
|
74
|
+
// range is not of that shape, and never 1: a divisor of 1 is in_out_flat.
|
|
75
|
+
int64_t in_out_div;
|
|
76
|
+
int64_t in_reduce_div;
|
|
72
77
|
ssize_t in_out_step; // bytes, or bits for a Bit input
|
|
73
78
|
ssize_t in_reduce_step; // bytes, or bits for a Bit input
|
|
74
79
|
ssize_t out_step; // bytes
|
|
@@ -93,8 +98,58 @@ static inline bool axes_are_flat(const TIarray& iarray, const cumo_na_indexer_t&
|
|
|
93
98
|
return true;
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
// axes_are_flat for a range that ends in broadcast axes. A step of 0 does not
|
|
102
|
+
// move the address, so the offset of the i-th element is (i / div) * step,
|
|
103
|
+
// where div is how many indices share one address. Answers a div of 1 where
|
|
104
|
+
// there is no such axis, which is what axes_are_flat already describes.
|
|
105
|
+
template <typename TIarray>
|
|
106
|
+
static inline bool axes_are_flat_bcast(const TIarray& iarray, const cumo_na_indexer_t& indexer, int begin, int end, ssize_t* step, int64_t* div) {
|
|
107
|
+
int64_t d = 1;
|
|
108
|
+
while (end > begin && iarray.step[end - 1] == 0) {
|
|
109
|
+
d *= static_cast<int64_t>(indexer.shape[end - 1]);
|
|
110
|
+
--end;
|
|
111
|
+
}
|
|
112
|
+
if (!axes_are_flat(iarray, indexer, begin, end, step)) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
*div = d;
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Fills in the divisor form for a range axes_are_flat turned down, so that the
|
|
120
|
+
// kernel spends one division on it rather than walking every dimension.
|
|
121
|
+
template <typename TIarray>
|
|
122
|
+
static inline int64_t reduce_addr_div(bool flat, const TIarray& iarray, const cumo_na_indexer_t& indexer, int begin, int end, ssize_t* step) {
|
|
123
|
+
ssize_t bcast_step;
|
|
124
|
+
int64_t div;
|
|
125
|
+
|
|
126
|
+
// *step stays as the caller left it unless there is a divisor to go with
|
|
127
|
+
// it, so that the two are only ever read together.
|
|
128
|
+
if (flat || !axes_are_flat_bcast(iarray, indexer, begin, end, &bcast_step, &div) || div <= 1) {
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
*step = bcast_step;
|
|
132
|
+
return div;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The innermost step of each of the two axis groups. out_inner is decided from
|
|
136
|
+
// these, and a zip decides again from both operands', so they are handed back
|
|
137
|
+
// rather than kept in cumo_reduce_addr_t: that one is a kernel parameter, and
|
|
138
|
+
// the note above says what a wider one costs.
|
|
139
|
+
typedef struct {
|
|
140
|
+
ssize_t out;
|
|
141
|
+
ssize_t reduce;
|
|
142
|
+
} cumo_inner_steps_t;
|
|
143
|
+
|
|
144
|
+
// The out axis runs along memory when its step is real and shorter than the
|
|
145
|
+
// reduce axis's, which is what decides how a block shares its threads.
|
|
146
|
+
static inline bool inner_steps_say_out(const cumo_inner_steps_t& inner) {
|
|
147
|
+
return inner.out != 0 &&
|
|
148
|
+
(inner.reduce == 0 || step_magnitude(inner.out) < step_magnitude(inner.reduce));
|
|
149
|
+
}
|
|
150
|
+
|
|
96
151
|
template <typename TArg>
|
|
97
|
-
static inline cumo_reduce_addr_t make_reduce_addr(const TArg& arg, int64_t reduce_total_size) {
|
|
152
|
+
static inline cumo_reduce_addr_t make_reduce_addr(const TArg& arg, int64_t reduce_total_size, cumo_inner_steps_t* inner = 0) {
|
|
98
153
|
cumo_reduce_addr_t ad;
|
|
99
154
|
int in_ndim = arg.in_indexer.ndim;
|
|
100
155
|
ssize_t whole_step;
|
|
@@ -108,6 +163,8 @@ static inline cumo_reduce_addr_t make_reduce_addr(const TArg& arg, int64_t reduc
|
|
|
108
163
|
ad.in_reduce_flat = true;
|
|
109
164
|
ad.in_reduce_step = whole_step;
|
|
110
165
|
ad.in_out_step = whole_step * reduce_total_size;
|
|
166
|
+
ad.in_out_div = 0;
|
|
167
|
+
ad.in_reduce_div = 0;
|
|
111
168
|
} else {
|
|
112
169
|
int split = in_ndim;
|
|
113
170
|
int64_t acc = 1;
|
|
@@ -119,33 +176,74 @@ static inline cumo_reduce_addr_t make_reduce_addr(const TArg& arg, int64_t reduc
|
|
|
119
176
|
ad.split = split;
|
|
120
177
|
ad.in_reduce_flat = axes_are_flat(arg.in, arg.in_indexer, split, in_ndim, &ad.in_reduce_step);
|
|
121
178
|
ad.in_out_flat = axes_are_flat(arg.in, arg.in_indexer, 0, split, &ad.in_out_step);
|
|
179
|
+
ad.in_reduce_div = reduce_addr_div(ad.in_reduce_flat, arg.in, arg.in_indexer, split, in_ndim, &ad.in_reduce_step);
|
|
180
|
+
ad.in_out_div = reduce_addr_div(ad.in_out_flat, arg.in, arg.in_indexer, 0, split, &ad.in_out_step);
|
|
122
181
|
} else {
|
|
123
182
|
ad.split = -1;
|
|
124
183
|
ad.in_reduce_flat = false;
|
|
125
184
|
ad.in_out_flat = false;
|
|
126
185
|
ad.in_reduce_step = 0;
|
|
127
186
|
ad.in_out_step = 0;
|
|
187
|
+
ad.in_out_div = 0;
|
|
188
|
+
ad.in_reduce_div = 0;
|
|
189
|
+
}
|
|
190
|
+
// axes_are_flat leaves the step alone where it answers false, and the
|
|
191
|
+
// kernels work one out unconditionally, so give them a zero to read.
|
|
192
|
+
if (!ad.in_reduce_flat && ad.in_reduce_div == 0) {
|
|
193
|
+
ad.in_reduce_step = 0;
|
|
194
|
+
}
|
|
195
|
+
if (!ad.in_out_flat && ad.in_out_div == 0) {
|
|
196
|
+
ad.in_out_step = 0;
|
|
128
197
|
}
|
|
129
198
|
}
|
|
130
199
|
|
|
200
|
+
ad.out_step = 0;
|
|
131
201
|
ad.out_flat = axes_are_flat(arg.out, arg.out_indexer, 0, arg.out_indexer.ndim, &ad.out_step);
|
|
132
202
|
ad.out2_flat = true;
|
|
133
203
|
ad.out2_step = 0;
|
|
134
204
|
|
|
135
|
-
|
|
205
|
+
cumo_inner_steps_t steps;
|
|
136
206
|
if (ad.in_out_flat && ad.in_reduce_flat) {
|
|
137
|
-
|
|
138
|
-
|
|
207
|
+
steps.out = ad.in_out_step;
|
|
208
|
+
steps.reduce = ad.in_reduce_step;
|
|
139
209
|
} else {
|
|
140
|
-
|
|
141
|
-
|
|
210
|
+
steps.out = ad.split > 0 ? arg.in.step[ad.split - 1] : 0;
|
|
211
|
+
steps.reduce = (ad.split >= 0 && ad.split < in_ndim) ? arg.in.step[in_ndim - 1] : 0;
|
|
212
|
+
}
|
|
213
|
+
ad.out_inner = inner_steps_say_out(steps);
|
|
214
|
+
if (inner != 0) {
|
|
215
|
+
*inner = steps;
|
|
142
216
|
}
|
|
143
|
-
ad.out_inner = out_inner_step != 0 &&
|
|
144
|
-
(reduce_inner_step == 0 || step_magnitude(out_inner_step) < step_magnitude(reduce_inner_step));
|
|
145
217
|
|
|
146
218
|
return ad;
|
|
147
219
|
}
|
|
148
220
|
|
|
221
|
+
// The shorter of two steps, counting a zero as no step at all: an operand that
|
|
222
|
+
// does not move along an axis reads one address for the whole of it, so it has
|
|
223
|
+
// no say in which axis runs along memory.
|
|
224
|
+
static inline ssize_t shorter_step(ssize_t a, ssize_t b) {
|
|
225
|
+
if (a == 0) return b;
|
|
226
|
+
if (b == 0) return a;
|
|
227
|
+
return step_magnitude(a) < step_magnitude(b) ? a : b;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// A zip reduction reads both operands through one thread layout, so the layout
|
|
231
|
+
// has to answer for both. Taking the shorter step of the two along each axis
|
|
232
|
+
// gives the same answer whichever operand the caller wrote first, which a
|
|
233
|
+
// decision read off one of them does not.
|
|
234
|
+
template <typename TArg>
|
|
235
|
+
static inline void make_zip_reduce_addrs(const TArg& arg, const TArg& arg2, int64_t reduce_total_size,
|
|
236
|
+
cumo_reduce_addr_t* ad, cumo_reduce_addr_t* ad2) {
|
|
237
|
+
cumo_inner_steps_t inner, inner2, both;
|
|
238
|
+
|
|
239
|
+
*ad = make_reduce_addr(arg, reduce_total_size, &inner);
|
|
240
|
+
*ad2 = make_reduce_addr(arg2, reduce_total_size, &inner2);
|
|
241
|
+
|
|
242
|
+
both.out = shorter_step(inner.out, inner2.out);
|
|
243
|
+
both.reduce = shorter_step(inner.reduce, inner2.reduce);
|
|
244
|
+
ad->out_inner = ad2->out_inner = inner_steps_say_out(both);
|
|
245
|
+
}
|
|
246
|
+
|
|
149
247
|
static inline void set_reduce_addr_out2(cumo_reduce_addr_t* ad, const cumo_na_reduction_arg_t& arg, const cumo_na_iarray_t& out2) {
|
|
150
248
|
ad->out2_flat = axes_are_flat(out2, arg.out_indexer, 0, arg.out_indexer.ndim, &ad->out2_step);
|
|
151
249
|
}
|
|
@@ -219,6 +317,7 @@ __device__ static __forceinline__ void axes_offset_pair(const TIarray& a, const
|
|
|
219
317
|
template <bool FLAT>
|
|
220
318
|
__device__ static __forceinline__ ssize_t reduce_in_out_offset(const cumo_na_iarray_t& in, const cumo_na_indexer_t& in_indexer, const cumo_reduce_addr_t& ad, int64_t i_out) {
|
|
221
319
|
if (FLAT || ad.in_out_flat) return i_out * ad.in_out_step;
|
|
320
|
+
if (!FLAT && ad.in_out_div > 0) return (i_out / ad.in_out_div) * ad.in_out_step;
|
|
222
321
|
if (ad.split < 0) return 0;
|
|
223
322
|
return axes_offset(in, in_indexer, 0, ad.split, i_out);
|
|
224
323
|
}
|
|
@@ -226,7 +325,8 @@ __device__ static __forceinline__ ssize_t reduce_in_out_offset(const cumo_na_iar
|
|
|
226
325
|
// reduce_in_out_offset for the two operands of a zip reduction at once.
|
|
227
326
|
template <bool FLAT>
|
|
228
327
|
__device__ static __forceinline__ void reduce_in_out_offset_pair(const cumo_na_iarray_t& in, const cumo_na_iarray_t& in2, const cumo_na_indexer_t& in_indexer, const cumo_reduce_addr_t& ad, const cumo_reduce_addr_t& ad2, int64_t i_out, ssize_t* off, ssize_t* off2) {
|
|
229
|
-
if (!FLAT && !ad.in_out_flat && !ad2.in_out_flat && ad.
|
|
328
|
+
if (!FLAT && !ad.in_out_flat && !ad2.in_out_flat && ad.in_out_div == 0 && ad2.in_out_div == 0 &&
|
|
329
|
+
ad.split >= 0 && ad.split == ad2.split) {
|
|
230
330
|
axes_offset_pair(in, in2, in_indexer, 0, ad.split, i_out, off, off2);
|
|
231
331
|
return;
|
|
232
332
|
}
|
|
@@ -237,6 +337,7 @@ __device__ static __forceinline__ void reduce_in_out_offset_pair(const cumo_na_i
|
|
|
237
337
|
template <bool FLAT>
|
|
238
338
|
__device__ static __forceinline__ ssize_t reduce_in_offset(const cumo_na_iarray_t& in, const cumo_na_indexer_t& in_indexer, const cumo_reduce_addr_t& ad, ssize_t in_out_off, int64_t i_reduce, int64_t i_in) {
|
|
239
339
|
if (FLAT || ad.in_reduce_flat) return in_out_off + i_reduce * ad.in_reduce_step;
|
|
340
|
+
if (!FLAT && ad.in_reduce_div > 0) return in_out_off + (i_reduce / ad.in_reduce_div) * ad.in_reduce_step;
|
|
240
341
|
if (ad.split < 0) return axes_offset(in, in_indexer, 0, in_indexer.ndim, i_in);
|
|
241
342
|
return in_out_off + axes_offset(in, in_indexer, ad.split, in_indexer.ndim, i_reduce);
|
|
242
343
|
}
|
|
@@ -340,7 +441,7 @@ __device__ static __forceinline__ auto reduce_axis(const cumo_na_iarray_t& in, c
|
|
|
340
441
|
// once, which is what mulsum wants: the product it accumulates never exists as
|
|
341
442
|
// an array. The pair comes out of one broadcast, so arg.in_indexer addresses
|
|
342
443
|
// both and only the steps differ, which is what in2 and ad2 carry.
|
|
343
|
-
template <bool FLAT, typename TypeIn, typename ReductionImpl>
|
|
444
|
+
template <bool FLAT, typename TypeIn, typename TypeIn2, typename ReductionImpl>
|
|
344
445
|
__device__ static __forceinline__ auto reduce_axis_zip(const cumo_na_reduction_arg_t& arg, const cumo_na_iarray_t& in2,
|
|
345
446
|
const cumo_reduce_addr_t& ad, const cumo_reduce_addr_t& ad2, ReductionImpl& impl,
|
|
346
447
|
ssize_t in_out_off, ssize_t in_out_off2, int64_t i_in, int64_t begin, int64_t end,
|
|
@@ -356,7 +457,7 @@ __device__ static __forceinline__ auto reduce_axis_zip(const cumo_na_reduction_a
|
|
|
356
457
|
TypeReduce accum = impl.Identity(0);
|
|
357
458
|
|
|
358
459
|
for (; i_reduce < end; i_reduce += reduce_block_size, i_in += reduce_block_size) {
|
|
359
|
-
impl.Reduce(impl.MapIn(*reinterpret_cast<TypeIn*>(p), *reinterpret_cast<
|
|
460
|
+
impl.Reduce(impl.MapIn(*reinterpret_cast<TypeIn*>(p), *reinterpret_cast<TypeIn2*>(q), i_reduce), accum);
|
|
360
461
|
p = (FLAT || ad.in_reduce_flat)
|
|
361
462
|
? p + advance
|
|
362
463
|
: arg.in.ptr + reduce_in_offset<FLAT>(arg.in, arg.in_indexer, ad, in_out_off, i_reduce + reduce_block_size, i_in + reduce_block_size);
|
|
@@ -402,7 +503,7 @@ __global__ static void reduction_kernel(CUMO_GRID_CONSTANT cumo_na_reduction_arg
|
|
|
402
503
|
|
|
403
504
|
// Variant of reduction_kernel reading two inputs, for mulsum. See
|
|
404
505
|
// reduce_axis_zip above.
|
|
405
|
-
template <bool FLAT, typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
506
|
+
template <bool FLAT, typename TypeIn, typename TypeIn2, typename TypeOut, typename ReductionImpl>
|
|
406
507
|
__global__ static void reduction_zip_kernel(CUMO_GRID_CONSTANT cumo_na_reduction_arg_t arg, CUMO_GRID_CONSTANT cumo_na_iarray_t in2, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad2, int out_block_size, int reduce_block_size, ReductionImpl impl) {
|
|
407
508
|
using TypeReduce = decltype(impl.Identity(0));
|
|
408
509
|
|
|
@@ -423,7 +524,7 @@ __global__ static void reduction_zip_kernel(CUMO_GRID_CONSTANT cumo_na_reduction
|
|
|
423
524
|
reduce_in_out_offset_pair<FLAT>(arg.in, in2, arg.in_indexer, ad, ad2, i_out, &in_out_off, &in_out_off2);
|
|
424
525
|
int64_t i_in = i_out * reduce_total_size + reduce_offset;
|
|
425
526
|
|
|
426
|
-
TypeReduce accum = reduce_axis_zip<FLAT,TypeIn>(arg, in2, ad, ad2, impl, in_out_off, in_out_off2, i_in, 0, reduce_total_size, reduce_offset, reduce_block_size);
|
|
527
|
+
TypeReduce accum = reduce_axis_zip<FLAT,TypeIn,TypeIn2>(arg, in2, ad, ad2, impl, in_out_off, in_out_off2, i_in, 0, reduce_total_size, reduce_offset, reduce_block_size);
|
|
427
528
|
|
|
428
529
|
accum = reduce_in_block(accum, sdata, tid, out_block_size, reduce_block_size, !ad.out_inner, impl);
|
|
429
530
|
if (reduce_offset == 0) {
|
|
@@ -433,6 +534,89 @@ __global__ static void reduction_zip_kernel(CUMO_GRID_CONSTANT cumo_na_reduction
|
|
|
433
534
|
}
|
|
434
535
|
}
|
|
435
536
|
|
|
537
|
+
// The reduce axis of a zip whose operands both address without the indexer.
|
|
538
|
+
// Splitting this out of reduce_axis_zip is what buys the speed: the general
|
|
539
|
+
// path is gone from the instantiation, so the indexer, which carries shape[]
|
|
540
|
+
// for CUMO_NA_MAX_DIMENSION, never has to be live.
|
|
541
|
+
template <typename TypeIn, typename TypeIn2, typename ReductionImpl>
|
|
542
|
+
__device__ static __forceinline__ auto reduce_axis_zip_nodim(const cumo_na_reduction_arg_t& arg, const cumo_na_iarray_t& in2,
|
|
543
|
+
const cumo_reduce_addr_t& ad, const cumo_reduce_addr_t& ad2, ReductionImpl& impl,
|
|
544
|
+
ssize_t in_out_off, ssize_t in_out_off2, int64_t begin, int64_t end,
|
|
545
|
+
int64_t reduce_offset, int64_t reduce_block_size) -> decltype(impl.Identity(0)) {
|
|
546
|
+
using TypeReduce = decltype(impl.Identity(0));
|
|
547
|
+
|
|
548
|
+
int64_t i_reduce = begin + reduce_offset;
|
|
549
|
+
char* p = arg.in.ptr + in_out_off + i_reduce * ad.in_reduce_step;
|
|
550
|
+
ssize_t advance = ad.in_reduce_step * reduce_block_size;
|
|
551
|
+
|
|
552
|
+
TypeReduce accum = impl.Identity(0);
|
|
553
|
+
|
|
554
|
+
// The two loops keep the divisor out of the body. One loop with a divisor
|
|
555
|
+
// of 1 for the flat case costs a 64-bit division on every element, which
|
|
556
|
+
// is more than the addressing it saves.
|
|
557
|
+
if (ad2.in_reduce_flat) {
|
|
558
|
+
char* q = in2.ptr + in_out_off2 + i_reduce * ad2.in_reduce_step;
|
|
559
|
+
ssize_t advance2 = ad2.in_reduce_step * reduce_block_size;
|
|
560
|
+
|
|
561
|
+
for (; i_reduce < end; i_reduce += reduce_block_size, p += advance, q += advance2) {
|
|
562
|
+
impl.Reduce(impl.MapIn(*reinterpret_cast<TypeIn*>(p), *reinterpret_cast<TypeIn2*>(q), i_reduce), accum);
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
int64_t div2 = ad2.in_reduce_div;
|
|
566
|
+
|
|
567
|
+
for (; i_reduce < end; i_reduce += reduce_block_size, p += advance) {
|
|
568
|
+
char* q = in2.ptr + in_out_off2 + (i_reduce / div2) * ad2.in_reduce_step;
|
|
569
|
+
impl.Reduce(impl.MapIn(*reinterpret_cast<TypeIn*>(p), *reinterpret_cast<TypeIn2*>(q), i_reduce), accum);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return accum;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// reduction_zip_kernel for the same case.
|
|
576
|
+
template <typename TypeIn, typename TypeIn2, typename TypeOut, typename ReductionImpl>
|
|
577
|
+
__global__ static void reduction_zip_nodim_kernel(CUMO_GRID_CONSTANT cumo_na_reduction_arg_t arg, CUMO_GRID_CONSTANT cumo_na_iarray_t in2, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad2, int out_block_size, int reduce_block_size, ReductionImpl impl) {
|
|
578
|
+
using TypeReduce = decltype(impl.Identity(0));
|
|
579
|
+
|
|
580
|
+
extern __shared__ __align__(8) char sdata_raw[];
|
|
581
|
+
TypeReduce* sdata = reinterpret_cast<TypeReduce*>(sdata_raw);
|
|
582
|
+
unsigned int tid = threadIdx.x;
|
|
583
|
+
|
|
584
|
+
int64_t out_total_size = arg.out_indexer.total_size;
|
|
585
|
+
int64_t reduce_total_size = arg.in_indexer.total_size / out_total_size;
|
|
586
|
+
int64_t out_div2 = ad2.in_out_flat ? 1 : ad2.in_out_div;
|
|
587
|
+
|
|
588
|
+
int64_t reduce_offset, out_offset;
|
|
589
|
+
reduce_thread_split(ad, tid, out_block_size, reduce_block_size, &reduce_offset, &out_offset);
|
|
590
|
+
int64_t out_base = blockIdx.x * out_block_size;
|
|
591
|
+
int64_t out_stride = gridDim.x * out_block_size;
|
|
592
|
+
|
|
593
|
+
for (int64_t i_out = out_base + out_offset; i_out < out_total_size; i_out += out_stride) {
|
|
594
|
+
ssize_t in_out_off = i_out * ad.in_out_step;
|
|
595
|
+
ssize_t in_out_off2 = (i_out / out_div2) * ad2.in_out_step;
|
|
596
|
+
|
|
597
|
+
TypeReduce accum = reduce_axis_zip_nodim<TypeIn,TypeIn2>(arg, in2, ad, ad2, impl, in_out_off, in_out_off2, 0, reduce_total_size, reduce_offset, reduce_block_size);
|
|
598
|
+
|
|
599
|
+
accum = reduce_in_block(accum, sdata, tid, out_block_size, reduce_block_size, !ad.out_inner, impl);
|
|
600
|
+
if (reduce_offset == 0) {
|
|
601
|
+
TypeOut* out_ptr = reinterpret_cast<TypeOut*>(arg.out.ptr + i_out * ad.out_step);
|
|
602
|
+
*out_ptr = impl.MapOut(accum);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Whether both operands of a zip address without the indexer: one is flat, the
|
|
608
|
+
// other flat or flat once its broadcast axes are divided out.
|
|
609
|
+
//
|
|
610
|
+
// Only the second operand may carry a divisor. The first is the receiver, and
|
|
611
|
+
// a broadcast one reaches this as the argument: a.mulsum(b) with b the smaller
|
|
612
|
+
// shape. Writing it the other way round leaves the general path, which answers
|
|
613
|
+
// the same and takes the time the kernel below saves.
|
|
614
|
+
static inline bool zip_axes_need_no_dim(const cumo_reduce_addr_t& ad, const cumo_reduce_addr_t& ad2) {
|
|
615
|
+
return ad.in_out_flat && ad.in_reduce_flat && ad.out_flat &&
|
|
616
|
+
(ad2.in_out_flat || ad2.in_out_div > 0) &&
|
|
617
|
+
(ad2.in_reduce_flat || ad2.in_reduce_div > 0);
|
|
618
|
+
}
|
|
619
|
+
|
|
436
620
|
// Variant of reduction_kernel for arg-reductions (argmax/argmin), which report
|
|
437
621
|
// the index along the reduction axis rather than the index of an element.
|
|
438
622
|
template <bool FLAT, typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
@@ -539,8 +723,45 @@ __global__ static void reduction_partial_kernel(CUMO_GRID_CONSTANT cumo_na_reduc
|
|
|
539
723
|
}
|
|
540
724
|
}
|
|
541
725
|
|
|
726
|
+
// reduction_zip_partial_kernel for operands that address without the indexer.
|
|
727
|
+
// A split reduction is what a small output over a long reduce axis takes, so
|
|
728
|
+
// leaving this one on the general path would miss the shape that gains most.
|
|
729
|
+
template <typename TypeIn, typename TypeIn2, typename TypeReduce, typename ReductionImpl>
|
|
730
|
+
__global__ static void reduction_zip_nodim_partial_kernel(CUMO_GRID_CONSTANT cumo_na_reduction_arg_t arg, CUMO_GRID_CONSTANT cumo_na_iarray_t in2, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad2, TypeReduce* partial, int64_t n_split, int64_t chunk, int out_block_size, int reduce_block_size, ReductionImpl impl) {
|
|
731
|
+
extern __shared__ __align__(8) char sdata_raw[];
|
|
732
|
+
TypeReduce* sdata = reinterpret_cast<TypeReduce*>(sdata_raw);
|
|
733
|
+
unsigned int tid = threadIdx.x;
|
|
734
|
+
|
|
735
|
+
int64_t out_total_size = arg.out_indexer.total_size;
|
|
736
|
+
int64_t reduce_total_size = arg.in_indexer.total_size / out_total_size;
|
|
737
|
+
int64_t partial_total_size = out_total_size * n_split;
|
|
738
|
+
int64_t out_div2 = ad2.in_out_flat ? 1 : ad2.in_out_div;
|
|
739
|
+
|
|
740
|
+
int64_t reduce_offset, out_offset;
|
|
741
|
+
reduce_thread_split(ad, tid, out_block_size, reduce_block_size, &reduce_offset, &out_offset);
|
|
742
|
+
int64_t out_base = blockIdx.x * out_block_size;
|
|
743
|
+
int64_t out_stride = gridDim.x * out_block_size;
|
|
744
|
+
|
|
745
|
+
for (int64_t i = out_base + out_offset; i < partial_total_size; i += out_stride) {
|
|
746
|
+
int64_t i_out = i % out_total_size;
|
|
747
|
+
int64_t i_split = i / out_total_size;
|
|
748
|
+
int64_t begin = i_split * chunk;
|
|
749
|
+
int64_t end = begin + chunk;
|
|
750
|
+
if (end > reduce_total_size) end = reduce_total_size;
|
|
751
|
+
ssize_t in_out_off = i_out * ad.in_out_step;
|
|
752
|
+
ssize_t in_out_off2 = (i_out / out_div2) * ad2.in_out_step;
|
|
753
|
+
|
|
754
|
+
TypeReduce accum = reduce_axis_zip_nodim<TypeIn,TypeIn2>(arg, in2, ad, ad2, impl, in_out_off, in_out_off2, begin, end, reduce_offset, reduce_block_size);
|
|
755
|
+
|
|
756
|
+
accum = reduce_in_block(accum, sdata, tid, out_block_size, reduce_block_size, !ad.out_inner, impl);
|
|
757
|
+
if (reduce_offset == 0) {
|
|
758
|
+
partial[i_out * n_split + i_split] = accum;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
542
763
|
// First pass of a split zip reduction. See reduction_partial_kernel above.
|
|
543
|
-
template <bool FLAT, typename TypeIn, typename TypeReduce, typename ReductionImpl>
|
|
764
|
+
template <bool FLAT, typename TypeIn, typename TypeIn2, typename TypeReduce, typename ReductionImpl>
|
|
544
765
|
__global__ static void reduction_zip_partial_kernel(CUMO_GRID_CONSTANT cumo_na_reduction_arg_t arg, CUMO_GRID_CONSTANT cumo_na_iarray_t in2, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad, CUMO_GRID_CONSTANT cumo_reduce_addr_t ad2, TypeReduce* partial, int64_t n_split, int64_t chunk, int out_block_size, int reduce_block_size, ReductionImpl impl) {
|
|
545
766
|
extern __shared__ __align__(8) char sdata_raw[];
|
|
546
767
|
TypeReduce* sdata = reinterpret_cast<TypeReduce*>(sdata_raw);
|
|
@@ -565,7 +786,7 @@ __global__ static void reduction_zip_partial_kernel(CUMO_GRID_CONSTANT cumo_na_r
|
|
|
565
786
|
reduce_in_out_offset_pair<FLAT>(arg.in, in2, arg.in_indexer, ad, ad2, i_out, &in_out_off, &in_out_off2);
|
|
566
787
|
int64_t i_in = i_out * reduce_total_size + begin + reduce_offset;
|
|
567
788
|
|
|
568
|
-
TypeReduce accum = reduce_axis_zip<FLAT,TypeIn>(arg, in2, ad, ad2, impl, in_out_off, in_out_off2, i_in, begin, end, reduce_offset, reduce_block_size);
|
|
789
|
+
TypeReduce accum = reduce_axis_zip<FLAT,TypeIn,TypeIn2>(arg, in2, ad, ad2, impl, in_out_off, in_out_off2, i_in, begin, end, reduce_offset, reduce_block_size);
|
|
569
790
|
|
|
570
791
|
accum = reduce_in_block(accum, sdata, tid, out_block_size, reduce_block_size, !ad.out_inner, impl);
|
|
571
792
|
if (reduce_offset == 0) {
|
|
@@ -602,7 +823,7 @@ struct reduce_combine {
|
|
|
602
823
|
// the partials so the caller can combine them with its own second pass. The
|
|
603
824
|
// caller frees the returned buffer.
|
|
604
825
|
template <typename TypeIn, typename TypeReduce, typename ReductionImpl, bool ARG = false>
|
|
605
|
-
TypeReduce* reduce_partial_pass(cumo_na_reduction_arg_t arg, cumo_reduce_addr_t ad, int64_t n_split, int64_t reduce_total_size, cumo_na_reduction_arg_t* arg2, ReductionImpl& impl) {
|
|
826
|
+
TypeReduce* reduce_partial_pass(cumo_na_reduction_arg_t arg, cumo_reduce_addr_t ad, int64_t n_split, int64_t reduce_total_size, cumo_na_reduction_arg_t* arg2, ReductionImpl& impl, char* held = 0) {
|
|
606
827
|
int64_t chunk = (reduce_total_size + n_split - 1) / n_split;
|
|
607
828
|
int64_t partial_total_size = arg.out_indexer.total_size * n_split;
|
|
608
829
|
TypeReduce* partial = reinterpret_cast<TypeReduce*>(cumo_cuda_runtime_malloc(sizeof(TypeReduce) * partial_total_size));
|
|
@@ -618,7 +839,7 @@ TypeReduce* reduce_partial_pass(cumo_na_reduction_arg_t arg, cumo_reduce_addr_t
|
|
|
618
839
|
} else {
|
|
619
840
|
reduction_partial_kernel<false,ARG,TypeIn,TypeReduce,ReductionImpl><<<grid_size, max_block_size, shared_mem_size>>>(arg, ad, partial, n_split, chunk, out_block_size, reduce_block_size, impl);
|
|
620
841
|
}
|
|
621
|
-
|
|
842
|
+
cumo_check_launch_holding(partial, held);
|
|
622
843
|
|
|
623
844
|
arg2->in.ptr = reinterpret_cast<char*>(partial);
|
|
624
845
|
arg2->in.step[0] = sizeof(TypeReduce);
|
|
@@ -635,8 +856,8 @@ static inline bool zip_axes_are_flat(const cumo_reduce_addr_t& ad, const cumo_re
|
|
|
635
856
|
}
|
|
636
857
|
|
|
637
858
|
// First pass of a split zip reduction. See reduce_partial_pass above.
|
|
638
|
-
template <typename TypeIn, typename TypeReduce, typename ReductionImpl>
|
|
639
|
-
TypeReduce* reduce_zip_partial_pass(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, cumo_reduce_addr_t ad, cumo_reduce_addr_t ad2, int64_t n_split, int64_t reduce_total_size, cumo_na_reduction_arg_t* arg2, ReductionImpl& impl) {
|
|
859
|
+
template <typename TypeIn, typename TypeIn2, typename TypeReduce, typename ReductionImpl>
|
|
860
|
+
TypeReduce* reduce_zip_partial_pass(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, cumo_reduce_addr_t ad, cumo_reduce_addr_t ad2, int64_t n_split, int64_t reduce_total_size, cumo_na_reduction_arg_t* arg2, ReductionImpl& impl, char* held = 0) {
|
|
640
861
|
int64_t chunk = (reduce_total_size + n_split - 1) / n_split;
|
|
641
862
|
int64_t partial_total_size = arg.out_indexer.total_size * n_split;
|
|
642
863
|
TypeReduce* partial = reinterpret_cast<TypeReduce*>(cumo_cuda_runtime_malloc(sizeof(TypeReduce) * partial_total_size));
|
|
@@ -648,11 +869,13 @@ TypeReduce* reduce_zip_partial_pass(cumo_na_reduction_arg_t arg, cumo_na_iarray_
|
|
|
648
869
|
int64_t shared_mem_size = sizeof(TypeReduce) * max_block_size;
|
|
649
870
|
|
|
650
871
|
if (zip_axes_are_flat(ad, ad2)) {
|
|
651
|
-
reduction_zip_partial_kernel<true,TypeIn,TypeReduce,ReductionImpl><<<grid_size, max_block_size, shared_mem_size>>>(arg, in2, ad, ad2, partial, n_split, chunk, out_block_size, reduce_block_size, impl);
|
|
872
|
+
reduction_zip_partial_kernel<true,TypeIn,TypeIn2,TypeReduce,ReductionImpl><<<grid_size, max_block_size, shared_mem_size>>>(arg, in2, ad, ad2, partial, n_split, chunk, out_block_size, reduce_block_size, impl);
|
|
873
|
+
} else if (zip_axes_need_no_dim(ad, ad2)) {
|
|
874
|
+
reduction_zip_nodim_partial_kernel<TypeIn,TypeIn2,TypeReduce,ReductionImpl><<<grid_size, max_block_size, shared_mem_size>>>(arg, in2, ad, ad2, partial, n_split, chunk, out_block_size, reduce_block_size, impl);
|
|
652
875
|
} else {
|
|
653
|
-
reduction_zip_partial_kernel<false,TypeIn,TypeReduce,ReductionImpl><<<grid_size, max_block_size, shared_mem_size>>>(arg, in2, ad, ad2, partial, n_split, chunk, out_block_size, reduce_block_size, impl);
|
|
876
|
+
reduction_zip_partial_kernel<false,TypeIn,TypeIn2,TypeReduce,ReductionImpl><<<grid_size, max_block_size, shared_mem_size>>>(arg, in2, ad, ad2, partial, n_split, chunk, out_block_size, reduce_block_size, impl);
|
|
654
877
|
}
|
|
655
|
-
|
|
878
|
+
cumo_check_launch_holding(partial, held);
|
|
656
879
|
|
|
657
880
|
arg2->in.ptr = reinterpret_cast<char*>(partial);
|
|
658
881
|
arg2->in.step[0] = sizeof(TypeReduce);
|
|
@@ -664,8 +887,12 @@ TypeReduce* reduce_zip_partial_pass(cumo_na_reduction_arg_t arg, cumo_na_iarray_
|
|
|
664
887
|
|
|
665
888
|
} // cumo_detail
|
|
666
889
|
|
|
890
|
+
// held0 and held1 are every scratch buffer still outstanding, the caller's
|
|
891
|
+
// included. The checks free them before they raise, since rb_raise is a longjmp
|
|
892
|
+
// and nothing written after it runs. The split forms pass their own partial as
|
|
893
|
+
// well as whatever they were handed.
|
|
667
894
|
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
668
|
-
void cumo_reduce(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
895
|
+
void cumo_reduce(cumo_na_reduction_arg_t arg, ReductionImpl&& impl, char* held0 = 0, char* held1 = 0) {
|
|
669
896
|
if (arg.out_indexer.total_size == 0) {
|
|
670
897
|
return;
|
|
671
898
|
}
|
|
@@ -686,7 +913,7 @@ void cumo_reduce(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
|
686
913
|
} else {
|
|
687
914
|
cumo_detail::reduction_kernel<false,TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, ad, out_block_size, reduce_block_size, impl);
|
|
688
915
|
}
|
|
689
|
-
|
|
916
|
+
cumo_check_launch_holding(held0, held1);
|
|
690
917
|
}
|
|
691
918
|
|
|
692
919
|
// Runs the reduce axis of one output across several blocks and combines their
|
|
@@ -695,7 +922,7 @@ void cumo_reduce(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
|
695
922
|
// case. Only for an impl whose Identity ignores its index argument — see
|
|
696
923
|
// reduce_combine above.
|
|
697
924
|
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
698
|
-
void cumo_reduce_split(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
925
|
+
void cumo_reduce_split(cumo_na_reduction_arg_t arg, ReductionImpl&& impl, char* held = 0) {
|
|
699
926
|
using TypeReduce = decltype(impl.Identity(0));
|
|
700
927
|
|
|
701
928
|
if (arg.out_indexer.total_size == 0) {
|
|
@@ -711,20 +938,20 @@ void cumo_reduce_split(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
|
711
938
|
|
|
712
939
|
int64_t n_split = cumo_detail::reduce_split_count(reduce_total_size, out_block_num);
|
|
713
940
|
if (n_split < 2) {
|
|
714
|
-
cumo_reduce<TypeIn, TypeOut, ReductionImpl>(arg, std::forward<ReductionImpl>(impl));
|
|
941
|
+
cumo_reduce<TypeIn, TypeOut, ReductionImpl>(arg, std::forward<ReductionImpl>(impl), held);
|
|
715
942
|
return;
|
|
716
943
|
}
|
|
717
944
|
|
|
718
945
|
cumo_na_reduction_arg_t arg2 = arg;
|
|
719
|
-
TypeReduce* partial = cumo_detail::reduce_partial_pass<TypeIn, TypeReduce, ReductionImpl>(arg, ad, n_split, reduce_total_size, &arg2, impl);
|
|
720
|
-
cumo_reduce<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(arg2, cumo_detail::reduce_combine<ReductionImpl>{impl});
|
|
946
|
+
TypeReduce* partial = cumo_detail::reduce_partial_pass<TypeIn, TypeReduce, ReductionImpl>(arg, ad, n_split, reduce_total_size, &arg2, impl, held);
|
|
947
|
+
cumo_reduce<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(arg2, cumo_detail::reduce_combine<ReductionImpl>{impl}, reinterpret_cast<char*>(partial), held);
|
|
721
948
|
cumo_cuda_runtime_free(reinterpret_cast<char*>(partial));
|
|
722
949
|
}
|
|
723
950
|
|
|
724
951
|
// Variant of cumo_reduce reading two inputs, for mulsum. in2 describes the same
|
|
725
952
|
// shape as arg.in, since the one in_indexer addresses both.
|
|
726
|
-
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
727
|
-
void cumo_reduce_zip(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, ReductionImpl&& impl) {
|
|
953
|
+
template <typename TypeIn, typename TypeIn2, typename TypeOut, typename ReductionImpl>
|
|
954
|
+
void cumo_reduce_zip(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, ReductionImpl&& impl, char* held0 = 0, char* held1 = 0) {
|
|
728
955
|
if (arg.out_indexer.total_size == 0) {
|
|
729
956
|
return;
|
|
730
957
|
}
|
|
@@ -732,8 +959,8 @@ void cumo_reduce_zip(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, Reductio
|
|
|
732
959
|
int64_t reduce_total_size = arg.in_indexer.total_size / arg.out_indexer.total_size;
|
|
733
960
|
cumo_na_reduction_arg_t arg2 = arg;
|
|
734
961
|
arg2.in = in2;
|
|
735
|
-
cumo_detail::cumo_reduce_addr_t ad
|
|
736
|
-
cumo_detail::
|
|
962
|
+
cumo_detail::cumo_reduce_addr_t ad, ad2;
|
|
963
|
+
cumo_detail::make_zip_reduce_addrs(arg, arg2, reduce_total_size, &ad, &ad2);
|
|
737
964
|
|
|
738
965
|
int64_t out_block_size, reduce_block_size;
|
|
739
966
|
cumo_detail::reduce_block_split(ad, reduce_total_size, &out_block_size, &reduce_block_size);
|
|
@@ -744,17 +971,19 @@ void cumo_reduce_zip(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, Reductio
|
|
|
744
971
|
int64_t shared_mem_size = sizeof(decltype(impl.Identity(0))) * block_size;
|
|
745
972
|
|
|
746
973
|
if (cumo_detail::zip_axes_are_flat(ad, ad2) && ad.out_flat) {
|
|
747
|
-
cumo_detail::reduction_zip_kernel<true,TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, in2, ad, ad2, out_block_size, reduce_block_size, impl);
|
|
974
|
+
cumo_detail::reduction_zip_kernel<true,TypeIn,TypeIn2,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, in2, ad, ad2, out_block_size, reduce_block_size, impl);
|
|
975
|
+
} else if (cumo_detail::zip_axes_need_no_dim(ad, ad2)) {
|
|
976
|
+
cumo_detail::reduction_zip_nodim_kernel<TypeIn,TypeIn2,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, in2, ad, ad2, out_block_size, reduce_block_size, impl);
|
|
748
977
|
} else {
|
|
749
|
-
cumo_detail::reduction_zip_kernel<false,TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, in2, ad, ad2, out_block_size, reduce_block_size, impl);
|
|
978
|
+
cumo_detail::reduction_zip_kernel<false,TypeIn,TypeIn2,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, in2, ad, ad2, out_block_size, reduce_block_size, impl);
|
|
750
979
|
}
|
|
751
|
-
|
|
980
|
+
cumo_check_launch_holding(held0, held1);
|
|
752
981
|
}
|
|
753
982
|
|
|
754
983
|
// cumo_reduce_split for a zip reduction. The first pass reads both operands and
|
|
755
984
|
// the combine pass has only accumulators left, so it is the plain one.
|
|
756
|
-
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
757
|
-
void cumo_reduce_zip_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, ReductionImpl&& impl) {
|
|
985
|
+
template <typename TypeIn, typename TypeIn2, typename TypeOut, typename ReductionImpl>
|
|
986
|
+
void cumo_reduce_zip_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, ReductionImpl&& impl, char* held = 0) {
|
|
758
987
|
using TypeReduce = decltype(impl.Identity(0));
|
|
759
988
|
|
|
760
989
|
if (arg.out_indexer.total_size == 0) {
|
|
@@ -764,8 +993,8 @@ void cumo_reduce_zip_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, Re
|
|
|
764
993
|
int64_t reduce_total_size = arg.in_indexer.total_size / arg.out_indexer.total_size;
|
|
765
994
|
cumo_na_reduction_arg_t arg2 = arg;
|
|
766
995
|
arg2.in = in2;
|
|
767
|
-
cumo_detail::cumo_reduce_addr_t ad
|
|
768
|
-
cumo_detail::
|
|
996
|
+
cumo_detail::cumo_reduce_addr_t ad, ad2;
|
|
997
|
+
cumo_detail::make_zip_reduce_addrs(arg, arg2, reduce_total_size, &ad, &ad2);
|
|
769
998
|
|
|
770
999
|
int64_t out_block_size, reduce_block_size;
|
|
771
1000
|
cumo_detail::reduce_block_split(ad, reduce_total_size, &out_block_size, &reduce_block_size);
|
|
@@ -773,13 +1002,13 @@ void cumo_reduce_zip_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, Re
|
|
|
773
1002
|
|
|
774
1003
|
int64_t n_split = cumo_detail::reduce_split_count(reduce_total_size, out_block_num);
|
|
775
1004
|
if (n_split < 2) {
|
|
776
|
-
cumo_reduce_zip<TypeIn, TypeOut, ReductionImpl>(arg, in2, std::forward<ReductionImpl>(impl));
|
|
1005
|
+
cumo_reduce_zip<TypeIn, TypeIn2, TypeOut, ReductionImpl>(arg, in2, std::forward<ReductionImpl>(impl), held);
|
|
777
1006
|
return;
|
|
778
1007
|
}
|
|
779
1008
|
|
|
780
1009
|
cumo_na_reduction_arg_t combine = arg;
|
|
781
|
-
TypeReduce* partial = cumo_detail::reduce_zip_partial_pass<TypeIn, TypeReduce, ReductionImpl>(arg, in2, ad, ad2, n_split, reduce_total_size, &combine, impl);
|
|
782
|
-
cumo_reduce<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(combine, cumo_detail::reduce_combine<ReductionImpl>{impl});
|
|
1010
|
+
TypeReduce* partial = cumo_detail::reduce_zip_partial_pass<TypeIn, TypeIn2, TypeReduce, ReductionImpl>(arg, in2, ad, ad2, n_split, reduce_total_size, &combine, impl, held);
|
|
1011
|
+
cumo_reduce<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(combine, cumo_detail::reduce_combine<ReductionImpl>{impl}, reinterpret_cast<char*>(partial), held);
|
|
783
1012
|
cumo_cuda_runtime_free(reinterpret_cast<char*>(partial));
|
|
784
1013
|
}
|
|
785
1014
|
|
|
@@ -787,7 +1016,7 @@ void cumo_reduce_zip_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t in2, Re
|
|
|
787
1016
|
// See reduction_pair_kernel above. out2 has to describe the same shape as
|
|
788
1017
|
// arg.out, since the one out_indexer addresses both.
|
|
789
1018
|
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
790
|
-
void cumo_reduce_pair(cumo_na_reduction_arg_t arg, cumo_na_iarray_t out2, ReductionImpl&& impl) {
|
|
1019
|
+
void cumo_reduce_pair(cumo_na_reduction_arg_t arg, cumo_na_iarray_t out2, ReductionImpl&& impl, char* held0 = 0, char* held1 = 0) {
|
|
791
1020
|
if (arg.out_indexer.total_size == 0) {
|
|
792
1021
|
return;
|
|
793
1022
|
}
|
|
@@ -809,12 +1038,12 @@ void cumo_reduce_pair(cumo_na_reduction_arg_t arg, cumo_na_iarray_t out2, Reduct
|
|
|
809
1038
|
} else {
|
|
810
1039
|
cumo_detail::reduction_pair_kernel<false,TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, out2, ad, out_block_size, reduce_block_size, impl);
|
|
811
1040
|
}
|
|
812
|
-
|
|
1041
|
+
cumo_check_launch_holding(held0, held1);
|
|
813
1042
|
}
|
|
814
1043
|
|
|
815
1044
|
// cumo_reduce_split for the two-output form. Same constraint on Identity.
|
|
816
1045
|
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
817
|
-
void cumo_reduce_pair_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t out2, ReductionImpl&& impl) {
|
|
1046
|
+
void cumo_reduce_pair_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t out2, ReductionImpl&& impl, char* held = 0) {
|
|
818
1047
|
using TypeReduce = decltype(impl.Identity(0));
|
|
819
1048
|
|
|
820
1049
|
if (arg.out_indexer.total_size == 0) {
|
|
@@ -830,20 +1059,20 @@ void cumo_reduce_pair_split(cumo_na_reduction_arg_t arg, cumo_na_iarray_t out2,
|
|
|
830
1059
|
|
|
831
1060
|
int64_t n_split = cumo_detail::reduce_split_count(reduce_total_size, out_block_num);
|
|
832
1061
|
if (n_split < 2) {
|
|
833
|
-
cumo_reduce_pair<TypeIn, TypeOut, ReductionImpl>(arg, out2, std::forward<ReductionImpl>(impl));
|
|
1062
|
+
cumo_reduce_pair<TypeIn, TypeOut, ReductionImpl>(arg, out2, std::forward<ReductionImpl>(impl), held);
|
|
834
1063
|
return;
|
|
835
1064
|
}
|
|
836
1065
|
|
|
837
1066
|
cumo_na_reduction_arg_t arg2 = arg;
|
|
838
|
-
TypeReduce* partial = cumo_detail::reduce_partial_pass<TypeIn, TypeReduce, ReductionImpl>(arg, ad, n_split, reduce_total_size, &arg2, impl);
|
|
839
|
-
cumo_reduce_pair<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(arg2, out2, cumo_detail::reduce_combine<ReductionImpl>{impl});
|
|
1067
|
+
TypeReduce* partial = cumo_detail::reduce_partial_pass<TypeIn, TypeReduce, ReductionImpl>(arg, ad, n_split, reduce_total_size, &arg2, impl, held);
|
|
1068
|
+
cumo_reduce_pair<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(arg2, out2, cumo_detail::reduce_combine<ReductionImpl>{impl}, reinterpret_cast<char*>(partial), held);
|
|
840
1069
|
cumo_cuda_runtime_free(reinterpret_cast<char*>(partial));
|
|
841
1070
|
}
|
|
842
1071
|
|
|
843
1072
|
// Variant of cumo_reduce for arg-reductions (argmax/argmin), which returns
|
|
844
1073
|
// indices along the reduction axis. See reduction_arg_kernel above.
|
|
845
1074
|
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
846
|
-
void cumo_reduce_arg(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
1075
|
+
void cumo_reduce_arg(cumo_na_reduction_arg_t arg, ReductionImpl&& impl, char* held0 = 0, char* held1 = 0) {
|
|
847
1076
|
if (arg.out_indexer.total_size == 0) {
|
|
848
1077
|
return;
|
|
849
1078
|
}
|
|
@@ -864,14 +1093,14 @@ void cumo_reduce_arg(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
|
864
1093
|
} else {
|
|
865
1094
|
cumo_detail::reduction_arg_kernel<false,TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, ad, out_block_size, reduce_block_size, impl);
|
|
866
1095
|
}
|
|
867
|
-
|
|
1096
|
+
cumo_check_launch_holding(held0, held1);
|
|
868
1097
|
}
|
|
869
1098
|
|
|
870
1099
|
// cumo_reduce_split for the arg form. The partials already carry indices along
|
|
871
1100
|
// the reduce axis, so the second pass combines them with the plain kernel.
|
|
872
1101
|
// Only for an impl whose Identity ignores its index argument.
|
|
873
1102
|
template <typename TypeIn, typename TypeOut, typename ReductionImpl>
|
|
874
|
-
void cumo_reduce_arg_split(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
1103
|
+
void cumo_reduce_arg_split(cumo_na_reduction_arg_t arg, ReductionImpl&& impl, char* held = 0) {
|
|
875
1104
|
using TypeReduce = decltype(impl.Identity(0));
|
|
876
1105
|
|
|
877
1106
|
if (arg.out_indexer.total_size == 0) {
|
|
@@ -887,13 +1116,13 @@ void cumo_reduce_arg_split(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
|
|
|
887
1116
|
|
|
888
1117
|
int64_t n_split = cumo_detail::reduce_split_count(reduce_total_size, out_block_num);
|
|
889
1118
|
if (n_split < 2) {
|
|
890
|
-
cumo_reduce_arg<TypeIn, TypeOut, ReductionImpl>(arg, std::forward<ReductionImpl>(impl));
|
|
1119
|
+
cumo_reduce_arg<TypeIn, TypeOut, ReductionImpl>(arg, std::forward<ReductionImpl>(impl), held);
|
|
891
1120
|
return;
|
|
892
1121
|
}
|
|
893
1122
|
|
|
894
1123
|
cumo_na_reduction_arg_t arg2 = arg;
|
|
895
|
-
TypeReduce* partial = cumo_detail::reduce_partial_pass<TypeIn, TypeReduce, ReductionImpl, true>(arg, ad, n_split, reduce_total_size, &arg2, impl);
|
|
896
|
-
cumo_reduce<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(arg2, cumo_detail::reduce_combine<ReductionImpl>{impl});
|
|
1124
|
+
TypeReduce* partial = cumo_detail::reduce_partial_pass<TypeIn, TypeReduce, ReductionImpl, true>(arg, ad, n_split, reduce_total_size, &arg2, impl, held);
|
|
1125
|
+
cumo_reduce<TypeReduce, TypeOut, cumo_detail::reduce_combine<ReductionImpl>>(arg2, cumo_detail::reduce_combine<ReductionImpl>{impl}, reinterpret_cast<char*>(partial), held);
|
|
897
1126
|
cumo_cuda_runtime_free(reinterpret_cast<char*>(partial));
|
|
898
1127
|
}
|
|
899
1128
|
|