cumo 0.6.0 → 0.7.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/CHANGELOG.md +44 -2
- data/README.md +133 -0
- data/bench/cumo_sync_probe.rb +71 -8
- data/ext/cumo/cuda/cublas.c +0 -40
- data/ext/cumo/cuda/cudnn.c +48 -0
- data/ext/cumo/cuda/cudnn_impl.cpp +91 -62
- data/ext/cumo/cuda/runtime.c +3 -4
- data/ext/cumo/cumo.c +34 -0
- data/ext/cumo/extconf.rb +2 -0
- data/ext/cumo/include/cumo/cuda/cudnn.h +21 -2
- data/ext/cumo/include/cumo/cuda/cumo_thrust.hpp +1 -0
- data/ext/cumo/include/cumo/cuda/runtime.h +28 -0
- data/ext/cumo/include/cumo/intern.h +4 -1
- data/ext/cumo/include/cumo/narray.h +59 -3
- data/ext/cumo/include/cumo/template.h +35 -10
- data/ext/cumo/include/cumo/template_kernel.h +96 -0
- data/ext/cumo/include/cumo/types/bit.h +3 -0
- data/ext/cumo/include/cumo/types/bit_kernel.h +3 -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/float_macro.h +2 -0
- data/ext/cumo/include/cumo/types/float_macro_kernel.h +2 -0
- data/ext/cumo/include/cumo/types/half_def.h +129 -0
- data/ext/cumo/include/cumo/types/half_def_kernel.h +28 -0
- data/ext/cumo/include/cumo/types/half_macro.h +188 -0
- data/ext/cumo/include/cumo/types/half_macro_kernel.h +198 -0
- data/ext/cumo/include/cumo/types/hfloat.h +22 -0
- data/ext/cumo/include/cumo/types/hfloat_kernel.h +16 -0
- data/ext/cumo/include/cumo/types/real_accum.h +2 -0
- data/ext/cumo/include/cumo/types/real_accum_kernel.h +2 -0
- data/ext/cumo/include/cumo/types/robj_macro.h +3 -0
- data/ext/cumo/include/cumo/types/xint_macro.h +3 -0
- 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 +49 -174
- data/ext/cumo/narray/gen/def/bit.rb +2 -0
- data/ext/cumo/narray/gen/def/dcomplex.rb +2 -0
- data/ext/cumo/narray/gen/def/dfloat.rb +8 -0
- data/ext/cumo/narray/gen/def/hfloat.rb +47 -0
- data/ext/cumo/narray/gen/def/int16.rb +2 -0
- data/ext/cumo/narray/gen/def/int32.rb +2 -0
- data/ext/cumo/narray/gen/def/int64.rb +2 -0
- data/ext/cumo/narray/gen/def/int8.rb +2 -0
- data/ext/cumo/narray/gen/def/robject.rb +2 -0
- data/ext/cumo/narray/gen/def/scomplex.rb +2 -0
- data/ext/cumo/narray/gen/def/sfloat.rb +8 -0
- data/ext/cumo/narray/gen/def/uint16.rb +3 -1
- data/ext/cumo/narray/gen/def/uint32.rb +3 -1
- data/ext/cumo/narray/gen/def/uint64.rb +2 -0
- data/ext/cumo/narray/gen/def/uint8.rb +3 -1
- data/ext/cumo/narray/gen/erbpp2.rb +6 -0
- data/ext/cumo/narray/gen/spec.rb +1 -0
- data/ext/cumo/narray/gen/tmpl/accum.c +1 -1
- data/ext/cumo/narray/gen/tmpl/accum_arg.c +1 -1
- data/ext/cumo/narray/gen/tmpl/accum_arg_kernel.cu +5 -5
- data/ext/cumo/narray/gen/tmpl/accum_binary_kernel.cu +14 -1
- data/ext/cumo/narray/gen/tmpl/accum_index.c +1 -1
- data/ext/cumo/narray/gen/tmpl/accum_index_kernel.cu +5 -5
- data/ext/cumo/narray/gen/tmpl/alloc_func.c +4 -7
- data/ext/cumo/narray/gen/tmpl/allocate.c +1 -2
- data/ext/cumo/narray/gen/tmpl/aref_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl/batch_norm.c +11 -23
- data/ext/cumo/narray/gen/tmpl/batch_norm_backward.c +12 -24
- data/ext/cumo/narray/gen/tmpl/binary_kernel.cu +69 -2
- data/ext/cumo/narray/gen/tmpl/clip.c +3 -3
- data/ext/cumo/narray/gen/tmpl/cond_unary.c +1 -1
- data/ext/cumo/narray/gen/tmpl/conv.c +11 -17
- data/ext/cumo/narray/gen/tmpl/conv_grad_w.c +11 -17
- data/ext/cumo/narray/gen/tmpl/conv_transpose.c +11 -17
- data/ext/cumo/narray/gen/tmpl/cum.c +24 -1
- data/ext/cumo/narray/gen/tmpl/cum_kernel.cu +29 -4
- data/ext/cumo/narray/gen/tmpl/each.c +2 -3
- data/ext/cumo/narray/gen/tmpl/each_with_index.c +5 -21
- data/ext/cumo/narray/gen/tmpl/extract_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl/extract_data.c +1 -1
- data/ext/cumo/narray/gen/tmpl/fill.c +1 -1
- data/ext/cumo/narray/gen/tmpl/fixed_batch_norm.c +9 -21
- data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +42 -37
- data/ext/cumo/narray/gen/tmpl/format.c +1 -1
- data/ext/cumo/narray/gen/tmpl/format_to_a.c +1 -1
- data/ext/cumo/narray/gen/tmpl/gemm.c +78 -27
- data/ext/cumo/narray/gen/tmpl/init_class.c +0 -7
- data/ext/cumo/narray/gen/tmpl/init_upcast.c +6 -0
- data/ext/cumo/narray/gen/tmpl/inspect.c +1 -1
- data/ext/cumo/narray/gen/tmpl/lib.c +11 -1
- data/ext/cumo/narray/gen/tmpl/map_with_index.c +7 -14
- data/ext/cumo/narray/gen/tmpl/median.c +9 -47
- data/ext/cumo/narray/gen/tmpl/minmax.c +1 -1
- data/ext/cumo/narray/gen/tmpl/poly.c +1 -1
- data/ext/cumo/narray/gen/tmpl/pooling_backward.c +2 -14
- data/ext/cumo/narray/gen/tmpl/pooling_forward.c +2 -14
- data/ext/cumo/narray/gen/tmpl/qsort.c +0 -1
- data/ext/cumo/narray/gen/tmpl/rand.c +20 -2
- data/ext/cumo/narray/gen/tmpl/rand_kernel.cu +13 -0
- data/ext/cumo/narray/gen/tmpl/rand_norm.c +4 -4
- data/ext/cumo/narray/gen/tmpl/rand_norm_kernel.cu +7 -5
- data/ext/cumo/narray/gen/tmpl/real_accum_kernel.cu +83 -97
- data/ext/cumo/narray/gen/tmpl/sort.c +1 -1
- data/ext/cumo/narray/gen/tmpl/sort_index.c +6 -3
- data/ext/cumo/narray/gen/tmpl/store_array.c +21 -22
- data/ext/cumo/narray/gen/tmpl/store_bit.c +1 -1
- data/ext/cumo/narray/gen/tmpl/store_from.c +1 -1
- data/ext/cumo/narray/gen/tmpl/store_from_kernel.cu +37 -2
- data/ext/cumo/narray/gen/tmpl/to_a.c +1 -1
- data/ext/cumo/narray/gen/tmpl/unary.c +20 -3
- data/ext/cumo/narray/gen/tmpl/unary2.c +1 -1
- data/ext/cumo/narray/gen/tmpl/unary_s.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/allocate.c +2 -3
- data/ext/cumo/narray/gen/tmpl_bit/aref_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/bit_count_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/each.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/each_with_index.c +5 -20
- data/ext/cumo/narray/gen/tmpl_bit/extract_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/format.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/format_to_a.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/inspect.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/mask.c +38 -17
- data/ext/cumo/narray/gen/tmpl_bit/mask_kernel.cu +4 -4
- data/ext/cumo/narray/gen/tmpl_bit/store_array.c +10 -11
- data/ext/cumo/narray/gen/tmpl_bit/store_from.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/to_a.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/where.c +66 -13
- data/ext/cumo/narray/gen/tmpl_bit/where2.c +57 -20
- data/ext/cumo/narray/gen/tmpl_bit/where_kernel.cu +6 -6
- data/ext/cumo/narray/index.c +63 -18
- data/ext/cumo/narray/index_kernel.cu +15 -0
- data/ext/cumo/narray/math.c +2 -0
- data/ext/cumo/narray/narray.c +289 -183
- data/ext/cumo/narray/ndloop.c +91 -26
- data/ext/cumo/narray/sort_kernel.cu +39 -18
- data/ext/cumo/narray/struct.c +14 -17
- data/lib/cumo/cuda/cudnn.rb +1 -1
- data/lib/cumo/narray/extra.rb +11 -2
- data/test/bit_test.rb +147 -0
- data/test/cudnn_test.rb +132 -46
- data/test/extra_test.rb +1 -1
- data/test/hfloat_test.rb +717 -0
- data/test/math_test.rb +4 -1
- data/test/narray_alt_coverage_test.rb +7 -0
- data/test/narray_test.rb +1018 -11
- data/test/test_helper.rb +73 -0
- metadata +11 -1
|
@@ -158,7 +158,8 @@ cumo_cuda_cudnn_CreateConvolutionDescriptor(
|
|
|
158
158
|
size_t ndim,
|
|
159
159
|
int* int_stride,
|
|
160
160
|
int* int_pad,
|
|
161
|
-
cudnnDataType_t
|
|
161
|
+
cudnnDataType_t compute_dtype,
|
|
162
|
+
cudnnMathType_t math_type) {
|
|
162
163
|
cudnnStatus_t status = CUDNN_STATUS_SUCCESS;
|
|
163
164
|
int int_dilation[CUMO_NA_MAX_DIMENSION];
|
|
164
165
|
for (size_t idim = 0; idim < ndim; ++idim) {
|
|
@@ -178,7 +179,7 @@ cumo_cuda_cudnn_CreateConvolutionDescriptor(
|
|
|
178
179
|
int_dilation[0],
|
|
179
180
|
int_dilation[1],
|
|
180
181
|
CUDNN_CROSS_CORRELATION,
|
|
181
|
-
|
|
182
|
+
compute_dtype);
|
|
182
183
|
} else {
|
|
183
184
|
status = cudnnSetConvolutionNdDescriptor(
|
|
184
185
|
*desc,
|
|
@@ -187,10 +188,14 @@ cumo_cuda_cudnn_CreateConvolutionDescriptor(
|
|
|
187
188
|
int_stride,
|
|
188
189
|
int_dilation,
|
|
189
190
|
CUDNN_CROSS_CORRELATION,
|
|
190
|
-
|
|
191
|
+
compute_dtype);
|
|
191
192
|
}
|
|
193
|
+
if (status != CUDNN_STATUS_SUCCESS) return status;
|
|
192
194
|
|
|
193
|
-
|
|
195
|
+
// Tensor cores are not reached under CUDNN_DEFAULT_MATH, and asking for
|
|
196
|
+
// them where they do not apply is not an error, so every dtype names what
|
|
197
|
+
// it wants.
|
|
198
|
+
return cudnnSetConvolutionMathType(*desc, math_type);
|
|
194
199
|
}
|
|
195
200
|
|
|
196
201
|
cudnnStatus_t
|
|
@@ -304,9 +309,49 @@ struct AlgoCacheKeyHash {
|
|
|
304
309
|
}
|
|
305
310
|
};
|
|
306
311
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
// The math type belongs with the algorithm: the descriptor's own setting is
|
|
313
|
+
// only a permission, and cuDNN reports which one the chosen algorithm actually
|
|
314
|
+
// used. Handing that algorithm to the convolution under a different math type
|
|
315
|
+
// is rejected, or answers something else.
|
|
316
|
+
// A template cannot be declared with C linkage, and this file's exports are
|
|
317
|
+
// wrapped in extern "C".
|
|
318
|
+
extern "C++" {
|
|
319
|
+
template <typename Algo>
|
|
320
|
+
struct AlgoCacheEntry {
|
|
321
|
+
Algo algo;
|
|
322
|
+
size_t memory;
|
|
323
|
+
cudnnMathType_t math_type;
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
using FwdAlgoCacheMap = std::unordered_map<AlgoCacheKey, AlgoCacheEntry<cudnnConvolutionFwdAlgo_t>, AlgoCacheKeyHash>;
|
|
328
|
+
using BwdDataAlgoCacheMap = std::unordered_map<AlgoCacheKey, AlgoCacheEntry<cudnnConvolutionBwdDataAlgo_t>, AlgoCacheKeyHash>;
|
|
329
|
+
using BwdFilterAlgoCacheMap = std::unordered_map<AlgoCacheKey, AlgoCacheEntry<cudnnConvolutionBwdFilterAlgo_t>, AlgoCacheKeyHash>;
|
|
330
|
+
|
|
331
|
+
// Every search builds the same key. Leaving each of the three to do it by hand
|
|
332
|
+
// is how the device id came to be set in one of them and not the others.
|
|
333
|
+
static AlgoCacheKey
|
|
334
|
+
MakeAlgoCacheKey(
|
|
335
|
+
cumo_narray_t* nx, cumo_narray_t* nw, cumo_narray_t* ny,
|
|
336
|
+
int* int_stride, int* int_pad, size_t ndim,
|
|
337
|
+
cudnnDataType_t cudnn_dtype, size_t max_workspace_size)
|
|
338
|
+
{
|
|
339
|
+
auto key = AlgoCacheKey{};
|
|
340
|
+
cumo_cuda_runtime_check_status(cudaGetDevice(&(key.device_id)));
|
|
341
|
+
key.ndim = ndim;
|
|
342
|
+
for (size_t idim = 0; idim < ndim + 2; ++idim) {
|
|
343
|
+
key.x_shape[idim] = nx->shape[idim];
|
|
344
|
+
key.w_shape[idim] = nw->shape[idim];
|
|
345
|
+
key.y_shape[idim] = ny->shape[idim];
|
|
346
|
+
}
|
|
347
|
+
for (size_t idim = 0; idim < ndim; ++idim) {
|
|
348
|
+
key.pad[idim] = int_pad[idim];
|
|
349
|
+
key.stride[idim] = int_stride[idim];
|
|
350
|
+
}
|
|
351
|
+
key.dtype = cudnn_dtype;
|
|
352
|
+
key.max_workspace_size = max_workspace_size;
|
|
353
|
+
return key;
|
|
354
|
+
}
|
|
310
355
|
|
|
311
356
|
static FwdAlgoCacheMap fwd_algo_cache_map_{};
|
|
312
357
|
static BwdDataAlgoCacheMap bwd_data_algo_cache_map_{};
|
|
@@ -335,28 +380,19 @@ cumo_cuda_cudnn_FindConvolutionForwardAlgorithm(
|
|
|
335
380
|
CumoGetNArray(w, nw);
|
|
336
381
|
CumoGetNArray(y, ny);
|
|
337
382
|
|
|
338
|
-
auto key =
|
|
339
|
-
|
|
340
|
-
key.ndim = ndim;
|
|
341
|
-
for (size_t idim = 0; idim < ndim + 2; ++idim) {
|
|
342
|
-
key.x_shape[idim] = nx->shape[idim];
|
|
343
|
-
key.w_shape[idim] = nw->shape[idim];
|
|
344
|
-
key.y_shape[idim] = ny->shape[idim];
|
|
345
|
-
}
|
|
346
|
-
for (size_t idim = 0; idim < ndim; ++idim) {
|
|
347
|
-
key.pad[idim]= int_pad[idim];
|
|
348
|
-
key.stride[idim]= int_stride[idim];
|
|
349
|
-
}
|
|
350
|
-
key.dtype = cudnn_dtype;
|
|
351
|
-
key.max_workspace_size = max_workspace_size;
|
|
383
|
+
auto key = MakeAlgoCacheKey(nx, nw, ny, int_stride, int_pad, ndim,
|
|
384
|
+
cudnn_dtype, max_workspace_size);
|
|
352
385
|
|
|
353
386
|
auto& algo_cache_map = fwd_algo_cache_map_;
|
|
354
387
|
// TODO: thread-safe
|
|
355
388
|
auto it = algo_cache_map.find(key);
|
|
356
389
|
if (it != algo_cache_map.end()) {
|
|
357
|
-
auto
|
|
358
|
-
|
|
359
|
-
perf_result
|
|
390
|
+
auto entry = it->second;
|
|
391
|
+
// clear the fields the search would have filled but the cache drops
|
|
392
|
+
*perf_result = {};
|
|
393
|
+
perf_result->algo = entry.algo;
|
|
394
|
+
perf_result->memory = entry.memory;
|
|
395
|
+
perf_result->mathType = entry.math_type;
|
|
360
396
|
return CUDNN_STATUS_SUCCESS;
|
|
361
397
|
}
|
|
362
398
|
|
|
@@ -382,10 +418,13 @@ cumo_cuda_cudnn_FindConvolutionForwardAlgorithm(
|
|
|
382
418
|
max_workspace_size);
|
|
383
419
|
cumo_cuda_runtime_free(workspace);
|
|
384
420
|
if (status != CUDNN_STATUS_SUCCESS) return status;
|
|
385
|
-
|
|
421
|
+
// A search that answers success with nothing to report would leave
|
|
422
|
+
// perf_result untouched, and its algo and math type are used below.
|
|
423
|
+
if (returned_algo_count < 1) return CUDNN_STATUS_NOT_SUPPORTED;
|
|
424
|
+
if (perf_result->status != CUDNN_STATUS_SUCCESS) return perf_result->status;
|
|
386
425
|
|
|
387
426
|
// TODO: thread-safe
|
|
388
|
-
algo_cache_map[key] = {perf_result->algo, perf_result->memory};
|
|
427
|
+
algo_cache_map[key] = {perf_result->algo, perf_result->memory, perf_result->mathType};
|
|
389
428
|
return status;
|
|
390
429
|
}
|
|
391
430
|
|
|
@@ -412,27 +451,19 @@ cumo_cuda_cudnn_FindConvolutionBackwardDataAlgorithm(
|
|
|
412
451
|
CumoGetNArray(w, nw);
|
|
413
452
|
CumoGetNArray(y, ny);
|
|
414
453
|
|
|
415
|
-
auto key =
|
|
416
|
-
|
|
417
|
-
for (size_t idim = 0; idim < ndim + 2; ++idim) {
|
|
418
|
-
key.x_shape[idim] = nx->shape[idim];
|
|
419
|
-
key.w_shape[idim] = nw->shape[idim];
|
|
420
|
-
key.y_shape[idim] = ny->shape[idim];
|
|
421
|
-
}
|
|
422
|
-
for (size_t idim = 0; idim < ndim; ++idim) {
|
|
423
|
-
key.pad[idim]= int_pad[idim];
|
|
424
|
-
key.stride[idim]= int_stride[idim];
|
|
425
|
-
}
|
|
426
|
-
key.dtype = cudnn_dtype;
|
|
427
|
-
key.max_workspace_size = max_workspace_size;
|
|
454
|
+
auto key = MakeAlgoCacheKey(nx, nw, ny, int_stride, int_pad, ndim,
|
|
455
|
+
cudnn_dtype, max_workspace_size);
|
|
428
456
|
|
|
429
457
|
auto& algo_cache_map = bwd_data_algo_cache_map_;
|
|
430
458
|
// TODO: thread-safe
|
|
431
459
|
auto it = algo_cache_map.find(key);
|
|
432
460
|
if (it != algo_cache_map.end()) {
|
|
433
|
-
auto
|
|
434
|
-
|
|
435
|
-
perf_result
|
|
461
|
+
auto entry = it->second;
|
|
462
|
+
// clear the fields the search would have filled but the cache drops
|
|
463
|
+
*perf_result = {};
|
|
464
|
+
perf_result->algo = entry.algo;
|
|
465
|
+
perf_result->memory = entry.memory;
|
|
466
|
+
perf_result->mathType = entry.math_type;
|
|
436
467
|
return CUDNN_STATUS_SUCCESS;
|
|
437
468
|
}
|
|
438
469
|
|
|
@@ -458,10 +489,13 @@ cumo_cuda_cudnn_FindConvolutionBackwardDataAlgorithm(
|
|
|
458
489
|
max_workspace_size);
|
|
459
490
|
cumo_cuda_runtime_free(workspace);
|
|
460
491
|
if (status != CUDNN_STATUS_SUCCESS) return status;
|
|
461
|
-
|
|
492
|
+
// A search that answers success with nothing to report would leave
|
|
493
|
+
// perf_result untouched, and its algo and math type are used below.
|
|
494
|
+
if (returned_algo_count < 1) return CUDNN_STATUS_NOT_SUPPORTED;
|
|
495
|
+
if (perf_result->status != CUDNN_STATUS_SUCCESS) return perf_result->status;
|
|
462
496
|
|
|
463
497
|
// TODO: thread-safe
|
|
464
|
-
algo_cache_map[key] = {perf_result->algo, perf_result->memory};
|
|
498
|
+
algo_cache_map[key] = {perf_result->algo, perf_result->memory, perf_result->mathType};
|
|
465
499
|
return status;
|
|
466
500
|
}
|
|
467
501
|
|
|
@@ -488,27 +522,19 @@ cumo_cuda_cudnn_FindConvolutionBackwardFilterAlgorithm(
|
|
|
488
522
|
CumoGetNArray(gy, ngy);
|
|
489
523
|
CumoGetNArray(gw, ngw);
|
|
490
524
|
|
|
491
|
-
auto key =
|
|
492
|
-
|
|
493
|
-
for (size_t idim = 0; idim < ndim + 2; ++idim) {
|
|
494
|
-
key.x_shape[idim] = nx->shape[idim];
|
|
495
|
-
key.w_shape[idim] = ngw->shape[idim];
|
|
496
|
-
key.y_shape[idim] = ngy->shape[idim];
|
|
497
|
-
}
|
|
498
|
-
for (size_t idim = 0; idim < ndim; ++idim) {
|
|
499
|
-
key.pad[idim]= int_pad[idim];
|
|
500
|
-
key.stride[idim]= int_stride[idim];
|
|
501
|
-
}
|
|
502
|
-
key.dtype = cudnn_dtype;
|
|
503
|
-
key.max_workspace_size = max_workspace_size;
|
|
525
|
+
auto key = MakeAlgoCacheKey(nx, ngw, ngy, int_stride, int_pad, ndim,
|
|
526
|
+
cudnn_dtype, max_workspace_size);
|
|
504
527
|
|
|
505
528
|
auto& algo_cache_map = bwd_filter_algo_cache_map_;
|
|
506
529
|
// TODO: thread-safe
|
|
507
530
|
auto it = algo_cache_map.find(key);
|
|
508
531
|
if (it != algo_cache_map.end()) {
|
|
509
|
-
auto
|
|
510
|
-
|
|
511
|
-
perf_result
|
|
532
|
+
auto entry = it->second;
|
|
533
|
+
// clear the fields the search would have filled but the cache drops
|
|
534
|
+
*perf_result = {};
|
|
535
|
+
perf_result->algo = entry.algo;
|
|
536
|
+
perf_result->memory = entry.memory;
|
|
537
|
+
perf_result->mathType = entry.math_type;
|
|
512
538
|
return CUDNN_STATUS_SUCCESS;
|
|
513
539
|
}
|
|
514
540
|
|
|
@@ -534,10 +560,13 @@ cumo_cuda_cudnn_FindConvolutionBackwardFilterAlgorithm(
|
|
|
534
560
|
max_workspace_size);
|
|
535
561
|
cumo_cuda_runtime_free(workspace);
|
|
536
562
|
if (status != CUDNN_STATUS_SUCCESS) return status;
|
|
537
|
-
|
|
563
|
+
// A search that answers success with nothing to report would leave
|
|
564
|
+
// perf_result untouched, and its algo and math type are used below.
|
|
565
|
+
if (returned_algo_count < 1) return CUDNN_STATUS_NOT_SUPPORTED;
|
|
566
|
+
if (perf_result->status != CUDNN_STATUS_SUCCESS) return perf_result->status;
|
|
538
567
|
|
|
539
568
|
// TODO: thread-safe
|
|
540
|
-
algo_cache_map[key] = {perf_result->algo, perf_result->memory};
|
|
569
|
+
algo_cache_map[key] = {perf_result->algo, perf_result->memory, perf_result->mathType};
|
|
541
570
|
return status;
|
|
542
571
|
}
|
|
543
572
|
|
data/ext/cumo/cuda/runtime.c
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
VALUE cumo_cuda_eRuntimeError;
|
|
7
7
|
VALUE cumo_cuda_mRuntime;
|
|
8
|
+
uint64_t cumo_cuda_sync_epoch = 0;
|
|
8
9
|
#define eRuntimeError cumo_cuda_eRuntimeError
|
|
9
10
|
#define mRuntime cumo_cuda_mRuntime
|
|
10
11
|
|
|
@@ -42,7 +43,7 @@ cumo_cuda_runtime_error_flag_new(void)
|
|
|
42
43
|
bool
|
|
43
44
|
cumo_cuda_runtime_error_flag_get(int *flag)
|
|
44
45
|
{
|
|
45
|
-
|
|
46
|
+
cumo_cuda_runtime_device_synchronize();
|
|
46
47
|
return (*flag != 0);
|
|
47
48
|
}
|
|
48
49
|
|
|
@@ -189,9 +190,7 @@ rb_cudaSetDevice(VALUE self, VALUE device)
|
|
|
189
190
|
static VALUE
|
|
190
191
|
rb_cudaDeviceSynchronize(VALUE self)
|
|
191
192
|
{
|
|
192
|
-
|
|
193
|
-
status = cudaDeviceSynchronize();
|
|
194
|
-
check_status(status);
|
|
193
|
+
cumo_cuda_runtime_device_synchronize();
|
|
195
194
|
return Qnil;
|
|
196
195
|
}
|
|
197
196
|
|
data/ext/cumo/cumo.c
CHANGED
|
@@ -20,11 +20,27 @@ void Init_cumo_uint8();
|
|
|
20
20
|
void Init_cumo_uint16();
|
|
21
21
|
void Init_cumo_uint32();
|
|
22
22
|
void Init_cumo_uint64();
|
|
23
|
+
void Init_cumo_hfloat();
|
|
23
24
|
void Init_cumo_sfloat();
|
|
24
25
|
void Init_cumo_scomplex();
|
|
25
26
|
void Init_cumo_dfloat();
|
|
26
27
|
void Init_cumo_dcomplex();
|
|
27
28
|
void Init_cumo_robject();
|
|
29
|
+
void Init_cumo_dcomplex_upcast();
|
|
30
|
+
void Init_cumo_dfloat_upcast();
|
|
31
|
+
void Init_cumo_scomplex_upcast();
|
|
32
|
+
void Init_cumo_sfloat_upcast();
|
|
33
|
+
void Init_cumo_hfloat_upcast();
|
|
34
|
+
void Init_cumo_int64_upcast();
|
|
35
|
+
void Init_cumo_uint64_upcast();
|
|
36
|
+
void Init_cumo_int32_upcast();
|
|
37
|
+
void Init_cumo_uint32_upcast();
|
|
38
|
+
void Init_cumo_int16_upcast();
|
|
39
|
+
void Init_cumo_uint16_upcast();
|
|
40
|
+
void Init_cumo_int8_upcast();
|
|
41
|
+
void Init_cumo_uint8_upcast();
|
|
42
|
+
void Init_cumo_bit_upcast();
|
|
43
|
+
void Init_cumo_robject_upcast();
|
|
28
44
|
void Init_cumo_na_math();
|
|
29
45
|
void Init_cumo_na_rand();
|
|
30
46
|
void Init_cumo_na_array();
|
|
@@ -150,6 +166,7 @@ Init_cumo()
|
|
|
150
166
|
Init_cumo_dfloat();
|
|
151
167
|
Init_cumo_scomplex();
|
|
152
168
|
Init_cumo_sfloat();
|
|
169
|
+
Init_cumo_hfloat();
|
|
153
170
|
|
|
154
171
|
Init_cumo_int64();
|
|
155
172
|
Init_cumo_uint64();
|
|
@@ -163,6 +180,23 @@ Init_cumo()
|
|
|
163
180
|
Init_cumo_bit();
|
|
164
181
|
Init_cumo_robject();
|
|
165
182
|
|
|
183
|
+
// Every class exists now, so the UPCAST tables can name all of them.
|
|
184
|
+
Init_cumo_dcomplex_upcast();
|
|
185
|
+
Init_cumo_dfloat_upcast();
|
|
186
|
+
Init_cumo_scomplex_upcast();
|
|
187
|
+
Init_cumo_sfloat_upcast();
|
|
188
|
+
Init_cumo_hfloat_upcast();
|
|
189
|
+
Init_cumo_int64_upcast();
|
|
190
|
+
Init_cumo_uint64_upcast();
|
|
191
|
+
Init_cumo_int32_upcast();
|
|
192
|
+
Init_cumo_uint32_upcast();
|
|
193
|
+
Init_cumo_int16_upcast();
|
|
194
|
+
Init_cumo_uint16_upcast();
|
|
195
|
+
Init_cumo_int8_upcast();
|
|
196
|
+
Init_cumo_uint8_upcast();
|
|
197
|
+
Init_cumo_bit_upcast();
|
|
198
|
+
Init_cumo_robject_upcast();
|
|
199
|
+
|
|
166
200
|
Init_cumo_na_math();
|
|
167
201
|
|
|
168
202
|
Init_cumo_na_rand();
|
data/ext/cumo/extconf.rb
CHANGED
|
@@ -64,6 +64,7 @@ narray/types/uint8
|
|
|
64
64
|
narray/types/uint16
|
|
65
65
|
narray/types/uint32
|
|
66
66
|
narray/types/uint64
|
|
67
|
+
narray/types/hfloat
|
|
67
68
|
narray/types/sfloat
|
|
68
69
|
narray/types/dfloat
|
|
69
70
|
narray/types/scomplex
|
|
@@ -78,6 +79,7 @@ narray/types/uint8_kernel
|
|
|
78
79
|
narray/types/uint16_kernel
|
|
79
80
|
narray/types/uint32_kernel
|
|
80
81
|
narray/types/uint64_kernel
|
|
82
|
+
narray/types/hfloat_kernel
|
|
81
83
|
narray/types/sfloat_kernel
|
|
82
84
|
narray/types/dfloat_kernel
|
|
83
85
|
narray/types/scomplex_kernel
|
|
@@ -21,7 +21,14 @@ extern VALUE cumo_cuda_eCUDNNError;
|
|
|
21
21
|
|
|
22
22
|
extern VALUE cumo_na_eShapeError;
|
|
23
23
|
|
|
24
|
-
#define CUMO_CUDA_CUDNN_DEFAULT_MAX_WORKSPACE_SIZE 8 * 1024 * 1024
|
|
24
|
+
#define CUMO_CUDA_CUDNN_DEFAULT_MAX_WORKSPACE_SIZE (8 * 1024 * 1024)
|
|
25
|
+
|
|
26
|
+
// How much scratch cuDNN may use to pick a convolution algorithm. The fastest
|
|
27
|
+
// half algorithms are the ones that need the most, so the default keeps every
|
|
28
|
+
// dtype on the algorithms it has always used and CUMO_CUDNN_MAX_WORKSPACE_SIZE
|
|
29
|
+
// raises the ceiling for whoever wants them.
|
|
30
|
+
size_t
|
|
31
|
+
cumo_cuda_cudnn_max_workspace_size();
|
|
25
32
|
|
|
26
33
|
// An output array given by the caller is written through a descriptor built
|
|
27
34
|
// from another operand, or as if it were contiguous, so cuDNN never learns how
|
|
@@ -76,6 +83,17 @@ cumo_cuda_cudnn_check_input(VALUE in, VALUE type, size_t ndim, size_t *shape)
|
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
85
|
|
|
86
|
+
// cuDNN derives the batch norm parameter descriptor from x, and widens it to
|
|
87
|
+
// float for a half x, so the parameters do not always take x's own class.
|
|
88
|
+
static inline void
|
|
89
|
+
cumo_cuda_cudnn_check_param_type(VALUE param, VALUE type, const char* name)
|
|
90
|
+
{
|
|
91
|
+
if (rb_obj_class(param) != type) {
|
|
92
|
+
rb_raise(rb_eTypeError, "%s must be %s, not %s",
|
|
93
|
+
name, rb_class2name(type), rb_obj_classname(param));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
79
97
|
void
|
|
80
98
|
cumo_cuda_cudnn_check_status(cudnnStatus_t status);
|
|
81
99
|
|
|
@@ -172,7 +190,8 @@ cumo_cuda_cudnn_CreateConvolutionDescriptor(
|
|
|
172
190
|
size_t ndim,
|
|
173
191
|
int* int_stride,
|
|
174
192
|
int* int_pad,
|
|
175
|
-
cudnnDataType_t
|
|
193
|
+
cudnnDataType_t compute_dtype,
|
|
194
|
+
cudnnMathType_t math_type);
|
|
176
195
|
|
|
177
196
|
cudnnStatus_t
|
|
178
197
|
cumo_cuda_cudnn_CreatePoolingDescriptor(
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include <thrust/inner_product.h>
|
|
9
9
|
#include <thrust/iterator/counting_iterator.h>
|
|
10
10
|
#include <thrust/iterator/transform_iterator.h>
|
|
11
|
+
#include <thrust/iterator/transform_output_iterator.h>
|
|
11
12
|
#include <thrust/iterator/permutation_iterator.h>
|
|
12
13
|
#include <thrust/reduce.h>
|
|
13
14
|
#include <thrust/scan.h>
|
|
@@ -13,6 +13,13 @@ extern "C" {
|
|
|
13
13
|
|
|
14
14
|
extern VALUE cumo_cuda_eRuntimeError;
|
|
15
15
|
|
|
16
|
+
// How many times the whole device has been seen to settle, which is what a host
|
|
17
|
+
// read of managed memory needs. One settling covers every kernel and copy issued
|
|
18
|
+
// before it, so code that recorded the count when it queued work can skip a wait
|
|
19
|
+
// the moment the count has moved on. Only cumo_cuda_runtime_device_synchronize
|
|
20
|
+
// advances it, and a count that is behind costs a wait rather than correctness.
|
|
21
|
+
extern uint64_t cumo_cuda_sync_epoch;
|
|
22
|
+
|
|
16
23
|
static inline void
|
|
17
24
|
cumo_cuda_runtime_check_status(cudaError_t status)
|
|
18
25
|
{
|
|
@@ -21,6 +28,27 @@ cumo_cuda_runtime_check_status(cudaError_t status)
|
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
|
|
31
|
+
static inline void
|
|
32
|
+
cumo_cuda_runtime_device_synchronize(void)
|
|
33
|
+
{
|
|
34
|
+
cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
|
|
35
|
+
cumo_cuda_sync_epoch++;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Asking costs less than half of waiting, and there is nothing to wait for
|
|
39
|
+
// whenever the block stayed off the device. Neither answer advances the settle
|
|
40
|
+
// count: stream 0 going quiet is not the whole device settling, and a host read
|
|
41
|
+
// of managed memory needs the latter where concurrentManagedAccess is 0.
|
|
42
|
+
static inline int
|
|
43
|
+
cumo_cuda_runtime_sync_if_busy(void)
|
|
44
|
+
{
|
|
45
|
+
if (cudaStreamQuery(0) == cudaSuccess) {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
cumo_cuda_runtime_check_status(cudaStreamSynchronize(0));
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
24
52
|
static inline int
|
|
25
53
|
cumo_cuda_runtime_get_device_count()
|
|
26
54
|
{
|
|
@@ -33,7 +33,9 @@ char* cumo_na_get_offset_pointer_for_read_write(VALUE);
|
|
|
33
33
|
|
|
34
34
|
void cumo_na_copy_flags(VALUE src, VALUE dst);
|
|
35
35
|
|
|
36
|
+
int cumo_na_last_dim_with_elements(const cumo_narray_t *na, int start_dim);
|
|
36
37
|
VALUE cumo_na_check_ladder(VALUE self, int start_dim);
|
|
38
|
+
void cumo_na_set_newaxis_strides(cumo_narray_view_t *na2, const int *newaxis, int n_newaxis, int ndim, ssize_t elmsz);
|
|
37
39
|
VALUE cumo_na_check_contiguous(VALUE self);
|
|
38
40
|
VALUE cumo_na_as_contiguous_array(VALUE a);
|
|
39
41
|
|
|
@@ -78,8 +80,9 @@ void cumo_na_parse_enumerator_step(VALUE enum_obj, VALUE *pstep);
|
|
|
78
80
|
|
|
79
81
|
// used in aref, aset
|
|
80
82
|
int cumo_na_get_result_dimension(VALUE self, int argc, VALUE *argv, ssize_t stride, size_t *pos_idx);
|
|
83
|
+
void cumo_na_index_check_stray(cumo_narray_view_t *nv);
|
|
81
84
|
void cumo_na_index_mark_filled(cumo_narray_view_t *nv);
|
|
82
|
-
void cumo_na_index_wait_fill(
|
|
85
|
+
void cumo_na_index_wait_fill(cumo_narray_view_t *nv);
|
|
83
86
|
VALUE cumo_na_aref_main(int nidx, VALUE *idx, VALUE self, int keep_dim, int result_nd, size_t pos);
|
|
84
87
|
VALUE cumo_na_at_main(int nidx, VALUE *idx, VALUE self, int keep_dim, int result_nd, size_t pos);
|
|
85
88
|
|
|
@@ -189,6 +189,7 @@ extern const rb_data_type_t cumo_na_data_type;
|
|
|
189
189
|
extern VALUE cumo_cBit;
|
|
190
190
|
extern VALUE cumo_cDFloat;
|
|
191
191
|
extern VALUE cumo_cSFloat;
|
|
192
|
+
extern VALUE cumo_cHFloat;
|
|
192
193
|
extern VALUE cumo_cDComplex;
|
|
193
194
|
extern VALUE cumo_cSComplex;
|
|
194
195
|
extern VALUE cumo_cInt64;
|
|
@@ -220,7 +221,6 @@ typedef struct {
|
|
|
220
221
|
unsigned char ndim; // # of dimensions
|
|
221
222
|
unsigned char type;
|
|
222
223
|
unsigned char flag[2]; // flags
|
|
223
|
-
unsigned short elmsz; // element size
|
|
224
224
|
size_t size; // # of total elements
|
|
225
225
|
size_t *shape; // # of elements for each dimension
|
|
226
226
|
VALUE reduce;
|
|
@@ -230,7 +230,6 @@ typedef struct {
|
|
|
230
230
|
typedef struct {
|
|
231
231
|
cumo_narray_t base;
|
|
232
232
|
char *ptr;
|
|
233
|
-
bool owned;
|
|
234
233
|
} cumo_narray_data_t;
|
|
235
234
|
|
|
236
235
|
|
|
@@ -255,6 +254,12 @@ typedef struct {
|
|
|
255
254
|
size_t reach_end;
|
|
256
255
|
uint64_t index_sync_epoch; // synchronizes counted when the index fills were
|
|
257
256
|
// issued; UINT64_MAX when that is not known
|
|
257
|
+
// A view made from another one can point at the index arrays it already
|
|
258
|
+
// has rather than copy them. index_owner keeps that view alive for as long
|
|
259
|
+
// as this one borrows from it, and index_owned says which dimensions are
|
|
260
|
+
// this view's own to free.
|
|
261
|
+
VALUE index_owner;
|
|
262
|
+
uint64_t index_owned;
|
|
258
263
|
} cumo_narray_view_t;
|
|
259
264
|
|
|
260
265
|
|
|
@@ -372,7 +377,6 @@ _cumo_na_get_narray_t(VALUE obj, unsigned char cumo_na_type)
|
|
|
372
377
|
#define CUMO_NA_DATA(na) ((cumo_narray_data_t*)(na))
|
|
373
378
|
#define CUMO_NA_VIEW(na) ((cumo_narray_view_t*)(na))
|
|
374
379
|
#define CUMO_NA_DATA_PTR(na) (CUMO_NA_DATA(na)->ptr)
|
|
375
|
-
#define CUMO_NA_DATA_OWNED(na) (CUMO_NA_DATA(na)->owned)
|
|
376
380
|
#define CUMO_NA_VIEW_DATA(na) (CUMO_NA_VIEW(na)->data)
|
|
377
381
|
#define CUMO_NA_VIEW_OFFSET(na) (CUMO_NA_VIEW(na)->offset)
|
|
378
382
|
#define CUMO_NA_VIEW_STRIDX(na) (CUMO_NA_VIEW(na)->stridx)
|
|
@@ -507,9 +511,61 @@ typedef unsigned int CUMO_BIT_DIGIT;
|
|
|
507
511
|
#define CUMO_BALL (~(CUMO_BIT_DIGIT)0)
|
|
508
512
|
#define CUMO_SLB(n) (((n)==CUMO_NB)?~(CUMO_BIT_DIGIT)0:(~(~(CUMO_BIT_DIGIT)0<<(n))))
|
|
509
513
|
|
|
514
|
+
// Bits are packed into digits, so a buffer holding n of them is as long as the
|
|
515
|
+
// digits they fill, rounded up. n has to be positive: an empty array has no
|
|
516
|
+
// buffer, and the subtraction below would wrap.
|
|
517
|
+
#define CUMO_BIT_BYTES(n) \
|
|
518
|
+
((((n) - 1) / 8 / sizeof(CUMO_BIT_DIGIT) + 1) * sizeof(CUMO_BIT_DIGIT))
|
|
519
|
+
|
|
510
520
|
#include "cumo/ndloop.h"
|
|
511
521
|
#include "cumo/intern.h"
|
|
512
522
|
|
|
523
|
+
// An index array a view holds is freed only if it was set through here, so a
|
|
524
|
+
// view that puts one in stridx any other way leaks it. The bit names the slot,
|
|
525
|
+
// so code that permutes stridx has to permute index_owned with it.
|
|
526
|
+
static inline void
|
|
527
|
+
cumo_na_index_own(cumo_narray_view_t *nv, int i, size_t *idx)
|
|
528
|
+
{
|
|
529
|
+
CUMO_SDX_SET_INDEX(nv->stridx[i], idx);
|
|
530
|
+
nv->index_owned |= (uint64_t)1 << i;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// One dimension of nv now points at an index array that from reaches, so from
|
|
534
|
+
// has to outlive nv. A lender that owns nothing itself is skipped for its own
|
|
535
|
+
// lender, which keeps the common chain one link long. A lender that owns even
|
|
536
|
+
// one dimension is named directly, since only it keeps that one alive.
|
|
537
|
+
//
|
|
538
|
+
// A view borrows every index array or none. Borrowing some while building
|
|
539
|
+
// others holds the lender for arrays this view has already replaced, which
|
|
540
|
+
// costs more memory than the copy it saves. One lender is recorded, so a view
|
|
541
|
+
// may not borrow from two.
|
|
542
|
+
static inline void
|
|
543
|
+
cumo_na_index_borrow(cumo_narray_view_t *nv, VALUE from)
|
|
544
|
+
{
|
|
545
|
+
cumo_narray_view_t *nv1;
|
|
546
|
+
|
|
547
|
+
if (RTEST(nv->index_owner)) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
CumoGetNArrayView(from, nv1);
|
|
551
|
+
nv->index_owner = (nv1->index_owned == 0 && RTEST(nv1->index_owner))
|
|
552
|
+
? nv1->index_owner : from;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Called once a view built from another one has all its dimensions. A view that
|
|
556
|
+
// owns index arrays built them here, so a fill is in flight and the first read
|
|
557
|
+
// waits. One that borrows them all is as settled as the view it borrowed from.
|
|
558
|
+
static inline void
|
|
559
|
+
cumo_na_index_mark_derived(cumo_narray_view_t *nv, cumo_narray_view_t *nv1)
|
|
560
|
+
{
|
|
561
|
+
if (nv->index_owned != 0) {
|
|
562
|
+
cumo_na_index_mark_filled(nv);
|
|
563
|
+
} else {
|
|
564
|
+
cumo_na_index_check_stray(nv);
|
|
565
|
+
nv->index_sync_epoch = nv1->index_sync_epoch;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
513
569
|
// for Ractor support code
|
|
514
570
|
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
515
571
|
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
@@ -36,17 +36,24 @@
|
|
|
36
36
|
|
|
37
37
|
// pos is the first position in iteration order, so a step below zero walks down
|
|
38
38
|
// from there and rebasing the pointer onto pos would underflow the position of
|
|
39
|
-
// every element past the first word.
|
|
40
|
-
//
|
|
39
|
+
// every element past the first word. An index holds positions relative to pos
|
|
40
|
+
// and one of them is below zero as soon as the view it came from walks an axis
|
|
41
|
+
// backwards, so pos + idx is right in unsigned arithmetic only while pos is
|
|
42
|
+
// whole. The test reads the iterator rather than the caller's copy of step,
|
|
43
|
+
// which is how a template declaring it as size_t used to lose the sign.
|
|
44
|
+
#define CUMO_REBASE_BIT_PTR( lp, i, ad, ps ) \
|
|
45
|
+
if (((lp)->args[i].iter[0]).step >= 0 && \
|
|
46
|
+
((lp)->args[i].iter[0]).idx == NULL) { \
|
|
47
|
+
ad += ps/CUMO_NB; \
|
|
48
|
+
ps %= CUMO_NB; \
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
#define CUMO_INIT_PTR_BIT( lp, i, ad, ps, st ) \
|
|
42
52
|
{ \
|
|
43
53
|
ps = ((lp)->args[i].iter[0]).pos; \
|
|
44
54
|
st = ((lp)->args[i].iter[0]).step; \
|
|
45
55
|
ad = (CUMO_BIT_DIGIT*)(((lp)->args[i]).ptr); \
|
|
46
|
-
|
|
47
|
-
ad += ps/CUMO_NB; \
|
|
48
|
-
ps %= CUMO_NB; \
|
|
49
|
-
} \
|
|
56
|
+
CUMO_REBASE_BIT_PTR(lp, i, ad, ps); \
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
#define CUMO_INIT_PTR_BIT_IDX( lp, i, ad, ps, st, id ) \
|
|
@@ -55,10 +62,7 @@
|
|
|
55
62
|
st = ((lp)->args[i].iter[0]).step; \
|
|
56
63
|
id = ((lp)->args[i].iter[0]).idx; \
|
|
57
64
|
ad = (CUMO_BIT_DIGIT*)(((lp)->args[i]).ptr); \
|
|
58
|
-
|
|
59
|
-
ad += ps/CUMO_NB; \
|
|
60
|
-
ps %= CUMO_NB; \
|
|
61
|
-
} \
|
|
65
|
+
CUMO_REBASE_BIT_PTR(lp, i, ad, ps); \
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
// A where compaction takes three launches, so below this many elements walking
|
|
@@ -179,4 +183,25 @@ cumo_na_store_rary_fetch(VALUE ary, size_t i, VALUE *x)
|
|
|
179
183
|
return true;
|
|
180
184
|
}
|
|
181
185
|
|
|
186
|
+
// A 0-dimensional walk still yields one index, so the depth floors at 0 rather
|
|
187
|
+
// than going negative and writing c[-1].
|
|
188
|
+
static inline void
|
|
189
|
+
cumo_na_with_index_dims(int ndim, int *nd, int *md)
|
|
190
|
+
{
|
|
191
|
+
*nd = (ndim > 0) ? ndim - 1 : ndim;
|
|
192
|
+
*md = *nd + 2;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static inline VALUE
|
|
196
|
+
cumo_na_yield_with_index(VALUE x, size_t *c, VALUE *a, int nd, int md)
|
|
197
|
+
{
|
|
198
|
+
int j;
|
|
199
|
+
|
|
200
|
+
a[0] = x;
|
|
201
|
+
for (j=0; j<=nd; j++) {
|
|
202
|
+
a[j+1] = SIZET2NUM(c[j]);
|
|
203
|
+
}
|
|
204
|
+
return rb_yield(rb_ary_new4(md,a));
|
|
205
|
+
}
|
|
206
|
+
|
|
182
207
|
#endif /* ifndef CUMO_TEMPLATE_H */
|