cumo 0.12.0 → 0.13.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 +33 -2
- data/README.md +1 -0
- data/ext/cumo/cuda/cudnn_impl.cpp +23 -30
- data/ext/cumo/cuda/cusolver.c +193 -24
- data/ext/cumo/cuda/nvrtc.c +77 -11
- data/ext/cumo/cuda/runtime.c +15 -4
- data/ext/cumo/depend.erb +1 -1
- data/ext/cumo/extconf.rb +2 -2
- data/ext/cumo/include/cumo/atomic.h +27 -0
- data/ext/cumo/include/cumo/cuda/runtime.h +26 -5
- data/ext/cumo/include/cumo/intern.h +2 -2
- data/ext/cumo/include/cumo/narray.h +2 -2
- data/ext/cumo/include/cumo/types/int_macro_kernel.h +1 -1
- data/ext/cumo/include/cumo/types/uint_macro_kernel.h +1 -2
- data/ext/cumo/include/cumo.h +2 -2
- data/ext/cumo/narray/array.c +4 -4
- data/ext/cumo/narray/data.c +14 -16
- data/ext/cumo/narray/gen/cogen_kernel.rb +24 -2
- data/ext/cumo/narray/gen/erbpp2.rb +7 -1
- data/ext/cumo/narray/gen/kernel_parts.rb +11 -1
- data/ext/cumo/narray/gen/narray_def.rb +2 -2
- data/ext/cumo/narray/gen/spec.rb +10 -0
- data/ext/cumo/narray/gen/tmpl/accum.c +9 -8
- data/ext/cumo/narray/gen/tmpl/accum_arg.c +3 -3
- data/ext/cumo/narray/gen/tmpl/accum_binary.c +5 -5
- data/ext/cumo/narray/gen/tmpl/accum_index.c +3 -3
- data/ext/cumo/narray/gen/tmpl/allocate.c +3 -1
- data/ext/cumo/narray/gen/tmpl/aref.c +2 -2
- data/ext/cumo/narray/gen/tmpl/aref_cpu.c +2 -2
- data/ext/cumo/narray/gen/tmpl/aset.c +3 -3
- data/ext/cumo/narray/gen/tmpl/at.c +2 -2
- data/ext/cumo/narray/gen/tmpl/binary.c +2 -2
- data/ext/cumo/narray/gen/tmpl/binary2.c +2 -2
- data/ext/cumo/narray/gen/tmpl/binary_s.c +3 -3
- data/ext/cumo/narray/gen/tmpl/bincount.c +7 -7
- data/ext/cumo/narray/gen/tmpl/cast.c +4 -2
- data/ext/cumo/narray/gen/tmpl/clip.c +3 -3
- data/ext/cumo/narray/gen/tmpl/coerce_cast.c +1 -1
- data/ext/cumo/narray/gen/tmpl/complex_accum_kernel.cu +44 -0
- data/ext/cumo/narray/gen/tmpl/cond_binary.c +2 -2
- data/ext/cumo/narray/gen/tmpl/cond_unary.c +1 -1
- data/ext/cumo/narray/gen/tmpl/cum.c +3 -3
- data/ext/cumo/narray/gen/tmpl/each.c +1 -1
- data/ext/cumo/narray/gen/tmpl/ewcomp.c +6 -5
- data/ext/cumo/narray/gen/tmpl/extract.c +1 -1
- data/ext/cumo/narray/gen/tmpl/extract_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl/eye.c +5 -5
- data/ext/cumo/narray/gen/tmpl/fill.c +2 -2
- data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +30 -0
- data/ext/cumo/narray/gen/tmpl/format.c +2 -2
- data/ext/cumo/narray/gen/tmpl/format_to_a.c +2 -2
- data/ext/cumo/narray/gen/tmpl/frexp.c +2 -2
- data/ext/cumo/narray/gen/tmpl/gemm.c +3 -3
- data/ext/cumo/narray/gen/tmpl/inspect.c +1 -1
- data/ext/cumo/narray/gen/tmpl/layer_norm.c +5 -5
- data/ext/cumo/narray/gen/tmpl/logseq.c +4 -4
- data/ext/cumo/narray/gen/tmpl/median.c +5 -5
- data/ext/cumo/narray/gen/tmpl/minmax.c +4 -4
- data/ext/cumo/narray/gen/tmpl/poly.c +2 -2
- data/ext/cumo/narray/gen/tmpl/pow.c +60 -15
- data/ext/cumo/narray/gen/tmpl/pow_kernel.cu +28 -16
- data/ext/cumo/narray/gen/tmpl/rand.c +7 -9
- data/ext/cumo/narray/gen/tmpl/rand_norm.c +6 -9
- data/ext/cumo/narray/gen/tmpl/rms_norm.c +4 -4
- data/ext/cumo/narray/gen/tmpl/seq.c +3 -3
- data/ext/cumo/narray/gen/tmpl/sort.c +4 -4
- data/ext/cumo/narray/gen/tmpl/sort_index.c +3 -3
- data/ext/cumo/narray/gen/tmpl/store.c +2 -2
- data/ext/cumo/narray/gen/tmpl/store_kernel.cu +1 -1
- data/ext/cumo/narray/gen/tmpl/to_a.c +1 -1
- data/ext/cumo/narray/gen/tmpl/unary.c +1 -1
- data/ext/cumo/narray/gen/tmpl/unary2.c +1 -1
- data/ext/cumo/narray/gen/tmpl/unary_ret2.c +1 -1
- data/ext/cumo/narray/gen/tmpl/unary_s.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/aref.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/aref_cpu.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/aset.c +3 -3
- data/ext/cumo/narray/gen/tmpl_bit/binary.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/bit_count.c +3 -3
- data/ext/cumo/narray/gen/tmpl_bit/bit_count_cpu.c +3 -3
- data/ext/cumo/narray/gen/tmpl_bit/bit_reduce.c +3 -3
- data/ext/cumo/narray/gen/tmpl_bit/bit_stat.c +3 -3
- data/ext/cumo/narray/gen/tmpl_bit/each.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/each_with_index.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/extract.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/extract_cpu.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/fill.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/format.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/format_to_a.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/inspect.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/mask.c +2 -2
- data/ext/cumo/narray/gen/tmpl_bit/to_a.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/unary.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/where.c +1 -1
- data/ext/cumo/narray/gen/tmpl_bit/where2.c +1 -1
- data/ext/cumo/narray/index.c +7 -4
- data/ext/cumo/narray/math.c +6 -6
- data/ext/cumo/narray/narray.c +54 -43
- data/ext/cumo/narray/ndloop.c +7 -7
- data/ext/cumo/narray/rand.c +7 -12
- data/ext/cumo/narray/struct.c +3 -3
- data/lib/cumo/cuda/compiler.rb +1 -1
- data/lib/cumo/cuda/elementwise_kernel.rb +7 -6
- data/lib/cumo/cuda/reduction_kernel.rb +7 -4
- data/lib/cumo/cuda/user_kernel.rb +5 -2
- data/lib/cumo/linalg.rb +313 -77
- data/lib/cumo/narray/extra.rb +5 -5
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad04bee56b44e50dfc5df236d806a034f1adef98415e6e78ffcdd73546047dfd
|
|
4
|
+
data.tar.gz: c202fc43967dc292dddeea61274b89be6095f8724a7cfb7ac37d299cbc56cc7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 00b7285a170c241c968f2bba0ab4e80013f971c01964d8d092eefa4eb177ea06d68616326bf457b1e9a6a9c08ca8906b85456ba2ef91acbb13334292959b10a0
|
|
7
|
+
data.tar.gz: eba6aed6cdb916d1abee4d856a5496892ef5e33d3bb55cf4124fb01c3066a0324301baefe5d095798e21a0066af5d87c33ceca51142a00fec24936450b9f5946
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
# 0.13.0 (2026/10/12)
|
|
2
|
+
|
|
3
|
+
Breaking changes:
|
|
4
|
+
|
|
5
|
+
* An integer array raised to a negative integer power raises `Cumo::NArray::ValueError`, where it answered 0 even for a base of 1 or -1. numo-narray-alt now raises here too, as NumPy does. A signed integer exponent held in an array is checked on the device, so such a `**` now waits for its kernel, as integer division by an array does. An exponent array that holds `2**31` or more is no longer narrowed to 32 bits, so `Cumo::Int64[1] ** Cumo::Int64[2**31]` answers `[1]` where it answered `[0]` (PR #614)
|
|
6
|
+
|
|
7
|
+
Fixes:
|
|
8
|
+
|
|
9
|
+
* Fix `inspect` printing `(empty)` for a scalar cast to an array, such as `Cumo::DFloat.cast(5.0)`, and for its views, which it did since 0.5.10. Its value and the operators on it were right. Fix such an array that is frozen, as `Ractor.make_shareable` leaves it, raising `FrozenError` when read, and then answering 0 to some operators and its value to others (PR #616)
|
|
10
|
+
* Fix a crash, or a read of the wrong memory, when a 0-dimensional array is indexed with nothing but `false`, `:rest` or `:~`, such as `Cumo::DFloat.cast(5.0)[false]` (PR #615)
|
|
11
|
+
* Fix the cuDNN algorithm caches and the counters that deferred host reads and index fills wait on, which two Ractors could update at once. They now take a lock or advance atomically (PR #613)
|
|
12
|
+
* Fix two Ractors calling `rand` or `rand_norm` at the same time drawing the same numbers. A single thread draws what it drew before, so `srand` still reproduces a sequence (PR #612)
|
|
13
|
+
* Fix wrong results, an illegal memory access, or a process stuck at full GPU load when two Ractors call cuSOLVER at once, as `Cumo::Linalg.svdvals` and `eigvals` do. Each thread keeps its own workspace and frees it when it ends (PR #611)
|
|
14
|
+
* Fix `Cumo::Linalg.expm` of a triangular matrix whose elements off the diagonal are far larger than those on it answering 1 on the diagonal. The diagonal and the first off-diagonal are now reset to their exact values after each squaring, as scipy does (PR #609)
|
|
15
|
+
* Fix `Cumo::Linalg.expm` raising `FloatDomainError: Infinity` for a finite matrix whose 1-norm overflows. It still refuses such a matrix, and now says that its 1-norm overflowed (PR #603)
|
|
16
|
+
* Fix `Cumo::Linalg.lu` and `matrix_power(a, 0)` raising `NoMethodError` for a Bit matrix. `P` and the identity are Bit matrices (PR #602)
|
|
17
|
+
* Fix `Cumo::Linalg.lu` raising `ShapeError` for an empty matrix. It answers `P`, `L` and `U` of m x m, m x 0 and 0 x n, the shapes a nonempty matrix gets. numo-linalg-alt raises here (PR #601)
|
|
18
|
+
|
|
19
|
+
Changes:
|
|
20
|
+
|
|
21
|
+
* The first elementwise call on a type loads the kernels of one family rather than every elementwise kernel of the type. The families are arithmetic, common math functions, rare math functions, comparisons, stores from other types, and random numbers with polynomials. A first SFloat add takes 28 MB of host memory where it took 86 MB (PR #610)
|
|
22
|
+
* `require "cumo"` no longer loads NVRTC. It is loaded from the CUDA that cumo was built against the first time `ElementwiseKernel`, `ReductionKernel` or `RawKernel` builds a kernel, which takes about 34 MB off the RSS after `require` (PR #607, PR #606)
|
|
23
|
+
* `Cumo::Linalg.norm` of ord 1, -1, Infinity and -Infinity takes the magnitudes as it reduces rather than through `abs`, which makes it about 2.4 times faster on a 4096 x 4096 DFloat (PR #605)
|
|
24
|
+
* `Cumo::Linalg.norm` of ord 2, -2 and `"nuc"` over stacked matrices of up to 32 rows and columns computes them in one batched call, about 7 times faster for 1000 DFloat matrices of 8 x 8. A stacked matrix that holds NaN or Infinity answers NaN, as the matrices past 32 do (PR #604)
|
|
25
|
+
* `Cumo::Linalg.expm` of a small matrix reads its three norms in one wait, which makes it about 3% faster on a 64 x 64 DFloat (PR #600)
|
|
26
|
+
* The factorizations in `Cumo::Linalg` free their column-major copies once used, so a small call reuses memory the GPU has touched: `lu_solve` of a 256 x 256 SFloat is about 8% faster (PR #599)
|
|
27
|
+
* `repeat` builds its index in one Array: `repeat(2)` of a million elements is 3.4 times faster, and `repeat` with an Array of counts 2.2 times. The development setup checks `lib` with rubocop-performance (PR #598, PR #597)
|
|
28
|
+
* `Cumo::Linalg.eig` and `svd` give cuSOLVER pinned host memory to work in, kept for the process up to 256 MiB: `eig` of a 4096 x 4096 SFloat is about 8% faster, and `svd` of an 8192 x 2048 SFloat about 5% (PR #596)
|
|
29
|
+
* `Cumo::Linalg.expm` frees its temporary matrices as it goes rather than leaving about 40 a call to the garbage collector, which makes it about 15% faster on a 1024 x 1024 SFloat of large norm (PR #595)
|
|
30
|
+
* The API docs show the parameters of overloaded methods such as `cast`, `store_binary` and `layer_norm`, where YARD warned 1,419 times (PR #608)
|
|
31
|
+
|
|
1
32
|
# 0.12.0 (2026/10/04)
|
|
2
33
|
|
|
3
34
|
Fixes:
|
|
@@ -503,7 +534,7 @@ Fixes:
|
|
|
503
534
|
* Remove unnecessary debug code
|
|
504
535
|
* Fix capability list
|
|
505
536
|
* Build only with supported capabilities to reduce compilation time
|
|
506
|
-
* Fix SEGV when calling
|
|
537
|
+
* Fix SEGV when calling `mean`, `var`, `stddev` or `rms` on a single-element array (#154)
|
|
507
538
|
* Suppress warning message for deprecated declarations
|
|
508
539
|
* Fix variable typo in complex log2 and log10 functions (#152)
|
|
509
540
|
|
|
@@ -545,7 +576,7 @@ Fixes:
|
|
|
545
576
|
* Backport: fix macro: STORE_BIT STORE_BIT_STEP: requires mask to leave the lowest bit
|
|
546
577
|
* Backport: fix NArray::Bit#any?,all?: empty array should return false
|
|
547
578
|
* Backport: fix NArray::Bit#count_true/false: empty array should return zero
|
|
548
|
-
* Backport: bug in NArray::Bit; fix bit operation in tmpl_bit/{store_bit,unary,binary}.c
|
|
579
|
+
* Backport: bug in NArray::Bit; fix bit operation in `tmpl_bit/{store_bit,unary,binary}.c`
|
|
549
580
|
* Fix typo
|
|
550
581
|
* Backport 135: Make all empty arrays equal
|
|
551
582
|
* Backport: minor fixes in na_get_result_dimension(), check_index_count()
|
data/README.md
CHANGED
|
@@ -312,6 +312,7 @@ Cumo differs from numo-linalg-alt in a few places on purpose:
|
|
|
312
312
|
* `expm` scales and squares the way scipy does, after Al-Mohy and Higham, which stays accurate where the norm of the matrix is large. Passing the order of the Pade approximant, as in `expm(a, 3)`, keeps numo-linalg-alt's algorithm.
|
|
313
313
|
* `norm` takes the 2-norm and the nuclear norm of matrices stacked along other axes, which numo-linalg-alt refuses.
|
|
314
314
|
* `cond` checks `ord` before it inverts the matrix, so an invalid `ord` raises `ArgumentError` even for a singular matrix, where numo-linalg-alt raises `LapackError`.
|
|
315
|
+
* `lu` answers for an empty matrix and for a `Bit` matrix, where numo-linalg-alt raises. P keeps the shape and the class it has for any other matrix: an m x m identity for an m x 0 matrix, where scipy answers a 0 x 0 one, and a `Bit` for a `Bit` matrix. `matrix_power(a, 0)` of a `Bit` matrix likewise answers a `Bit` identity.
|
|
315
316
|
|
|
316
317
|
A function waits for the current stream when it answers a Ruby number, or when it reads back whether cuSOLVER could do its work.
|
|
317
318
|
`solve`, `inv` and `det` read back whether the matrix was singular, `cho_fact` whether it was positive definite, and `eigh` and `svd` whether they converged.
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include "cumo/cuda/runtime.h"
|
|
12
12
|
#include "cumo/cuda/memory_pool.h"
|
|
13
13
|
|
|
14
|
+
#include <mutex>
|
|
14
15
|
#include <unordered_map>
|
|
15
16
|
|
|
16
17
|
#if defined(__cplusplus)
|
|
@@ -387,13 +388,32 @@ struct AlgoCacheEntry {
|
|
|
387
388
|
// Nothing may reach the C caller: it has no handler, so an escaping exception
|
|
388
389
|
// is std::terminate. The cache only saves a later search, so one that cannot
|
|
389
390
|
// grow leaves the answer this call already has.
|
|
391
|
+
static std::mutex algo_cache_mutex_;
|
|
392
|
+
|
|
390
393
|
template <typename Map>
|
|
391
394
|
void StoreAlgoCache(Map& map, const AlgoCacheKey& key, const typename Map::mapped_type& entry) {
|
|
395
|
+
std::lock_guard<std::mutex> lock{algo_cache_mutex_};
|
|
392
396
|
try {
|
|
393
397
|
map[key] = entry;
|
|
394
398
|
} catch (...) {
|
|
395
399
|
}
|
|
396
400
|
}
|
|
401
|
+
|
|
402
|
+
template <typename Map, typename Perf>
|
|
403
|
+
bool LookupAlgoCache(Map& map, const AlgoCacheKey& key, Perf* perf_result) {
|
|
404
|
+
std::lock_guard<std::mutex> lock{algo_cache_mutex_};
|
|
405
|
+
auto it = map.find(key);
|
|
406
|
+
if (it == map.end()) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
auto entry = it->second;
|
|
410
|
+
// clear the fields the search would have filled but the cache drops
|
|
411
|
+
*perf_result = {};
|
|
412
|
+
perf_result->algo = entry.algo;
|
|
413
|
+
perf_result->memory = entry.memory;
|
|
414
|
+
perf_result->mathType = entry.math_type;
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
397
417
|
}
|
|
398
418
|
|
|
399
419
|
using FwdAlgoCacheMap = std::unordered_map<AlgoCacheKey, AlgoCacheEntry<cudnnConvolutionFwdAlgo_t>, AlgoCacheKeyHash>;
|
|
@@ -456,15 +476,7 @@ cumo_cuda_cudnn_FindConvolutionForwardAlgorithm(
|
|
|
456
476
|
cudnn_dtype, max_workspace_size);
|
|
457
477
|
|
|
458
478
|
auto& algo_cache_map = fwd_algo_cache_map_;
|
|
459
|
-
|
|
460
|
-
auto it = algo_cache_map.find(key);
|
|
461
|
-
if (it != algo_cache_map.end()) {
|
|
462
|
-
auto entry = it->second;
|
|
463
|
-
// clear the fields the search would have filled but the cache drops
|
|
464
|
-
*perf_result = {};
|
|
465
|
-
perf_result->algo = entry.algo;
|
|
466
|
-
perf_result->memory = entry.memory;
|
|
467
|
-
perf_result->mathType = entry.math_type;
|
|
479
|
+
if (LookupAlgoCache(algo_cache_map, key, perf_result)) {
|
|
468
480
|
return CUDNN_STATUS_SUCCESS;
|
|
469
481
|
}
|
|
470
482
|
|
|
@@ -495,7 +507,6 @@ cumo_cuda_cudnn_FindConvolutionForwardAlgorithm(
|
|
|
495
507
|
if (returned_algo_count < 1) return CUDNN_STATUS_NOT_SUPPORTED;
|
|
496
508
|
if (perf_result->status != CUDNN_STATUS_SUCCESS) return perf_result->status;
|
|
497
509
|
|
|
498
|
-
// TODO: thread-safe
|
|
499
510
|
StoreAlgoCache(algo_cache_map, key, {perf_result->algo, perf_result->memory, perf_result->mathType});
|
|
500
511
|
return status;
|
|
501
512
|
}
|
|
@@ -527,15 +538,7 @@ cumo_cuda_cudnn_FindConvolutionBackwardDataAlgorithm(
|
|
|
527
538
|
cudnn_dtype, max_workspace_size);
|
|
528
539
|
|
|
529
540
|
auto& algo_cache_map = bwd_data_algo_cache_map_;
|
|
530
|
-
|
|
531
|
-
auto it = algo_cache_map.find(key);
|
|
532
|
-
if (it != algo_cache_map.end()) {
|
|
533
|
-
auto entry = it->second;
|
|
534
|
-
// clear the fields the search would have filled but the cache drops
|
|
535
|
-
*perf_result = {};
|
|
536
|
-
perf_result->algo = entry.algo;
|
|
537
|
-
perf_result->memory = entry.memory;
|
|
538
|
-
perf_result->mathType = entry.math_type;
|
|
541
|
+
if (LookupAlgoCache(algo_cache_map, key, perf_result)) {
|
|
539
542
|
return CUDNN_STATUS_SUCCESS;
|
|
540
543
|
}
|
|
541
544
|
|
|
@@ -566,7 +569,6 @@ cumo_cuda_cudnn_FindConvolutionBackwardDataAlgorithm(
|
|
|
566
569
|
if (returned_algo_count < 1) return CUDNN_STATUS_NOT_SUPPORTED;
|
|
567
570
|
if (perf_result->status != CUDNN_STATUS_SUCCESS) return perf_result->status;
|
|
568
571
|
|
|
569
|
-
// TODO: thread-safe
|
|
570
572
|
StoreAlgoCache(algo_cache_map, key, {perf_result->algo, perf_result->memory, perf_result->mathType});
|
|
571
573
|
return status;
|
|
572
574
|
}
|
|
@@ -598,15 +600,7 @@ cumo_cuda_cudnn_FindConvolutionBackwardFilterAlgorithm(
|
|
|
598
600
|
cudnn_dtype, max_workspace_size);
|
|
599
601
|
|
|
600
602
|
auto& algo_cache_map = bwd_filter_algo_cache_map_;
|
|
601
|
-
|
|
602
|
-
auto it = algo_cache_map.find(key);
|
|
603
|
-
if (it != algo_cache_map.end()) {
|
|
604
|
-
auto entry = it->second;
|
|
605
|
-
// clear the fields the search would have filled but the cache drops
|
|
606
|
-
*perf_result = {};
|
|
607
|
-
perf_result->algo = entry.algo;
|
|
608
|
-
perf_result->memory = entry.memory;
|
|
609
|
-
perf_result->mathType = entry.math_type;
|
|
603
|
+
if (LookupAlgoCache(algo_cache_map, key, perf_result)) {
|
|
610
604
|
return CUDNN_STATUS_SUCCESS;
|
|
611
605
|
}
|
|
612
606
|
|
|
@@ -637,7 +631,6 @@ cumo_cuda_cudnn_FindConvolutionBackwardFilterAlgorithm(
|
|
|
637
631
|
if (returned_algo_count < 1) return CUDNN_STATUS_NOT_SUPPORTED;
|
|
638
632
|
if (perf_result->status != CUDNN_STATUS_SUCCESS) return perf_result->status;
|
|
639
633
|
|
|
640
|
-
// TODO: thread-safe
|
|
641
634
|
StoreAlgoCache(algo_cache_map, key, {perf_result->algo, perf_result->memory, perf_result->mathType});
|
|
642
635
|
return status;
|
|
643
636
|
}
|
data/ext/cumo/cuda/cusolver.c
CHANGED
|
@@ -94,6 +94,8 @@ rb_cusolver_version(VALUE self)
|
|
|
94
94
|
typedef struct {
|
|
95
95
|
char *work;
|
|
96
96
|
size_t size;
|
|
97
|
+
char *host_work;
|
|
98
|
+
size_t host_size;
|
|
97
99
|
int *info;
|
|
98
100
|
cudaEvent_t done;
|
|
99
101
|
} cusolver_scratch_t;
|
|
@@ -105,19 +107,18 @@ typedef struct {
|
|
|
105
107
|
} cusolver_context_t;
|
|
106
108
|
|
|
107
109
|
#define CUSOLVER_KEPT_WORK_MAX ((size_t)32 << 20)
|
|
110
|
+
#define CUSOLVER_KEPT_HOST_WORK_MAX ((size_t)256 << 20)
|
|
111
|
+
|
|
112
|
+
static cumo_cuda_thread_local_t scratches;
|
|
108
113
|
|
|
109
114
|
static cusolver_scratch_t*
|
|
110
115
|
cusolver_scratch(void)
|
|
111
116
|
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (scratch == 0) {
|
|
116
|
-
scratch = ZALLOC_N(cusolver_scratch_t, cumo_cuda_runtime_get_device_count());
|
|
117
|
+
cusolver_scratch_t *s = (cusolver_scratch_t*)cumo_cuda_thread_local_get(&scratches);
|
|
118
|
+
if (s->done == NULL) {
|
|
119
|
+
cumo_cuda_runtime_check_status(cudaEventCreateWithFlags(&s->done, cudaEventDisableTiming));
|
|
117
120
|
}
|
|
118
|
-
s = &scratch[cumo_cuda_runtime_get_device()];
|
|
119
121
|
if (s->info == NULL) {
|
|
120
|
-
cumo_cuda_runtime_check_status(cudaEventCreateWithFlags(&s->done, cudaEventDisableTiming));
|
|
121
122
|
s->info = (int*)cumo_cuda_runtime_malloc(sizeof(int));
|
|
122
123
|
} else {
|
|
123
124
|
cumo_cuda_runtime_check_status(cudaStreamWaitEvent(cumo_cuda_stream(), s->done, 0));
|
|
@@ -125,6 +126,21 @@ cusolver_scratch(void)
|
|
|
125
126
|
return s;
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
static void
|
|
130
|
+
cusolver_scratch_release(void *entry)
|
|
131
|
+
{
|
|
132
|
+
cusolver_scratch_t *s = (cusolver_scratch_t*)entry;
|
|
133
|
+
if (s->done != NULL) {
|
|
134
|
+
cudaEventSynchronize(s->done);
|
|
135
|
+
cudaEventDestroy(s->done);
|
|
136
|
+
}
|
|
137
|
+
if (s->host_work != NULL) { cudaFreeHost(s->host_work); }
|
|
138
|
+
if (s->work != NULL) { cumo_cuda_runtime_free_no_raise(s->work); }
|
|
139
|
+
if (s->info != NULL) { cumo_cuda_runtime_free_no_raise((char*)s->info); }
|
|
140
|
+
cudaGetLastError();
|
|
141
|
+
memset(s, 0, sizeof(*s));
|
|
142
|
+
}
|
|
143
|
+
|
|
128
144
|
static cumo_cuda_thread_local_t contexts;
|
|
129
145
|
|
|
130
146
|
static cusolver_context_t
|
|
@@ -199,11 +215,38 @@ typedef struct {
|
|
|
199
215
|
char *d_work;
|
|
200
216
|
char *loose_work;
|
|
201
217
|
void *h_work;
|
|
218
|
+
bool h_pinned;
|
|
219
|
+
gesvdjInfo_t gesvdj;
|
|
202
220
|
int *d_info;
|
|
203
221
|
int info;
|
|
204
222
|
int skip_info;
|
|
205
223
|
} cusolver_call_t;
|
|
206
224
|
|
|
225
|
+
static void*
|
|
226
|
+
cusolver_host_work(cusolver_call_t *c, size_t size)
|
|
227
|
+
{
|
|
228
|
+
cusolver_scratch_t *s = c->ctx.scratch;
|
|
229
|
+
|
|
230
|
+
if (size <= CUSOLVER_KEPT_HOST_WORK_MAX && s->host_size < size) {
|
|
231
|
+
size_t grown = s->host_size * 2 > size ? s->host_size * 2 : size;
|
|
232
|
+
if (grown > CUSOLVER_KEPT_HOST_WORK_MAX) grown = CUSOLVER_KEPT_HOST_WORK_MAX;
|
|
233
|
+
cudaFreeHost(s->host_work);
|
|
234
|
+
s->host_work = NULL;
|
|
235
|
+
s->host_size = 0;
|
|
236
|
+
if (cudaHostAlloc((void**)&s->host_work, grown, cudaHostAllocPortable) == cudaSuccess) {
|
|
237
|
+
s->host_size = grown;
|
|
238
|
+
} else {
|
|
239
|
+
s->host_work = NULL;
|
|
240
|
+
cudaGetLastError();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (size <= s->host_size) {
|
|
244
|
+
c->h_pinned = true;
|
|
245
|
+
return s->host_work;
|
|
246
|
+
}
|
|
247
|
+
return ruby_xmalloc(size);
|
|
248
|
+
}
|
|
249
|
+
|
|
207
250
|
static char*
|
|
208
251
|
cusolver_work(cusolver_call_t *c, size_t size)
|
|
209
252
|
{
|
|
@@ -243,7 +286,7 @@ getrf_body(VALUE arg)
|
|
|
243
286
|
c->ctx.handle, c->ctx.params, c->m, c->n, c->dtype, c->a, c->m, c->dtype, &d_size, &h_size));
|
|
244
287
|
c->d_info = c->ctx.scratch->info;
|
|
245
288
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
246
|
-
if (h_size > 0) c->h_work =
|
|
289
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
247
290
|
cumo_cuda_cusolver_check_status(cusolverDnXgetrf(
|
|
248
291
|
c->ctx.handle, c->ctx.params, c->m, c->n, c->dtype, c->a, c->m, c->ipiv,
|
|
249
292
|
c->dtype, c->d_work, d_size, c->h_work, h_size, c->d_info));
|
|
@@ -274,7 +317,7 @@ potrf_body(VALUE arg)
|
|
|
274
317
|
c->ctx.handle, c->ctx.params, c->uplo, c->n, c->dtype, c->a, c->n, c->dtype, &d_size, &h_size));
|
|
275
318
|
c->d_info = c->ctx.scratch->info;
|
|
276
319
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
277
|
-
if (h_size > 0) c->h_work =
|
|
320
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
278
321
|
cumo_cuda_cusolver_check_status(cusolverDnXpotrf(
|
|
279
322
|
c->ctx.handle, c->ctx.params, c->uplo, c->n, c->dtype, c->a, c->n,
|
|
280
323
|
c->dtype, c->d_work, d_size, c->h_work, h_size, c->d_info));
|
|
@@ -347,7 +390,7 @@ syevd_body(VALUE arg)
|
|
|
347
390
|
c->dtype, c->a, c->n, wtype, c->w, c->dtype, &d_size, &h_size));
|
|
348
391
|
}
|
|
349
392
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
350
|
-
if (h_size > 0) c->h_work =
|
|
393
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
351
394
|
if (c->range) {
|
|
352
395
|
cumo_cuda_cusolver_check_status(cusolverDnXsyevdx(
|
|
353
396
|
c->ctx.handle, c->ctx.params, c->jobz, CUSOLVER_EIG_RANGE_I, CUBLAS_FILL_MODE_UPPER, c->n,
|
|
@@ -421,7 +464,7 @@ gesvd_body(VALUE arg)
|
|
|
421
464
|
stype, c->w, c->dtype, c->u, c->m, c->dtype, c->vt, ldvt, c->dtype, &d_size, &h_size));
|
|
422
465
|
c->d_info = c->ctx.scratch->info;
|
|
423
466
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
424
|
-
if (h_size > 0) c->h_work =
|
|
467
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
425
468
|
cumo_cuda_cusolver_check_status(cusolverDnXgesvd(
|
|
426
469
|
c->ctx.handle, c->ctx.params, c->job, c->job, c->m, c->n, c->dtype, c->a, c->m,
|
|
427
470
|
stype, c->w, c->dtype, c->u, c->m, c->dtype, c->vt, ldvt, c->dtype,
|
|
@@ -430,6 +473,91 @@ gesvd_body(VALUE arg)
|
|
|
430
473
|
return Qnil;
|
|
431
474
|
}
|
|
432
475
|
|
|
476
|
+
#define CUSOLVER_BATCHED_SVD_MAX 32
|
|
477
|
+
#define CUSOLVER_BATCHED_SVD_UV_MAX ((size_t)64 << 20)
|
|
478
|
+
|
|
479
|
+
static size_t
|
|
480
|
+
align_up(size_t size)
|
|
481
|
+
{
|
|
482
|
+
return (size + 255) & ~(size_t)255;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
static VALUE
|
|
486
|
+
gesvdj_batched_body(VALUE arg)
|
|
487
|
+
{
|
|
488
|
+
cusolver_call_t *c = (cusolver_call_t*)arg;
|
|
489
|
+
cusolverDnHandle_t h = c->ctx.handle;
|
|
490
|
+
int m = (int)c->m;
|
|
491
|
+
int n = (int)c->n;
|
|
492
|
+
int64_t k = m < n ? m : n;
|
|
493
|
+
int64_t done;
|
|
494
|
+
int chunk;
|
|
495
|
+
int lwork = 0;
|
|
496
|
+
size_t elsize;
|
|
497
|
+
size_t welsize;
|
|
498
|
+
size_t work_bytes;
|
|
499
|
+
size_t u_bytes;
|
|
500
|
+
size_t v_bytes;
|
|
501
|
+
char *buf;
|
|
502
|
+
int *d_infos;
|
|
503
|
+
int *infos;
|
|
504
|
+
int64_t i;
|
|
505
|
+
|
|
506
|
+
switch (c->dtype) {
|
|
507
|
+
case CUDA_R_32F: elsize = sizeof(float); welsize = sizeof(float); break;
|
|
508
|
+
case CUDA_R_64F: elsize = sizeof(double); welsize = sizeof(double); break;
|
|
509
|
+
case CUDA_C_32F: elsize = sizeof(cuComplex); welsize = sizeof(float); break;
|
|
510
|
+
default: elsize = sizeof(cuDoubleComplex); welsize = sizeof(double); break;
|
|
511
|
+
}
|
|
512
|
+
chunk = (int)(CUSOLVER_BATCHED_SVD_UV_MAX / (elsize * ((size_t)m * m + (size_t)n * n)));
|
|
513
|
+
if (chunk < 1) chunk = 1;
|
|
514
|
+
if ((int64_t)chunk > c->k) chunk = (int)c->k;
|
|
515
|
+
|
|
516
|
+
check_call(cusolverDnCreateGesvdjInfo(&c->gesvdj));
|
|
517
|
+
switch (c->dtype) {
|
|
518
|
+
#define GESVDJ_BUFFER_SIZE(fn, type, rtype) \
|
|
519
|
+
check_call(cusolverDn##fn##_bufferSize(h, CUSOLVER_EIG_MODE_NOVECTOR, m, n, (type*)c->a, m, \
|
|
520
|
+
(rtype*)c->w, NULL, m, NULL, n, &lwork, c->gesvdj, chunk)); \
|
|
521
|
+
break
|
|
522
|
+
case CUDA_R_32F: GESVDJ_BUFFER_SIZE(SgesvdjBatched, float, float);
|
|
523
|
+
case CUDA_R_64F: GESVDJ_BUFFER_SIZE(DgesvdjBatched, double, double);
|
|
524
|
+
case CUDA_C_32F: GESVDJ_BUFFER_SIZE(CgesvdjBatched, cuComplex, float);
|
|
525
|
+
default: GESVDJ_BUFFER_SIZE(ZgesvdjBatched, cuDoubleComplex, double);
|
|
526
|
+
#undef GESVDJ_BUFFER_SIZE
|
|
527
|
+
}
|
|
528
|
+
work_bytes = align_up(elsize * (size_t)(lwork > 0 ? lwork : 1));
|
|
529
|
+
u_bytes = align_up(elsize * (size_t)m * m * chunk);
|
|
530
|
+
v_bytes = align_up(elsize * (size_t)n * n * chunk);
|
|
531
|
+
buf = cusolver_work(c, work_bytes + u_bytes + v_bytes + sizeof(int) * (size_t)c->k);
|
|
532
|
+
d_infos = (int*)(buf + work_bytes + u_bytes + v_bytes);
|
|
533
|
+
for (done = 0; done < c->k; done += chunk) {
|
|
534
|
+
int batch = (int)(c->k - done < chunk ? c->k - done : chunk);
|
|
535
|
+
char *a = (char*)c->a + elsize * (size_t)m * n * done;
|
|
536
|
+
char *w = (char*)c->w + welsize * (size_t)k * done;
|
|
537
|
+
switch (c->dtype) {
|
|
538
|
+
#define GESVDJ_BATCHED(fn, type, rtype) \
|
|
539
|
+
cumo_cuda_cusolver_check_status(cusolverDn##fn(h, CUSOLVER_EIG_MODE_NOVECTOR, m, n, \
|
|
540
|
+
(type*)a, m, (rtype*)w, (type*)(buf + work_bytes), m, \
|
|
541
|
+
(type*)(buf + work_bytes + u_bytes), n, (type*)buf, lwork, d_infos + done, \
|
|
542
|
+
c->gesvdj, batch)); \
|
|
543
|
+
break
|
|
544
|
+
case CUDA_R_32F: GESVDJ_BATCHED(SgesvdjBatched, float, float);
|
|
545
|
+
case CUDA_R_64F: GESVDJ_BATCHED(DgesvdjBatched, double, double);
|
|
546
|
+
case CUDA_C_32F: GESVDJ_BATCHED(CgesvdjBatched, cuComplex, float);
|
|
547
|
+
default: GESVDJ_BATCHED(ZgesvdjBatched, cuDoubleComplex, double);
|
|
548
|
+
#undef GESVDJ_BATCHED
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
infos = ruby_xmalloc(sizeof(int) * (size_t)c->k);
|
|
552
|
+
c->h_work = infos;
|
|
553
|
+
cumo_cuda_runtime_check_status(cumo_cuda_runtime_memcpy_to_host(infos, d_infos, sizeof(int) * (size_t)c->k));
|
|
554
|
+
c->info = 0;
|
|
555
|
+
for (i = 0; i < c->k && c->info == 0; i++) {
|
|
556
|
+
c->info = infos[i];
|
|
557
|
+
}
|
|
558
|
+
return Qnil;
|
|
559
|
+
}
|
|
560
|
+
|
|
433
561
|
static VALUE
|
|
434
562
|
geqrf_body(VALUE arg)
|
|
435
563
|
{
|
|
@@ -442,7 +570,7 @@ geqrf_body(VALUE arg)
|
|
|
442
570
|
&d_size, &h_size));
|
|
443
571
|
c->d_info = c->ctx.scratch->info;
|
|
444
572
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
445
|
-
if (h_size > 0) c->h_work =
|
|
573
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
446
574
|
cumo_cuda_cusolver_check_status(cusolverDnXgeqrf(
|
|
447
575
|
c->ctx.handle, c->ctx.params, c->m, c->n, c->dtype, c->a, c->m, c->dtype, c->tau, c->dtype,
|
|
448
576
|
c->d_work, d_size, c->h_work, h_size, c->d_info));
|
|
@@ -483,7 +611,13 @@ call_ensure(VALUE arg)
|
|
|
483
611
|
cusolver_call_t *c = (cusolver_call_t*)arg;
|
|
484
612
|
if (c->ctx.scratch != NULL) { cudaEventRecord(c->ctx.scratch->done, cumo_cuda_stream()); }
|
|
485
613
|
cumo_cuda_runtime_return_scratch(c->loose_work, c->loose_work != NULL, NULL);
|
|
486
|
-
|
|
614
|
+
if (c->h_pinned) {
|
|
615
|
+
cudaStreamSynchronize(cumo_cuda_stream());
|
|
616
|
+
cudaGetLastError();
|
|
617
|
+
} else {
|
|
618
|
+
ruby_xfree(c->h_work);
|
|
619
|
+
}
|
|
620
|
+
if (c->gesvdj != NULL) { cusolverDnDestroyGesvdjInfo(c->gesvdj); }
|
|
487
621
|
return Qnil;
|
|
488
622
|
}
|
|
489
623
|
|
|
@@ -649,13 +783,14 @@ check_square_matrix(VALUE a, const char *name)
|
|
|
649
783
|
Factorizes a Hermitian positive definite matrix in place as A = U^H U or
|
|
650
784
|
A = L L^H with cusolverDnXpotrf.
|
|
651
785
|
|
|
652
|
-
@
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
786
|
+
@overload potrf(a, uplo, want_info = true)
|
|
787
|
+
@param a [Cumo::SFloat, Cumo::DFloat, Cumo::SComplex, Cumo::DComplex]
|
|
788
|
+
contiguous, of shape [n, n]: the column-major matrix, whose uplo
|
|
789
|
+
triangle is overwritten with the factor
|
|
790
|
+
@param uplo [String] "U" or "L"
|
|
791
|
+
@param want_info [Boolean] whether to wait for the info cuSOLVER reports,
|
|
792
|
+
true by default
|
|
793
|
+
@return [Integer, nil] the info cuSOLVER reports, or nil if it is not read
|
|
659
794
|
*/
|
|
660
795
|
static VALUE
|
|
661
796
|
rb_cusolver_potrf(int argc, VALUE *argv, VALUE self)
|
|
@@ -916,6 +1051,35 @@ rb_cusolver_gesvd(VALUE self, VALUE a, VALUE s, VALUE u, VALUE vt, VALUE job)
|
|
|
916
1051
|
return INT2NUM(c.info);
|
|
917
1052
|
}
|
|
918
1053
|
|
|
1054
|
+
static VALUE
|
|
1055
|
+
rb_cusolver_gesvdj_batched(VALUE self, VALUE a, VALUE s)
|
|
1056
|
+
{
|
|
1057
|
+
cusolver_call_t c = {0};
|
|
1058
|
+
cumo_narray_t *na;
|
|
1059
|
+
cumo_narray_t *ns;
|
|
1060
|
+
|
|
1061
|
+
na = check_contiguous_array(a, Qnil, 3, "a");
|
|
1062
|
+
c.dtype = cusolver_dtype(a);
|
|
1063
|
+
c.k = (int64_t)CUMO_NA_SHAPE(na)[0];
|
|
1064
|
+
c.n = (int64_t)CUMO_NA_SHAPE(na)[1];
|
|
1065
|
+
c.m = (int64_t)CUMO_NA_SHAPE(na)[2];
|
|
1066
|
+
if (c.m > CUSOLVER_BATCHED_SVD_MAX || c.n > CUSOLVER_BATCHED_SVD_MAX) {
|
|
1067
|
+
rb_raise(cumo_na_eShapeError, "a must have at most %d rows and columns", CUSOLVER_BATCHED_SVD_MAX);
|
|
1068
|
+
}
|
|
1069
|
+
ns = check_contiguous_array(s, eigen_real_class(c.dtype), 2, "s");
|
|
1070
|
+
if ((int64_t)CUMO_NA_SHAPE(ns)[0] != c.k || (int64_t)CUMO_NA_SHAPE(ns)[1] != (c.m < c.n ? c.m : c.n)) {
|
|
1071
|
+
rb_raise(cumo_na_eShapeError, "s must have the shape [%"PRId64", %"PRId64"]", c.k, c.m < c.n ? c.m : c.n);
|
|
1072
|
+
}
|
|
1073
|
+
if (c.k == 0 || c.m == 0 || c.n == 0) {
|
|
1074
|
+
return INT2FIX(0);
|
|
1075
|
+
}
|
|
1076
|
+
c.a = cumo_na_get_offset_pointer_for_read_write(a);
|
|
1077
|
+
c.w = cumo_na_get_offset_pointer_for_write(s);
|
|
1078
|
+
c.ctx = cusolver_context();
|
|
1079
|
+
rb_ensure(gesvdj_batched_body, (VALUE)&c, call_ensure, (VALUE)&c);
|
|
1080
|
+
return INT2NUM(c.info);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
919
1083
|
static int64_t
|
|
920
1084
|
check_tau(VALUE tau, VALUE a, int64_t k)
|
|
921
1085
|
{
|
|
@@ -1006,7 +1170,7 @@ geev_body(VALUE arg)
|
|
|
1006
1170
|
wtype, c->w, c->dtype, NULL, c->n, c->dtype, c->u, c->n, c->dtype, &d_size, &h_size));
|
|
1007
1171
|
c->d_info = c->ctx.scratch->info;
|
|
1008
1172
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
1009
|
-
if (h_size > 0) c->h_work =
|
|
1173
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
1010
1174
|
cumo_cuda_cusolver_check_status(cusolverDnXgeev(
|
|
1011
1175
|
c->ctx.handle, c->ctx.params, CUSOLVER_EIG_MODE_NOVECTOR, c->jobz, c->n, c->dtype, c->a, c->n,
|
|
1012
1176
|
wtype, c->w, c->dtype, NULL, c->n, c->dtype, c->u, c->n, c->dtype,
|
|
@@ -1082,7 +1246,7 @@ sytrf_body(VALUE arg)
|
|
|
1082
1246
|
c->ctx.handle, c->ctx.params, c->uplo, c->n, c->dtype, c->a, c->n, c->ipiv, c->dtype,
|
|
1083
1247
|
&d_size, &h_size));
|
|
1084
1248
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
1085
|
-
if (h_size > 0) c->h_work =
|
|
1249
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
1086
1250
|
cumo_cuda_cusolver_check_status(cusolverDnXhetrf(
|
|
1087
1251
|
c->ctx.handle, c->ctx.params, c->uplo, c->n, c->dtype, c->a, c->n, c->ipiv, c->dtype,
|
|
1088
1252
|
c->d_work, d_size, c->h_work, h_size, c->d_info));
|
|
@@ -1095,7 +1259,7 @@ sytrf_body(VALUE arg)
|
|
|
1095
1259
|
c->ctx.handle, c->ctx.params, c->uplo, c->n, c->dtype, c->a, c->n, c->ipiv, c->dtype,
|
|
1096
1260
|
&d_size, &h_size));
|
|
1097
1261
|
if (d_size > 0) c->d_work = cusolver_work(c, d_size);
|
|
1098
|
-
if (h_size > 0) c->h_work =
|
|
1262
|
+
if (h_size > 0) c->h_work = cusolver_host_work(c, h_size);
|
|
1099
1263
|
cumo_cuda_cusolver_check_status(cusolverDnXsytrf(
|
|
1100
1264
|
c->ctx.handle, c->ctx.params, c->uplo, c->n, c->dtype, c->a, c->n, c->ipiv, c->dtype,
|
|
1101
1265
|
c->d_work, d_size, c->h_work, h_size, c->d_info));
|
|
@@ -1212,6 +1376,8 @@ Init_cumo_cuda_cusolver(void)
|
|
|
1212
1376
|
rb_define_singleton_method(mCusolver, "available?", rb_cusolver_available_p, 0);
|
|
1213
1377
|
#ifdef CUSOLVER_FOUND
|
|
1214
1378
|
cumo_cuda_thread_local_init(&contexts, sizeof(cusolver_context_t));
|
|
1379
|
+
cumo_cuda_thread_local_init(&scratches, sizeof(cusolver_scratch_t));
|
|
1380
|
+
cumo_cuda_thread_local_on_exit(&scratches, cusolver_scratch_release);
|
|
1215
1381
|
rb_define_singleton_method(mCusolver, "version", rb_cusolver_version, 0);
|
|
1216
1382
|
rb_define_singleton_method(mCusolver, "getrf", rb_cusolver_getrf, 1);
|
|
1217
1383
|
rb_define_singleton_method(mCusolver, "getrs", rb_cusolver_getrs, -1);
|
|
@@ -1222,6 +1388,8 @@ Init_cumo_cuda_cusolver(void)
|
|
|
1222
1388
|
rb_define_singleton_method(mCusolver, "syevd", rb_cusolver_syevd, 5);
|
|
1223
1389
|
rb_define_singleton_method(mCusolver, "sygvd", rb_cusolver_sygvd, 6);
|
|
1224
1390
|
rb_define_singleton_method(mCusolver, "gesvd", rb_cusolver_gesvd, 5);
|
|
1391
|
+
rb_define_singleton_method(mCusolver, "gesvdj_batched", rb_cusolver_gesvdj_batched, 2);
|
|
1392
|
+
rb_define_const(mCusolver, "BATCHED_SVD_MAX", INT2FIX(CUSOLVER_BATCHED_SVD_MAX));
|
|
1225
1393
|
rb_define_singleton_method(mCusolver, "geqrf", rb_cusolver_geqrf, 2);
|
|
1226
1394
|
rb_define_singleton_method(mCusolver, "orgqr", rb_cusolver_orgqr, 2);
|
|
1227
1395
|
rb_define_singleton_method(mCusolver, "sytrf", rb_cusolver_sytrf, 3);
|
|
@@ -1229,8 +1397,9 @@ Init_cumo_cuda_cusolver(void)
|
|
|
1229
1397
|
rb_define_singleton_method(mCusolver, "geev", rb_cusolver_geev, 3);
|
|
1230
1398
|
rb_funcall(mCusolver, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("geev")));
|
|
1231
1399
|
#endif
|
|
1232
|
-
rb_funcall(mCusolver, rb_intern("private_class_method"),
|
|
1400
|
+
rb_funcall(mCusolver, rb_intern("private_class_method"), 13,
|
|
1233
1401
|
ID2SYM(rb_intern("sytrf")), ID2SYM(rb_intern("geqrf")), ID2SYM(rb_intern("orgqr")), ID2SYM(rb_intern("gesvd")),
|
|
1402
|
+
ID2SYM(rb_intern("gesvdj_batched")),
|
|
1234
1403
|
ID2SYM(rb_intern("syevd")), ID2SYM(rb_intern("sygvd")), ID2SYM(rb_intern("uplo")),
|
|
1235
1404
|
ID2SYM(rb_intern("getrf")), ID2SYM(rb_intern("getrs")),
|
|
1236
1405
|
ID2SYM(rb_intern("potrf")), ID2SYM(rb_intern("potrs")), ID2SYM(rb_intern("potri")));
|