cumo 0.14.0 → 0.15.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 +35 -1
- data/README.md +24 -0
- data/Rakefile +32 -1
- data/ext/cumo/cuda/cub.cu +26 -0
- data/ext/cumo/extconf.rb +1 -1
- data/ext/cumo/include/cumo/cuda/runtime.h +3 -2
- data/ext/cumo/include/cumo/ndloop.h +7 -0
- data/ext/cumo/{narray/sort_kernel.cu → include/cumo/sort_kernel.h} +15 -15
- data/ext/cumo/include/cumo/template_kernel.h +2 -0
- data/ext/cumo/narray/data.c +3 -0
- data/ext/cumo/narray/gen/cogen_kernel.rb +19 -10
- data/ext/cumo/narray/gen/kernel_parts.rb +5 -3
- data/ext/cumo/narray/gen/spec.rb +4 -0
- data/ext/cumo/narray/gen/tmpl/accum_arg_kernel.cu +2 -2
- data/ext/cumo/narray/gen/tmpl/accum_binary_kernel.cu +1 -1
- data/ext/cumo/narray/gen/tmpl/accum_index_kernel.cu +2 -2
- data/ext/cumo/narray/gen/tmpl/binary.c +50 -0
- data/ext/cumo/narray/gen/tmpl/binary_kernel.cu +24 -0
- data/ext/cumo/narray/gen/tmpl/complex_accum_kernel.cu +17 -3
- data/ext/cumo/narray/gen/tmpl/cum_kernel.cu +2 -0
- data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +15 -3
- data/ext/cumo/narray/gen/tmpl/map_with_index.c +18 -0
- data/ext/cumo/narray/gen/tmpl/real_accum_kernel.cu +19 -1
- data/ext/cumo/narray/gen/tmpl/sort_kernel.cu +19 -0
- data/ext/cumo/narray/gen/tmpl/unary.c +8 -0
- data/ext/cumo/narray/index.c +98 -82
- data/ext/cumo/narray/narray.c +10 -0
- data/ext/cumo/narray/ndloop.c +141 -16
- data/ext/cumo/narray/step.c +0 -2
- data/lib/cumo/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6fcb0462dc2821749f43c243267e8eef32c5362d2a647769c3f93ccc048ddd0
|
|
4
|
+
data.tar.gz: 131ec1045f331591fb3f1c522824ea1e14c56fad40091bccacde73bb7f64a649
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfbb78f6f9ea625ae2848210722aa58106e6efd80af31d38e239585def253b7fb0e00426d18804e4177040492469d3498eaf61dca0cb7880ee482bd1c9669d0e
|
|
7
|
+
data.tar.gz: 80c944b3b2a544c593a221c9600c2a8cc441b273e37dc77f3ca1bbb738e381e1fcc0db42cbc66265f6d75832ee0ca396b008ffec7ff666549db313d386b82e81
|
data/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,42 @@
|
|
|
1
|
+
# 0.15.0 (2026/11/02)
|
|
2
|
+
|
|
3
|
+
Breaking changes:
|
|
4
|
+
|
|
5
|
+
* A subscript of an empty array is read as it is for any other array, where every subscript of an empty array raised `Cumo::NArray::ShapeError`. `a[true, 1]` of a 0 x 3 array answers an empty view, and a subscript that names an element raises as it does for any array, so `a[0]` raises `IndexError`. An empty range now selects nothing when it starts where an element could be inserted, as with `Array#[]`, so `b[2...2, true]` of a 2 x 3 array answers a 0 x 3 view where it raised `RangeError`. The README lists where this differs from Numo (PR #641)
|
|
6
|
+
* `Cumo::RObject` no longer has `store_binary`, `to_string`, `hton` or `Cumo::RObject.from_string`, and `set` with a String raises `NoMethodError` for it. They read or wrote the object references of an RObject as raw bytes, so the next garbage collection could crash, and `to_string` gave out heap addresses. Calling the methods of `Cumo::NArray` on an RObject through `bind_call` raises `TypeError` (PR #638)
|
|
7
|
+
|
|
8
|
+
Fixes:
|
|
9
|
+
|
|
10
|
+
* Fix `require "cumo"` under `ruby -w` warning "method redefined; discarding old %". Cumo no longer defines `Range#%` again, which Ruby has had since 2.6 and which works the same (PR #643)
|
|
11
|
+
* Fix a crash, possible since 0.7.0, when storing an Array whose NArray row of another type is followed by a row that raises, such as one with the wrong number of dimensions. The garbage collector could free the cast copy of the row before the store let go of it (PR #642)
|
|
12
|
+
* Fix a range with a negative step and an excluded or missing end selecting the wrong elements: `(4...1).step(-1)` selected 5 elements of a 5-element array where it should select 3, and `(3..).step(-1)` none. Fix a stepped range that selects nothing returning elements, as `(1..0).step(2)` returned one and `(3...3).step(-1)` two (PR #641)
|
|
13
|
+
* Fix `to_a` and `format_to_a` aborting when Cumo is compiled with `RUBY_DEBUG` against a Ruby whose headers check the index of `RARRAY_AREF`, as Ruby master does since ruby/ruby@61261bf5c4 (PR #640)
|
|
14
|
+
|
|
15
|
+
Changes:
|
|
16
|
+
|
|
17
|
+
* CI builds against CUDA 13.4.3 on Ubuntu 26.04 where it built against 13.4.1 on Ubuntu 24.04, and the CUDA 12.9.2 job builds for sm_121 where it built for sm_120 (PR #639)
|
|
18
|
+
* The first `sort`, `median` or `sort_index` of a type loads the sort kernels of that type alone, where the first of a process loaded those of all twelve types. On SFloat the first `sort` is about 5.7 times faster, `median` about 9 times and `sort_index` about 3 times (PR #636)
|
|
19
|
+
* The first `cumsum` or `cumprod` of a process no longer loads every sort kernel, which makes the first SFloat `cumsum` about 2.1 times faster and keeps the peak RSS 57 MB lower (PR #635)
|
|
20
|
+
* `sum`, `mean`, `max`, `min` and the `dot` of two vectors have a kernel module of their own, so the first of them on a type no longer loads every reduction of the type. The first SFloat `sum` or vector `dot` of a process is about 8.6 times faster (PR #634)
|
|
21
|
+
|
|
22
|
+
# 0.14.1 (2026/10/22)
|
|
23
|
+
|
|
24
|
+
Fixes:
|
|
25
|
+
|
|
26
|
+
* Fix a host loop such as `each` yielding the old values of an array after its block wrote the array through `store_binary`, an in-place `cumsum` or `cumprod`, or an in-place `map` or `map_with_index`, also one paused by an Enumerator (PR #631, PR #630)
|
|
27
|
+
* Fix an in-place `map_with_index` over a view that reaches an element more than once, such as `x[[0, 0, 0]]`, reading the element as it was before its own write. It now reads its own write, as `map` and numo do (PR #631)
|
|
28
|
+
* Fix the release gem recording the tag of the previous release as `Cumo::REVISION`, as the 0.14.0 gem does with `"v0.13.0-11-gafd8ead9"`. `rake release` now makes the tag before it builds the gem, so this gem gives `"v0.14.1"` (PR #626)
|
|
29
|
+
|
|
30
|
+
Changes:
|
|
31
|
+
|
|
32
|
+
* `+`, `-`, `*` and `/` between a complex array and a real array of the same precision, in either order, read the real array as it is rather than casting it to a complex array first. On 4M elements this makes SComplex with SFloat about 1.7 to 1.8 times faster, and DComplex divided by DFloat about 1.4 times. The answers are the same but for the sign of a NaN (PR #632)
|
|
33
|
+
* A host loop such as `each` whose block writes to the device copies the rest of the row, or of the array, again at once when copying the elements one at a time would cost more. With one write early in an `each_with_index` over 100,000 elements, the loop is about 90 times faster and about as fast as with no write. With a write at every 100th element it is about 12 times faster, and with a write at every other element about 16% slower (PR #631)
|
|
34
|
+
|
|
1
35
|
# 0.14.0 (2026/10/18)
|
|
2
36
|
|
|
3
37
|
Breaking changes:
|
|
4
38
|
|
|
5
|
-
* `cumo.h` no longer defines `CUMO_VERSION` or `CUMO_VERSION_CODE`. `Cumo::VERSION` and `Cumo::NArray::VERSION` are defined in Ruby
|
|
39
|
+
* `cumo.h` no longer defines `CUMO_VERSION` or `CUMO_VERSION_CODE`. `Cumo::VERSION` and `Cumo::NArray::VERSION` are defined in Ruby. The new `Cumo::REVISION` tells a release gem from one built from a checkout. A release gives its tag, and a gem built at a later commit gives something like `"v0.14.0-3-g1a2b3c4d"`. The 0.14.0 gem was built before its tag was made, so it gives `"v0.13.0-11-gafd8ead9"`. `rake release` makes the tag before the gem from the next release on (PR #617, PR #626)
|
|
6
40
|
|
|
7
41
|
Fixes:
|
|
8
42
|
|
data/README.md
CHANGED
|
@@ -198,6 +198,30 @@ Cumo::DFloat.new(1, 3).seq.transpose.contiguous? #=> true
|
|
|
198
198
|
Code that runs against both libraries should not read `contiguous?` and expect the same answer.
|
|
199
199
|
Where it wants a contiguous array it can ask for one, since `dup` answers one in either library.
|
|
200
200
|
|
|
201
|
+
#### Subscripts That Select Nothing
|
|
202
|
+
|
|
203
|
+
Numo raises `ShapeError` for every subscript of an empty array.
|
|
204
|
+
Cumo returns the empty view numpy does, and raises only for a subscript that names an element.
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
a = Cumo::DFloat.new(0, 3)
|
|
208
|
+
a[true, 1].shape #=> [0], where Numo raises ShapeError
|
|
209
|
+
a[0] # raises IndexError, where Numo raises ShapeError
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
A range that selects nothing only has to start where an element could be inserted, as with `Array#[]`.
|
|
213
|
+
Numo raises `RangeError` when such a range starts at either end of an axis.
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
b = Cumo::DFloat.new(2, 3).seq
|
|
217
|
+
b[2...2, true].shape #=> [0, 3], where Numo raises RangeError
|
|
218
|
+
b[3...3, true] # raises RangeError in both
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
A stepped range that selects nothing also selects nothing in Cumo.
|
|
222
|
+
Numo returns one element for `(1..0).step(2)` and two for `(3...3).step(-1)`.
|
|
223
|
+
`compatible_mode` does not change any of this.
|
|
224
|
+
|
|
201
225
|
### Keeping Scalars On The Device
|
|
202
226
|
|
|
203
227
|
The 0-dimensional return is what lets an iterative loop stay on the GPU.
|
data/Rakefile
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
4
|
require "rake/testtask"
|
|
5
|
+
require "rubygems/package"
|
|
6
|
+
|
|
7
|
+
Rake::Task["release"].clear
|
|
8
|
+
desc "Tag the version, build the gem at the tag, and push the branch, the tag and the gem"
|
|
9
|
+
task :release, [:remote] do |_, args|
|
|
10
|
+
git = ->(*argv) { IO.popen(["git", *argv], err: File::NULL, &:read).strip }
|
|
11
|
+
version = File.read(File.join(__dir__, "lib/cumo/version.rb"))[/VERSION = "([^"]+)"/, 1]
|
|
12
|
+
tag = "v#{version}"
|
|
13
|
+
gem_file = "pkg/cumo-#{version}.gem"
|
|
14
|
+
remote = args[:remote] || "origin"
|
|
15
|
+
raise "There are files that need to be committed first." unless system("git", "diff", "--quiet") && system("git", "diff-index", "--quiet", "--cached", "HEAD")
|
|
16
|
+
|
|
17
|
+
tagged = git.call("rev-parse", "-q", "--verify", "#{tag}^{commit}")
|
|
18
|
+
raise "#{tag} is on #{tagged[0, 8]}, not on HEAD." unless tagged.empty? || tagged == git.call("rev-parse", "HEAD")
|
|
19
|
+
|
|
20
|
+
sh "git", "tag", "-m", "Version #{version}", tag if tagged.empty?
|
|
21
|
+
begin
|
|
22
|
+
mkdir_p "pkg"
|
|
23
|
+
sh "gem", "build", "cumo.gemspec", "--output", gem_file
|
|
24
|
+
revision = Gem::Package.new(gem_file).spec.metadata["cumo_revision"]
|
|
25
|
+
raise "#{gem_file} records #{revision.inspect} as cumo_revision, not #{tag.inspect}." unless revision == tag
|
|
26
|
+
rescue StandardError
|
|
27
|
+
sh "git", "tag", "-d", tag if tagged.empty?
|
|
28
|
+
raise
|
|
29
|
+
end
|
|
30
|
+
sh "git", "push", remote, "HEAD"
|
|
31
|
+
sh "git", "push", remote, "refs/tags/#{tag}"
|
|
32
|
+
sh "gem", "push", gem_file unless ENV["gem_push"] == "no"
|
|
33
|
+
end
|
|
5
34
|
|
|
6
35
|
Rake::TestTask.new(:test) do |t|
|
|
7
36
|
t.libs << "test"
|
|
@@ -10,7 +39,9 @@ Rake::TestTask.new(:test) do |t|
|
|
|
10
39
|
end
|
|
11
40
|
|
|
12
41
|
require "rake/extensiontask"
|
|
13
|
-
Rake::ExtensionTask.new("cumo")
|
|
42
|
+
ext = Rake::ExtensionTask.new("cumo")
|
|
43
|
+
# The Makefile lists an object for each kernel part, so a new part needs extconf.rb to run again.
|
|
44
|
+
file "#{ext.tmp_dir}/#{ext.platform}/#{ext.name}/#{RUBY_VERSION}/Makefile" => "ext/cumo/narray/gen/kernel_parts.rb"
|
|
14
45
|
|
|
15
46
|
desc 'Build the C++ memory pool test harness without running it (running it needs a GPU)'
|
|
16
47
|
task :build_ctest do
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#include <cub/util_device.cuh>
|
|
2
|
+
#include "cumo/template_kernel.h"
|
|
3
|
+
|
|
4
|
+
namespace {
|
|
5
|
+
|
|
6
|
+
__global__ void cumo_cub_ptx_version_probe() {}
|
|
7
|
+
|
|
8
|
+
} // namespace
|
|
9
|
+
|
|
10
|
+
// CUB learns each device's PTX version once, from the attributes of an empty
|
|
11
|
+
// kernel. Each translation unit has its own empty kernel, but the link keeps
|
|
12
|
+
// one copy of the code that asks. The query loads the module that copy came
|
|
13
|
+
// from, which can be a large one the caller never runs. This module has one
|
|
14
|
+
// kernel built with the same flags, so it gives the same version at little cost.
|
|
15
|
+
extern "C" void
|
|
16
|
+
cumo_cuda_cub_prime_ptx_version(void)
|
|
17
|
+
{
|
|
18
|
+
cub::GetPerDeviceAttributeCache<cub::PtxVersionCacheTag>()(
|
|
19
|
+
[](int& ptx_version) {
|
|
20
|
+
cudaFuncAttributes attrs = {};
|
|
21
|
+
cudaError_t status = cudaFuncGetAttributes(&attrs, (const void*)cumo_cub_ptx_version_probe);
|
|
22
|
+
ptx_version = attrs.ptxVersion * 10;
|
|
23
|
+
return status;
|
|
24
|
+
},
|
|
25
|
+
cub::CurrentDevice());
|
|
26
|
+
}
|
data/ext/cumo/extconf.rb
CHANGED
|
@@ -55,7 +55,6 @@ narray/ndloop
|
|
|
55
55
|
narray/ndloop_kernel
|
|
56
56
|
narray/data
|
|
57
57
|
narray/data_kernel
|
|
58
|
-
narray/sort_kernel
|
|
59
58
|
narray/math
|
|
60
59
|
narray/SFMT
|
|
61
60
|
narray/struct
|
|
@@ -70,6 +69,7 @@ cuda/cudnn
|
|
|
70
69
|
cuda/cudnn_impl
|
|
71
70
|
cuda/cusolver
|
|
72
71
|
cuda/cufft
|
|
72
|
+
cuda/cub
|
|
73
73
|
)
|
|
74
74
|
%w[bit int8 int16 int32 int64 uint8 uint16 uint32 uint64 hfloat bfloat sfloat dfloat scomplex dcomplex robject].each do |type_name|
|
|
75
75
|
srcs << "narray/types/#{type_name}"
|
|
@@ -33,10 +33,11 @@ extern size_t cumo_cuda_sync_epoch;
|
|
|
33
33
|
// and reads again once the count moves.
|
|
34
34
|
extern size_t cumo_cuda_launch_epoch;
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// Answers the count before the write.
|
|
37
|
+
static inline size_t
|
|
37
38
|
cumo_cuda_runtime_note_device_write(void)
|
|
38
39
|
{
|
|
39
|
-
cumo_atomic_size_fetch_add(&cumo_cuda_launch_epoch, 1);
|
|
40
|
+
return cumo_atomic_size_fetch_add(&cumo_cuda_launch_epoch, 1);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// A pinned host buffer for reading device memory back: a copy into pinned
|
|
@@ -104,6 +104,13 @@ typedef struct {
|
|
|
104
104
|
// it will read next again if device memory was written since it was staged.
|
|
105
105
|
void cumo_na_ndloop_refresh_next(cumo_na_loop_t *lp, const void *next, size_t bytes);
|
|
106
106
|
|
|
107
|
+
// For a function that yields to Ruby and writes an array that was there
|
|
108
|
+
// before it, which cumo_na_ndloop_writes_existing answers: counts the element
|
|
109
|
+
// it just wrote, so that a loop it yields to before it ends reads it. A staged
|
|
110
|
+
// copy of its own has to hold the element already.
|
|
111
|
+
int cumo_na_ndloop_writes_existing(cumo_na_loop_t *lp);
|
|
112
|
+
void cumo_na_ndloop_wrote(cumo_na_loop_t *lp);
|
|
113
|
+
|
|
107
114
|
// spec of user function
|
|
108
115
|
typedef struct {
|
|
109
116
|
cumo_na_iter_func_t func; // user function
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
#ifndef CUMO_SORT_KERNEL_H
|
|
2
|
+
#define CUMO_SORT_KERNEL_H
|
|
3
|
+
|
|
1
4
|
#include "cumo/narray_kernel.h"
|
|
2
5
|
#include "cumo/indexer.h"
|
|
3
6
|
#include "cumo/template_kernel.h"
|
|
@@ -146,6 +149,7 @@ cudaError_t sort_pairs(const Key* kin, Key* kout, const Value* vin, Value* vout,
|
|
|
146
149
|
int64_t total, int64_t n_rows, int64_t row_len) {
|
|
147
150
|
size_t bytes = 0;
|
|
148
151
|
cudaError_t st = cudaSuccess;
|
|
152
|
+
cumo_cuda_cub_prime_ptx_version();
|
|
149
153
|
if (n_rows == 1) {
|
|
150
154
|
st = cub::DeviceRadixSort::SortPairs(nullptr, bytes, kin, kout, vin, vout, total, 0, sizeof(Key) * 8, cumo_cuda_stream());
|
|
151
155
|
if (st != cudaSuccess) { return st; }
|
|
@@ -168,6 +172,7 @@ template <typename Key>
|
|
|
168
172
|
cudaError_t sort_keys(const Key* kin, Key* kout, int64_t total, int64_t n_rows, int64_t row_len) {
|
|
169
173
|
size_t bytes = 0;
|
|
170
174
|
cudaError_t st = cudaSuccess;
|
|
175
|
+
cumo_cuda_cub_prime_ptx_version();
|
|
171
176
|
if (n_rows == 1) {
|
|
172
177
|
st = cub::DeviceRadixSort::SortKeys(nullptr, bytes, kin, kout, total, 0, sizeof(Key) * 8, cumo_cuda_stream());
|
|
173
178
|
if (st != cudaSuccess) { return st; }
|
|
@@ -329,6 +334,12 @@ __global__ void iota_kernel(I* out, int64_t n) {
|
|
|
329
334
|
}
|
|
330
335
|
}
|
|
331
336
|
|
|
337
|
+
// The positions go to CUB as this rather than as a bare integer, so that
|
|
338
|
+
// SortPairs is a function of this file alone. With a bare integer it is the
|
|
339
|
+
// same function for every type whose key has the same width, and the link
|
|
340
|
+
// keeps one, so SFloat would launch the kernels of the UInt32 module.
|
|
341
|
+
template <typename I> struct position { I value; };
|
|
342
|
+
|
|
332
343
|
// perm[i] is the position the i-th smallest element sat at, and the index
|
|
333
344
|
// array holds the number to answer for that position.
|
|
334
345
|
template <int NDIM, typename I>
|
|
@@ -373,13 +384,13 @@ void sort_index_rows(cumo_na_iarray_t* a, cumo_na_indexer_t* indexer, cumo_na_ia
|
|
|
373
384
|
key_t* kout = (key_t*)cumo_cuda_runtime_malloc(sizeof(key_t) * total);
|
|
374
385
|
float_key_kernel<T><<<grid_dim, block_dim, 0, cumo_cuda_stream()>>>(data, kin, total);
|
|
375
386
|
cumo_check_launch_holding(kin, kout, pin, pout, gathered);
|
|
376
|
-
cumo_check_status_holding(sort_pairs(kin, kout, pin, pout, total, n_rows, row_len),
|
|
387
|
+
cumo_check_status_holding(sort_pairs(kin, kout, (const position<I>*)pin, (position<I>*)pout, total, n_rows, row_len),
|
|
377
388
|
kin, kout, pin, pout, gathered);
|
|
378
389
|
cumo_cuda_runtime_free((char*)kout);
|
|
379
390
|
cumo_cuda_runtime_free((char*)kin);
|
|
380
391
|
} else {
|
|
381
392
|
T* kout = (T*)cumo_cuda_runtime_malloc(sizeof(T) * total);
|
|
382
|
-
cumo_check_status_holding(sort_pairs(data, kout, pin, pout, total, n_rows, row_len),
|
|
393
|
+
cumo_check_status_holding(sort_pairs(data, kout, (const position<I>*)pin, (position<I>*)pout, total, n_rows, row_len),
|
|
383
394
|
kout, pin, pout, gathered);
|
|
384
395
|
cumo_cuda_runtime_free((char*)kout);
|
|
385
396
|
}
|
|
@@ -396,7 +407,7 @@ void sort_index_rows(cumo_na_iarray_t* a, cumo_na_indexer_t* indexer, cumo_na_ia
|
|
|
396
407
|
|
|
397
408
|
} // namespace
|
|
398
409
|
|
|
399
|
-
// float_key is only defined for the
|
|
410
|
+
// float_key is only defined for the float types, so the integer entry
|
|
400
411
|
// points must not instantiate it; the bool picks the branch at compile time.
|
|
401
412
|
#define CUMO_DEF_SORT(name, type, is_float) \
|
|
402
413
|
extern "C" void cumo_##name##_sort_kernel_launch( \
|
|
@@ -420,15 +431,4 @@ void sort_index_rows(cumo_na_iarray_t* a, cumo_na_indexer_t* indexer, cumo_na_ia
|
|
|
420
431
|
} \
|
|
421
432
|
}
|
|
422
433
|
|
|
423
|
-
|
|
424
|
-
CUMO_DEF_SORT(int16, int16_t, false)
|
|
425
|
-
CUMO_DEF_SORT(int32, int32_t, false)
|
|
426
|
-
CUMO_DEF_SORT(int64, int64_t, false)
|
|
427
|
-
CUMO_DEF_SORT(uint8, u_int8_t, false)
|
|
428
|
-
CUMO_DEF_SORT(uint16, u_int16_t, false)
|
|
429
|
-
CUMO_DEF_SORT(uint32, u_int32_t, false)
|
|
430
|
-
CUMO_DEF_SORT(uint64, u_int64_t, false)
|
|
431
|
-
CUMO_DEF_SORT(hfloat, cumo_half, true)
|
|
432
|
-
CUMO_DEF_SORT(bfloat, cumo_bfloat, true)
|
|
433
|
-
CUMO_DEF_SORT(sfloat, float, true)
|
|
434
|
-
CUMO_DEF_SORT(dfloat, double, true)
|
|
434
|
+
#endif /* ifndef CUMO_SORT_KERNEL_H */
|
|
@@ -186,6 +186,8 @@ void cumo_cuda_runtime_check_kernel_launch(void);
|
|
|
186
186
|
// The stream every launch and copy goes to. It is 0 until Stream#with says
|
|
187
187
|
// otherwise, and thread local, so one thread's choice is not another's.
|
|
188
188
|
struct CUstream_st* cumo_cuda_stream(void);
|
|
189
|
+
// Call before any CUB or Thrust algorithm. Defined in cuda/cub.cu, which says why.
|
|
190
|
+
void cumo_cuda_cub_prime_ptx_version(void);
|
|
189
191
|
|
|
190
192
|
// The forms to call while scratch is held, which free what they are given
|
|
191
193
|
// before they raise. Pass every buffer that is still outstanding, including the
|
data/ext/cumo/narray/data.c
CHANGED
|
@@ -158,6 +158,9 @@ cumo_na_swap_byte(VALUE self)
|
|
|
158
158
|
CUMO_STRIDE_LOOP|CUMO_NDF_INDEXER_LOOP|CUMO_NDF_ACCEPT_BYTESWAP,
|
|
159
159
|
1, 1, ain, aout };
|
|
160
160
|
|
|
161
|
+
if (rb_obj_is_kind_of(self, cumo_cRObject)) {
|
|
162
|
+
rb_raise(rb_eTypeError, "cannot swap bytes of %s", rb_obj_classname(self));
|
|
163
|
+
}
|
|
161
164
|
// Cumo::Bit's element is one bit, so swapping the bytes of an element
|
|
162
165
|
// changes nothing, and a loop stepping by the element stride would walk
|
|
163
166
|
// one byte per bit, eight times past the end of the packed buffer. Only
|
|
@@ -41,14 +41,14 @@ erb_dir.unshift("tmpl_bit") if (type_name == "bit")
|
|
|
41
41
|
erb_dir.map! { |d| File.join(thisdir, d) }
|
|
42
42
|
|
|
43
43
|
TEMPLATE_KERNEL_PARTS = {
|
|
44
|
-
"accum" => %w[reduce reduce_nan],
|
|
45
|
-
"accum_index" => %w[reduce reduce_nan],
|
|
46
|
-
"accum_arg" => %w[reduce reduce_nan],
|
|
47
|
-
"accum_binary" => %w[reduce reduce_nan reduce_from],
|
|
48
|
-
"cum" => %w[
|
|
49
|
-
"layer_norm" => %w[
|
|
50
|
-
"rms_norm" => %w[
|
|
51
|
-
"softmax" => %w[
|
|
44
|
+
"accum" => %w[reduce reduce_rare reduce_nan],
|
|
45
|
+
"accum_index" => %w[reduce reduce_rare reduce_nan],
|
|
46
|
+
"accum_arg" => %w[reduce reduce_rare reduce_nan],
|
|
47
|
+
"accum_binary" => %w[reduce reduce_rare reduce_nan reduce_from],
|
|
48
|
+
"cum" => %w[reduce_rare],
|
|
49
|
+
"layer_norm" => %w[reduce_rare],
|
|
50
|
+
"rms_norm" => %w[reduce_rare],
|
|
51
|
+
"softmax" => %w[reduce_rare],
|
|
52
52
|
"bit_count" => %w[reduce],
|
|
53
53
|
"bit_reduce" => %w[reduce],
|
|
54
54
|
"bit_stat" => %w[reduce],
|
|
@@ -59,10 +59,14 @@ TEMPLATE_KERNEL_PARTS = {
|
|
|
59
59
|
"poly" => %w[misc],
|
|
60
60
|
"quantize_symmetric" => %w[misc],
|
|
61
61
|
"unary_ret2" => %w[misc],
|
|
62
|
+
"sort" => %w[sort],
|
|
62
63
|
}.freeze
|
|
63
64
|
|
|
64
65
|
MATH_TEMPLATES = %w[unary_s binary_s ternary_s frexp].freeze
|
|
65
66
|
COMMON_MATH = %w[sqrt log log2 log10 exp exp2 sin cos tan tanh erf gelu gelu_tanh silu sigmoid softplus].freeze
|
|
67
|
+
# mulsum is here for dot of two vectors.
|
|
68
|
+
COMMON_REDUCE = %w[sum mean max min mulsum].freeze
|
|
69
|
+
RARE_REDUCE = %w[prod ptp minmax var stddev rms abs_sum abs_max abs_min kahan_sum min_index max_index argmin argmax].freeze
|
|
66
70
|
|
|
67
71
|
abort "unknown kernel part: #{$kernel_part}" unless KERNEL_PARTS.include?($kernel_part)
|
|
68
72
|
undeclared_math = COMMON_MATH - File.read(File.join(thisdir, "spec.rb")).scan(/^\s*math "(\w+)"/).flatten
|
|
@@ -83,8 +87,13 @@ class ErbPP
|
|
|
83
87
|
@children.select { |c| c.kernel_parts.include?($kernel_part) }
|
|
84
88
|
end
|
|
85
89
|
|
|
86
|
-
def kernel_part?(nan: false, from: nil)
|
|
87
|
-
$kernel_part ==
|
|
90
|
+
def kernel_part?(op = nil, nan: false, from: nil)
|
|
91
|
+
return $kernel_part == "reduce_from" if from
|
|
92
|
+
return $kernel_part == "reduce_nan" if nan
|
|
93
|
+
return $kernel_part == "reduce" if COMMON_REDUCE.include?(op)
|
|
94
|
+
return $kernel_part == "reduce_rare" if RARE_REDUCE.include?(op)
|
|
95
|
+
|
|
96
|
+
raise ArgumentError, "#{op.inspect} is in neither COMMON_REDUCE nor RARE_REDUCE"
|
|
88
97
|
end
|
|
89
98
|
|
|
90
99
|
def indexer_dims(narrow = false)
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
KERNEL_PARTS = %w[main reduce reduce_nan reduce_from math math_rare compare cast misc].freeze
|
|
3
|
+
KERNEL_PARTS = %w[main reduce reduce_nan reduce_from reduce_rare math math_rare compare cast misc sort].freeze
|
|
4
4
|
MATH_TYPES = %w[hfloat bfloat sfloat dfloat scomplex dcomplex].freeze
|
|
5
|
+
SORT_TYPES = %w[int8 int16 int32 int64 uint8 uint16 uint32 uint64 hfloat bfloat sfloat dfloat].freeze
|
|
5
6
|
|
|
6
7
|
def kernel_parts_of(type_name)
|
|
7
|
-
return
|
|
8
|
+
return %w[main reduce reduce_nan reduce_from] if type_name == "robject"
|
|
8
9
|
|
|
9
10
|
KERNEL_PARTS.reject do |part|
|
|
10
11
|
(%w[math math_rare].include?(part) && !MATH_TYPES.include?(type_name)) ||
|
|
11
|
-
(%w[compare misc].include?(part) && type_name == "bit")
|
|
12
|
+
(%w[compare misc reduce_rare].include?(part) && type_name == "bit") ||
|
|
13
|
+
(part == "sort" && !SORT_TYPES.include?(type_name))
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
|
data/ext/cumo/narray/gen/spec.rb
CHANGED
|
@@ -100,8 +100,12 @@ end
|
|
|
100
100
|
|
|
101
101
|
if is_object
|
|
102
102
|
undef_singleton_method "from_binary"
|
|
103
|
+
undef_singleton_method "from_string"
|
|
104
|
+
undef_method "store_binary"
|
|
103
105
|
undef_method "to_binary"
|
|
106
|
+
undef_method "to_string"
|
|
104
107
|
undef_method "swap_byte"
|
|
108
|
+
undef_method "hton"
|
|
105
109
|
undef_method "to_network"
|
|
106
110
|
undef_method "to_vacs"
|
|
107
111
|
undef_method "to_host"
|
|
@@ -119,7 +119,7 @@ extern "C" {
|
|
|
119
119
|
#endif
|
|
120
120
|
#endif
|
|
121
121
|
|
|
122
|
-
<% if kernel_part? %>
|
|
122
|
+
<% if kernel_part?("argmin") %>
|
|
123
123
|
void cumo_<%=type_name%>_argmin_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
124
124
|
{
|
|
125
125
|
cumo_reduce_arg_split<dtype, idx_t, cumo_<%=type_name%>_argmin_int<%=i%>_impl>(*arg, cumo_<%=type_name%>_argmin_int<%=i%>_impl{});
|
|
@@ -133,7 +133,7 @@ void cumo_<%=type_name%>_argmin_nan_int<%=i%>_kernel_launch(cumo_na_reduction_ar
|
|
|
133
133
|
}
|
|
134
134
|
<% end %>
|
|
135
135
|
|
|
136
|
-
<% if kernel_part? %>
|
|
136
|
+
<% if kernel_part?("argmax") %>
|
|
137
137
|
void cumo_<%=type_name%>_argmax_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
138
138
|
{
|
|
139
139
|
cumo_reduce_arg_split<dtype, idx_t, cumo_<%=type_name%>_argmax_int<%=i%>_impl>(*arg, cumo_<%=type_name%>_argmax_int<%=i%>_impl{});
|
|
@@ -63,7 +63,7 @@ extern "C" {
|
|
|
63
63
|
//<% (is_float ? ["","_nan"] : [""]).each do |nan| %>
|
|
64
64
|
//<% ([nil] + from_types).each do |from| %>
|
|
65
65
|
//<% sfx = from ? "_from_#{from[:id]}" : "" %>
|
|
66
|
-
//<% if kernel_part?(nan: nan == "_nan", from: from) %>
|
|
66
|
+
//<% if kernel_part?(name, nan: nan == "_nan", from: from) %>
|
|
67
67
|
void <%="cumo_#{type_name}_#{name}#{nan}#{sfx}_kernel_launch"%>(cumo_na_reduction_arg_t* arg, cumo_na_iarray_t* in2)
|
|
68
68
|
{
|
|
69
69
|
cumo_reduce_zip_split<dtype, <%= from ? from[:ctype] : "dtype" %>, dtype, <%="cumo_#{type_name}_#{name}#{nan}#{sfx}_impl"%>>(*arg, *in2, <%="cumo_#{type_name}_#{name}#{nan}#{sfx}_impl"%>{});
|
|
@@ -119,7 +119,7 @@ extern "C" {
|
|
|
119
119
|
#endif
|
|
120
120
|
#endif
|
|
121
121
|
|
|
122
|
-
<% if kernel_part? %>
|
|
122
|
+
<% if kernel_part?("min_index") %>
|
|
123
123
|
void cumo_<%=type_name%>_min_index_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
124
124
|
{
|
|
125
125
|
cumo_reduce_split<dtype, idx_t, cumo_<%=type_name%>_min_index_int<%=i%>_impl>(*arg, cumo_<%=type_name%>_min_index_int<%=i%>_impl{});
|
|
@@ -133,7 +133,7 @@ void cumo_<%=type_name%>_min_index_nan_int<%=i%>_kernel_launch(cumo_na_reduction
|
|
|
133
133
|
}
|
|
134
134
|
<% end %>
|
|
135
135
|
|
|
136
|
-
<% if kernel_part? %>
|
|
136
|
+
<% if kernel_part?("max_index") %>
|
|
137
137
|
void cumo_<%=type_name%>_max_index_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
138
138
|
{
|
|
139
139
|
cumo_reduce_split<dtype, idx_t, cumo_<%=type_name%>_max_index_int<%=i%>_impl>(*arg, cumo_<%=type_name%>_max_index_int<%=i%>_impl{});
|
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
<% unless type_name == 'robject' %>
|
|
12
12
|
void <%="cumo_#{c_iter}_kernel_launch"%>(cumo_na_iarray_t* a1, cumo_na_iarray_t* a2, cumo_na_iarray_t* a3, cumo_na_indexer_t* indexer, int* divzero);
|
|
13
|
+
//<% if is_complex && %w[add sub mul div].include?(name) %>
|
|
14
|
+
void <%="cumo_#{c_iter}_r_kernel_launch"%>(cumo_na_iarray_t* a1, cumo_na_iarray_t* a2, cumo_na_iarray_t* a3, cumo_na_indexer_t* indexer, int real_is_left);
|
|
15
|
+
//<% end %>
|
|
16
|
+
//<% complex_of = {'sfloat' => ['scomplex', 'cumo_cSComplex'], 'dfloat' => ['dcomplex', 'cumo_cDComplex']}[type_name] if %w[add sub mul div].include?(name) %>
|
|
17
|
+
//<% if complex_of %>
|
|
18
|
+
VALUE <%="cumo_#{complex_of[0]}_#{name}_real_left"%>(VALUE real, VALUE complex);
|
|
19
|
+
//<% end %>
|
|
13
20
|
//<% if %w[add sub mul div mod bit_and bit_or bit_xor left_shift right_shift copysign].include?(name) %>
|
|
14
21
|
void <%="cumo_#{c_iter}_s_kernel_launch"%>(cumo_na_iarray_t* a1, dtype sv, cumo_na_iarray_t* a3, cumo_na_indexer_t* indexer, int* divzero, int scalar_is_left);
|
|
15
22
|
//<% end %>
|
|
@@ -171,6 +178,40 @@ static void
|
|
|
171
178
|
//<% end %>
|
|
172
179
|
#undef check_intdivzero
|
|
173
180
|
|
|
181
|
+
//<% if is_complex && %w[add sub mul div].include?(name) %>
|
|
182
|
+
// The operands stay in the order they were written in, so that a shape
|
|
183
|
+
// mismatch names them as it always did.
|
|
184
|
+
static void
|
|
185
|
+
<%=c_iter%>_r(cumo_na_loop_t *const lp)
|
|
186
|
+
{
|
|
187
|
+
int real_is_left = *(int*)(lp->opt_ptr);
|
|
188
|
+
cumo_na_iarray_t a1 = cumo_na_make_iarray(&lp->args[real_is_left ? 1 : 0]);
|
|
189
|
+
cumo_na_iarray_t a2 = cumo_na_make_iarray(&lp->args[real_is_left ? 0 : 1]);
|
|
190
|
+
cumo_na_iarray_t a3 = cumo_na_make_iarray(&lp->args[2]);
|
|
191
|
+
cumo_na_indexer_t indexer = cumo_na_make_indexer(&lp->args[0]);
|
|
192
|
+
|
|
193
|
+
<%="cumo_#{c_iter}_r_kernel_launch"%>(&a1,&a2,&a3,&indexer,real_is_left);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// A real operand of this precision is read as it is rather than cast to a
|
|
197
|
+
// complex array first.
|
|
198
|
+
static VALUE
|
|
199
|
+
<%=c_func%>_real(VALUE lhs, VALUE rhs, int real_is_left)
|
|
200
|
+
{
|
|
201
|
+
cumo_ndfunc_arg_in_t ain[2] = {{real_is_left ? cRT : cT,0},{real_is_left ? cT : cRT,0}};
|
|
202
|
+
cumo_ndfunc_arg_out_t aout[1] = {{cT,0}};
|
|
203
|
+
cumo_ndfunc_t ndf = { <%=c_iter%>_r, CUMO_STRIDE_LOOP|CUMO_NDF_INDEXER_LOOP|CUMO_NDF_ANY_ORDER, 2, 1, ain, aout };
|
|
204
|
+
|
|
205
|
+
return cumo_na_ndloop3(&ndf, &real_is_left, 2, lhs, rhs);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
VALUE
|
|
209
|
+
<%="cumo_#{type_name}_#{name}_real_left"%>(VALUE real, VALUE self)
|
|
210
|
+
{
|
|
211
|
+
return <%=c_func%>_real(real, self, 1);
|
|
212
|
+
}
|
|
213
|
+
//<% end %>
|
|
214
|
+
|
|
174
215
|
static VALUE
|
|
175
216
|
<%=c_func%>_self(VALUE self, VALUE other)
|
|
176
217
|
{
|
|
@@ -202,6 +243,11 @@ static VALUE
|
|
|
202
243
|
return cumo_na_ndloop3(&ndf_s, &y, 1, self);
|
|
203
244
|
}
|
|
204
245
|
//<% end %>
|
|
246
|
+
//<% if is_complex && %w[add sub mul div].include?(name) %>
|
|
247
|
+
if (rb_obj_class(other) == cRT) {
|
|
248
|
+
return <%=c_func%>_real(self, other, 0);
|
|
249
|
+
}
|
|
250
|
+
//<% end %>
|
|
205
251
|
cumo_ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
|
|
206
252
|
cumo_ndfunc_arg_out_t aout[1] = {{cT,0}};
|
|
207
253
|
<% if type_name == 'robject' %>
|
|
@@ -230,6 +276,10 @@ static VALUE
|
|
|
230
276
|
klass = cumo_na_upcast(rb_obj_class(self),rb_obj_class(other));
|
|
231
277
|
if (klass==cT) {
|
|
232
278
|
return <%=c_func%>_self(self, other);
|
|
279
|
+
//<% if complex_of %>
|
|
280
|
+
} else if (rb_obj_class(other) == <%=complex_of[1]%> && rb_obj_class(self) == cT) {
|
|
281
|
+
return <%="cumo_#{complex_of[0]}_#{name}_real_left"%>(self, other);
|
|
282
|
+
//<% end %>
|
|
233
283
|
} else {
|
|
234
284
|
v = rb_funcall(klass, cumo_id_cast, 1, self);
|
|
235
285
|
return rb_funcall(v, <%=cumo_id_op%>, 1, other);
|
|
@@ -214,5 +214,29 @@ void <%="cumo_#{c_iter}_kernel_launch"%>(cumo_na_iarray_t* a1, cumo_na_iarray_t*
|
|
|
214
214
|
cumo_cuda_runtime_check_kernel_launch();
|
|
215
215
|
}
|
|
216
216
|
//<% end %>
|
|
217
|
+
|
|
218
|
+
//<% if is_complex && %w[add sub mul div].include?(name) %>
|
|
219
|
+
// A real operand of the same precision is made complex as it is read, which is
|
|
220
|
+
// what casting it first did, without the array the cast wrote.
|
|
221
|
+
<% indexer_dims(true).each do |idim| %>
|
|
222
|
+
__global__ void <%="cumo_#{c_iter}_r_kernel_dim#{idim}"%>(cumo_na_iarray_t a1, cumo_na_iarray_t a2, cumo_na_iarray_t a3, cumo_na_indexer_t indexer, int real_is_left)
|
|
223
|
+
{
|
|
224
|
+
for (uint64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < indexer.total_size; i += blockDim.x * gridDim.x) {
|
|
225
|
+
cumo_na_indexer_set_dim<%=idim%>(&indexer, i);
|
|
226
|
+
dtype x = *(dtype*)(cumo_na_iarray_at_dim<%=idim%>(&a1, &indexer));
|
|
227
|
+
dtype y = m_from_real(*(rtype*)(cumo_na_iarray_at_dim<%=idim%>(&a2, &indexer)));
|
|
228
|
+
*(dtype*)(cumo_na_iarray_at_dim<%=idim%>(&a3, &indexer)) = real_is_left ? m_<%=name%>(y, x) : m_<%=name%>(x, y);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
<% end %>
|
|
232
|
+
|
|
233
|
+
void <%="cumo_#{c_iter}_r_kernel_launch"%>(cumo_na_iarray_t* a1, cumo_na_iarray_t* a2, cumo_na_iarray_t* a3, cumo_na_indexer_t* indexer, int real_is_left)
|
|
234
|
+
{
|
|
235
|
+
size_t grid_dim = cumo_get_grid_dim(indexer->total_size);
|
|
236
|
+
size_t block_dim = cumo_get_block_dim(indexer->total_size);
|
|
237
|
+
<%= indexer_switch("cumo_#{c_iter}_r_kernel", "*a1,*a2,*a3,*indexer,real_is_left", narrow: %w[a1 a2 a3]) %>
|
|
238
|
+
cumo_cuda_runtime_check_kernel_launch();
|
|
239
|
+
}
|
|
240
|
+
//<% end %>
|
|
217
241
|
#undef cumo_check_intdivzero
|
|
218
242
|
<% end %>
|
|
@@ -215,33 +215,43 @@ extern "C" {
|
|
|
215
215
|
#endif
|
|
216
216
|
#endif
|
|
217
217
|
|
|
218
|
-
<% if kernel_part? %>
|
|
218
|
+
<% if kernel_part?("sum") %>
|
|
219
219
|
void cumo_<%=type_name%>_sum_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
220
220
|
{
|
|
221
221
|
cumo_reduce_split<dtype, <%=dtype%>, cumo_<%=type_name%>_sum_impl>(*arg, cumo_<%=type_name%>_sum_impl{});
|
|
222
222
|
}
|
|
223
|
+
<% end %>
|
|
223
224
|
|
|
225
|
+
<% if kernel_part?("prod") %>
|
|
224
226
|
void cumo_<%=type_name%>_prod_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
225
227
|
{
|
|
226
228
|
cumo_reduce_split<dtype, <%=dtype%>, cumo_<%=type_name%>_prod_impl>(*arg, cumo_<%=type_name%>_prod_impl{});
|
|
227
229
|
}
|
|
230
|
+
<% end %>
|
|
228
231
|
|
|
232
|
+
<% if kernel_part?("mean") %>
|
|
229
233
|
void cumo_<%=type_name%>_mean_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
230
234
|
{
|
|
231
235
|
rtype n = (rtype)(arg->in_indexer.total_size / arg->out_indexer.total_size);
|
|
232
236
|
cumo_reduce_split<dtype, dtype, cumo_<%=type_name%>_mean_impl>(*arg, cumo_<%=type_name%>_mean_impl{n});
|
|
233
237
|
}
|
|
238
|
+
<% end %>
|
|
234
239
|
|
|
240
|
+
<% if kernel_part?("var") %>
|
|
235
241
|
void cumo_<%=type_name%>_var_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
236
242
|
{
|
|
237
243
|
cumo_reduce_split<dtype, rtype, cumo_<%=type_name%>_var_impl>(*arg, cumo_<%=type_name%>_var_impl{});
|
|
238
244
|
}
|
|
245
|
+
<% end %>
|
|
239
246
|
|
|
247
|
+
<% if kernel_part?("stddev") %>
|
|
240
248
|
void cumo_<%=type_name%>_stddev_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
241
249
|
{
|
|
242
250
|
cumo_reduce_split<dtype, rtype, cumo_<%=type_name%>_stddev_impl>(*arg, cumo_<%=type_name%>_stddev_impl{});
|
|
243
251
|
}
|
|
252
|
+
<% end %>
|
|
244
253
|
|
|
254
|
+
<% if kernel_part?("rms") %>
|
|
245
255
|
void cumo_<%=type_name%>_rms_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
246
256
|
{
|
|
247
257
|
rtype n = (rtype)(arg->in_indexer.total_size / arg->out_indexer.total_size);
|
|
@@ -280,25 +290,29 @@ void cumo_<%=type_name%>_rms_nan_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
|
280
290
|
cumo_reduce_split<dtype, rtype, cumo_<%=type_name%>_rms_nan_impl>(*arg, cumo_<%=type_name%>_rms_nan_impl{});
|
|
281
291
|
}
|
|
282
292
|
<% end %>
|
|
283
|
-
<% if kernel_part? %>
|
|
293
|
+
<% if kernel_part?("abs_sum") %>
|
|
284
294
|
void cumo_<%=type_name%>_abs_sum_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
285
295
|
{
|
|
286
296
|
cumo_reduce_split<dtype, rtype, cumo_<%=type_name%>_abs_sum_impl>(*arg, cumo_<%=type_name%>_abs_sum_impl{});
|
|
287
297
|
}
|
|
298
|
+
<% end %>
|
|
288
299
|
|
|
300
|
+
<% if kernel_part?("abs_max") %>
|
|
289
301
|
void cumo_<%=type_name%>_abs_max_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
290
302
|
{
|
|
291
303
|
using impl = cumo_<%=type_name%>_abs_extremum_of<cumo_<%=type_name%>_abs_extremum_rules::Max>;
|
|
292
304
|
cumo_reduce_split<dtype, rtype, impl>(*arg, impl{});
|
|
293
305
|
}
|
|
306
|
+
<% end %>
|
|
294
307
|
|
|
308
|
+
<% if kernel_part?("abs_min") %>
|
|
295
309
|
void cumo_<%=type_name%>_abs_min_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
296
310
|
{
|
|
297
311
|
using impl = cumo_<%=type_name%>_abs_extremum_of<cumo_<%=type_name%>_abs_extremum_rules::Min>;
|
|
298
312
|
cumo_reduce_split<dtype, rtype, impl>(*arg, impl{});
|
|
299
313
|
}
|
|
300
314
|
<% end %>
|
|
301
|
-
<% if is_double_precision && kernel_part? %>
|
|
315
|
+
<% if is_double_precision && kernel_part?("kahan_sum") %>
|
|
302
316
|
|
|
303
317
|
void cumo_<%=type_name%>_kahan_sum_kernel_launch(cumo_na_reduction_arg_t* arg)
|
|
304
318
|
{
|