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
data/ext/cumo/cuda/nvrtc.c
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
#include <ruby/thread.h>
|
|
3
3
|
#include <assert.h>
|
|
4
4
|
#include <limits.h>
|
|
5
|
+
#include <cuda.h>
|
|
6
|
+
#include <dlfcn.h>
|
|
7
|
+
#include <pthread.h>
|
|
8
|
+
#include <stdio.h>
|
|
5
9
|
#include <nvrtc.h>
|
|
6
10
|
#include "cumo/cuda/nvrtc.h"
|
|
7
11
|
#include "cumo/cuda/handle.h"
|
|
@@ -13,11 +17,70 @@ VALUE cumo_cuda_mNVRTC;
|
|
|
13
17
|
|
|
14
18
|
static cumo_cuda_handle_set_t programs;
|
|
15
19
|
|
|
20
|
+
#define NVRTC_FUNCTIONS(X) \
|
|
21
|
+
X(nvrtcGetErrorString) X(nvrtcVersion) X(nvrtcCreateProgram) X(nvrtcDestroyProgram) \
|
|
22
|
+
X(nvrtcCompileProgram) X(nvrtcGetPTXSize) X(nvrtcGetPTX) X(nvrtcAddNameExpression) \
|
|
23
|
+
X(nvrtcGetLoweredName) X(nvrtcGetProgramLogSize) X(nvrtcGetProgramLog)
|
|
24
|
+
|
|
25
|
+
static struct {
|
|
26
|
+
#define NVRTC_POINTER(f) __typeof__(&f) f;
|
|
27
|
+
NVRTC_FUNCTIONS(NVRTC_POINTER)
|
|
28
|
+
#undef NVRTC_POINTER
|
|
29
|
+
} nvrtc_functions;
|
|
30
|
+
static pthread_once_t nvrtc_once = PTHREAD_ONCE_INIT;
|
|
31
|
+
static char nvrtc_error[256];
|
|
32
|
+
|
|
33
|
+
static const char*
|
|
34
|
+
dl_error(void)
|
|
35
|
+
{
|
|
36
|
+
const char *e = dlerror();
|
|
37
|
+
return e ? e : "unknown error";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static void
|
|
41
|
+
load_nvrtc(void)
|
|
42
|
+
{
|
|
43
|
+
char soname[32];
|
|
44
|
+
void *lib;
|
|
45
|
+
|
|
46
|
+
if (CUDA_VERSION >= 12000) {
|
|
47
|
+
snprintf(soname, sizeof(soname), "libnvrtc.so.%d", CUDA_VERSION / 1000);
|
|
48
|
+
} else if (CUDA_VERSION >= 11020) {
|
|
49
|
+
snprintf(soname, sizeof(soname), "libnvrtc.so.11.2");
|
|
50
|
+
} else {
|
|
51
|
+
snprintf(soname, sizeof(soname), "libnvrtc.so.%d.%d", CUDA_VERSION / 1000, CUDA_VERSION % 1000 / 10);
|
|
52
|
+
}
|
|
53
|
+
lib = dlopen(soname, RTLD_NOW | RTLD_LOCAL);
|
|
54
|
+
if (lib == NULL) {
|
|
55
|
+
snprintf(nvrtc_error, sizeof(nvrtc_error), "cannot load %s: %s", soname, dl_error());
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
#define NVRTC_RESOLVE(f) \
|
|
59
|
+
nvrtc_functions.f = (__typeof__(&f))dlsym(lib, #f); \
|
|
60
|
+
if (nvrtc_functions.f == NULL) { \
|
|
61
|
+
snprintf(nvrtc_error, sizeof(nvrtc_error), "%s has no %s: %s", soname, #f, dl_error()); \
|
|
62
|
+
dlclose(lib); \
|
|
63
|
+
return; \
|
|
64
|
+
}
|
|
65
|
+
NVRTC_FUNCTIONS(NVRTC_RESOLVE)
|
|
66
|
+
#undef NVRTC_RESOLVE
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static const __typeof__(nvrtc_functions)*
|
|
70
|
+
nvrtc(void)
|
|
71
|
+
{
|
|
72
|
+
pthread_once(&nvrtc_once, load_nvrtc);
|
|
73
|
+
if (nvrtc_error[0] != '\0') {
|
|
74
|
+
rb_raise(cumo_cuda_eNVRTCError, "%s", nvrtc_error);
|
|
75
|
+
}
|
|
76
|
+
return &nvrtc_functions;
|
|
77
|
+
}
|
|
78
|
+
|
|
16
79
|
static void
|
|
17
80
|
check_status(nvrtcResult status)
|
|
18
81
|
{
|
|
19
82
|
if (status != 0) {
|
|
20
|
-
rb_raise(cumo_cuda_eNVRTCError, "%s (error=%d)", nvrtcGetErrorString(status), status);
|
|
83
|
+
rb_raise(cumo_cuda_eNVRTCError, "%s (error=%d)", nvrtc()->nvrtcGetErrorString(status), status);
|
|
21
84
|
}
|
|
22
85
|
}
|
|
23
86
|
|
|
@@ -28,7 +91,7 @@ rb_nvrtcVersion(VALUE self)
|
|
|
28
91
|
nvrtcResult status;
|
|
29
92
|
VALUE major, minor;
|
|
30
93
|
|
|
31
|
-
status = nvrtcVersion(&_major, &_minor);
|
|
94
|
+
status = nvrtc()->nvrtcVersion(&_major, &_minor);
|
|
32
95
|
|
|
33
96
|
check_status(status);
|
|
34
97
|
major = INT2NUM(_major);
|
|
@@ -105,7 +168,7 @@ nvrtcCreateProgram_without_gvl_cb(void *param)
|
|
|
105
168
|
{
|
|
106
169
|
struct nvrtcCreateProgramParam *p = param;
|
|
107
170
|
nvrtcResult status;
|
|
108
|
-
status = nvrtcCreateProgram(p->prog, p->src, p->name, p->numHeaders, p->headers, p->includeNames);
|
|
171
|
+
status = nvrtc_functions.nvrtcCreateProgram(p->prog, p->src, p->name, p->numHeaders, p->headers, p->includeNames);
|
|
109
172
|
return (void *)status;
|
|
110
173
|
}
|
|
111
174
|
|
|
@@ -126,6 +189,7 @@ rb_nvrtcCreateProgram(
|
|
|
126
189
|
const char** _includeNames = NULL;
|
|
127
190
|
VALUE strings;
|
|
128
191
|
|
|
192
|
+
nvrtc();
|
|
129
193
|
// nvrtcCreateProgram reads numHeaders entries out of includeNames as well,
|
|
130
194
|
// so a shorter array would be read past its end.
|
|
131
195
|
if (ary_len(includeNames, "include_names") != _numHeaders) {
|
|
@@ -168,7 +232,7 @@ nvrtcDestroyProgram_without_gvl_cb(void *param)
|
|
|
168
232
|
{
|
|
169
233
|
struct nvrtcDestroyProgramParam *p = param;
|
|
170
234
|
nvrtcResult status;
|
|
171
|
-
status = nvrtcDestroyProgram(p->prog);
|
|
235
|
+
status = nvrtc_functions.nvrtcDestroyProgram(p->prog);
|
|
172
236
|
return (void *)status;
|
|
173
237
|
}
|
|
174
238
|
|
|
@@ -179,6 +243,7 @@ rb_nvrtcDestroyProgram(VALUE self, VALUE prog)
|
|
|
179
243
|
nvrtcProgram _prog = (nvrtcProgram)cumo_cuda_handle_take(&programs, prog, "nvrtcProgram");
|
|
180
244
|
|
|
181
245
|
struct nvrtcDestroyProgramParam param = {&_prog};
|
|
246
|
+
nvrtc();
|
|
182
247
|
status = (nvrtcResult)rb_thread_call_without_gvl(nvrtcDestroyProgram_without_gvl_cb, ¶m, NULL, NULL);
|
|
183
248
|
|
|
184
249
|
check_status(status);
|
|
@@ -196,7 +261,7 @@ nvrtcCompileProgram_without_gvl_cb(void *param)
|
|
|
196
261
|
{
|
|
197
262
|
struct nvrtcCompileProgramParam *p = param;
|
|
198
263
|
nvrtcResult status;
|
|
199
|
-
status = nvrtcCompileProgram(p->prog, p->numOptions, p->options);
|
|
264
|
+
status = nvrtc_functions.nvrtcCompileProgram(p->prog, p->numOptions, p->options);
|
|
200
265
|
return (void *)status;
|
|
201
266
|
}
|
|
202
267
|
|
|
@@ -209,6 +274,7 @@ rb_nvrtcCompileProgram(VALUE self, VALUE prog, VALUE options)
|
|
|
209
274
|
const char** _options = NULL;
|
|
210
275
|
VALUE strings;
|
|
211
276
|
|
|
277
|
+
nvrtc();
|
|
212
278
|
strings = rb_ary_new_capa(_numOptions);
|
|
213
279
|
push_strings(strings, options, _numOptions);
|
|
214
280
|
|
|
@@ -237,12 +303,12 @@ rb_nvrtcGetPTX(VALUE self, VALUE prog)
|
|
|
237
303
|
char *_ptx;
|
|
238
304
|
VALUE ptx;
|
|
239
305
|
|
|
240
|
-
status = nvrtcGetPTXSize(_prog, &_ptxSizeRet);
|
|
306
|
+
status = nvrtc()->nvrtcGetPTXSize(_prog, &_ptxSizeRet);
|
|
241
307
|
check_status(status);
|
|
242
308
|
|
|
243
309
|
ptx = rb_str_new(NULL, _ptxSizeRet);
|
|
244
310
|
_ptx = RSTRING_PTR(ptx);
|
|
245
|
-
status = nvrtcGetPTX(_prog, _ptx);
|
|
311
|
+
status = nvrtc()->nvrtcGetPTX(_prog, _ptx);
|
|
246
312
|
check_status(status);
|
|
247
313
|
|
|
248
314
|
return ptx;
|
|
@@ -262,7 +328,7 @@ rb_nvrtcAddNameExpression(VALUE self, VALUE prog, VALUE name_expression)
|
|
|
262
328
|
nvrtcProgram _prog;
|
|
263
329
|
StringValueCStr(name_expression);
|
|
264
330
|
_prog = (nvrtcProgram)cumo_cuda_handle_get(&programs, prog, "nvrtcProgram");
|
|
265
|
-
check_status(nvrtcAddNameExpression(_prog, RSTRING_PTR(name_expression)));
|
|
331
|
+
check_status(nvrtc()->nvrtcAddNameExpression(_prog, RSTRING_PTR(name_expression)));
|
|
266
332
|
RB_GC_GUARD(name_expression);
|
|
267
333
|
return Qnil;
|
|
268
334
|
}
|
|
@@ -283,7 +349,7 @@ rb_nvrtcGetLoweredName(VALUE self, VALUE prog, VALUE name_expression)
|
|
|
283
349
|
const char *lowered = NULL;
|
|
284
350
|
StringValueCStr(name_expression);
|
|
285
351
|
_prog = (nvrtcProgram)cumo_cuda_handle_get(&programs, prog, "nvrtcProgram");
|
|
286
|
-
check_status(nvrtcGetLoweredName(_prog, RSTRING_PTR(name_expression), &lowered));
|
|
352
|
+
check_status(nvrtc()->nvrtcGetLoweredName(_prog, RSTRING_PTR(name_expression), &lowered));
|
|
287
353
|
RB_GC_GUARD(name_expression);
|
|
288
354
|
return rb_str_new_cstr(lowered);
|
|
289
355
|
}
|
|
@@ -297,12 +363,12 @@ rb_nvrtcGetProgramLog(VALUE self, VALUE prog)
|
|
|
297
363
|
char *_log;
|
|
298
364
|
VALUE log;
|
|
299
365
|
|
|
300
|
-
status = nvrtcGetProgramLogSize(_prog, &_logSizeRet);
|
|
366
|
+
status = nvrtc()->nvrtcGetProgramLogSize(_prog, &_logSizeRet);
|
|
301
367
|
check_status(status);
|
|
302
368
|
|
|
303
369
|
log = rb_str_new(NULL, _logSizeRet);
|
|
304
370
|
_log = RSTRING_PTR(log);
|
|
305
|
-
status = nvrtcGetProgramLog(_prog, _log);
|
|
371
|
+
status = nvrtc()->nvrtcGetProgramLog(_prog, _log);
|
|
306
372
|
check_status(status);
|
|
307
373
|
|
|
308
374
|
return log;
|
data/ext/cumo/cuda/runtime.c
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
VALUE cumo_cuda_eRuntimeError;
|
|
13
13
|
VALUE cumo_cuda_mRuntime;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
size_t cumo_cuda_sync_epoch = 0;
|
|
15
|
+
size_t cumo_cuda_launch_epoch = 0;
|
|
16
16
|
|
|
17
17
|
static ID id_current_stream;
|
|
18
18
|
|
|
@@ -63,7 +63,7 @@ cumo_cuda_stream_set(cudaStream_t stream)
|
|
|
63
63
|
void
|
|
64
64
|
cumo_cuda_runtime_check_kernel_launch(void)
|
|
65
65
|
{
|
|
66
|
-
cumo_cuda_launch_epoch
|
|
66
|
+
cumo_atomic_size_fetch_add(&cumo_cuda_launch_epoch, 1);
|
|
67
67
|
check_status(cudaGetLastError());
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -215,7 +215,7 @@ cumo_cuda_runtime_check_taken_status_holding(int status, char *p0, char *p1, cha
|
|
|
215
215
|
void
|
|
216
216
|
cumo_cuda_runtime_check_kernel_launch_holding(char *p0, char *p1, char *p2, char *p3, char *p4)
|
|
217
217
|
{
|
|
218
|
-
cumo_cuda_launch_epoch
|
|
218
|
+
cumo_atomic_size_fetch_add(&cumo_cuda_launch_epoch, 1);
|
|
219
219
|
cumo_cuda_runtime_check_taken_status_holding((int)cudaGetLastError(), p0, p1, p2, p3, p4);
|
|
220
220
|
}
|
|
221
221
|
|
|
@@ -866,6 +866,10 @@ thread_table_free(void *ptr)
|
|
|
866
866
|
char *entry = t->entries + i * local->entry_size;
|
|
867
867
|
spare_entry_t *spare;
|
|
868
868
|
if (!entry_filled(entry, local->entry_size)) { continue; }
|
|
869
|
+
if (local->release != NULL) {
|
|
870
|
+
local->release(entry);
|
|
871
|
+
if (!entry_filled(entry, local->entry_size)) { continue; }
|
|
872
|
+
}
|
|
869
873
|
spare = (spare_entry_t*)malloc(sizeof(spare_entry_t) + local->entry_size);
|
|
870
874
|
if (spare == NULL) { continue; }
|
|
871
875
|
spare->device = i;
|
|
@@ -883,11 +887,18 @@ cumo_cuda_thread_local_init(cumo_cuda_thread_local_t *local, size_t entry_size)
|
|
|
883
887
|
{
|
|
884
888
|
local->entry_size = entry_size;
|
|
885
889
|
local->spare = NULL;
|
|
890
|
+
local->release = NULL;
|
|
886
891
|
if (pthread_mutex_init(&local->lock, NULL) != 0 || pthread_key_create(&local->key, thread_table_free) != 0) {
|
|
887
892
|
rb_raise(rb_eRuntimeError, "cannot set up a per-thread table");
|
|
888
893
|
}
|
|
889
894
|
}
|
|
890
895
|
|
|
896
|
+
void
|
|
897
|
+
cumo_cuda_thread_local_on_exit(cumo_cuda_thread_local_t *local, void (*release)(void *entry))
|
|
898
|
+
{
|
|
899
|
+
local->release = release;
|
|
900
|
+
}
|
|
901
|
+
|
|
891
902
|
static int
|
|
892
903
|
take_spare(cumo_cuda_thread_local_t *local, size_t device, char *entry)
|
|
893
904
|
{
|
data/ext/cumo/depend.erb
CHANGED
|
@@ -40,7 +40,7 @@ list_type_rb = Dir.glob("#{__dir__}/narray/gen/def/*.rb")
|
|
|
40
40
|
list_type_rb.each do |type_rb|
|
|
41
41
|
type_name = File.basename(type_rb, ".rb")
|
|
42
42
|
next if ENV['DTYPE'] and !type_name.downcase.include?(ENV['DTYPE'].downcase)
|
|
43
|
-
|
|
43
|
+
kernel_parts_of(type_name).each do |part|
|
|
44
44
|
list_type_cu << type_cu = "narray/types/" + kernel_part_basename(type_name, part) + ".cu"
|
|
45
45
|
%>
|
|
46
46
|
<%=type_cu%>: <%=type_rb%> $(CU_DEPENDS)
|
data/ext/cumo/extconf.rb
CHANGED
|
@@ -72,7 +72,7 @@ cuda/cusolver
|
|
|
72
72
|
)
|
|
73
73
|
%w[bit int8 int16 int32 int64 uint8 uint16 uint32 uint64 hfloat bfloat sfloat dfloat scomplex dcomplex robject].each do |type_name|
|
|
74
74
|
srcs << "narray/types/#{type_name}"
|
|
75
|
-
srcs.concat(
|
|
75
|
+
srcs.concat(kernel_parts_of(type_name).map { |part| "narray/types/" + kernel_part_basename(type_name, part) })
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
$objs = srcs.map { |src| "#{src}.o" }
|
|
@@ -138,7 +138,7 @@ dir_config('cumo', HEADER_DIRS, LIB_DIRS)
|
|
|
138
138
|
|
|
139
139
|
have_library('cuda')
|
|
140
140
|
have_library('cudart')
|
|
141
|
-
|
|
141
|
+
have_header('nvrtc.h')
|
|
142
142
|
have_library('cublas')
|
|
143
143
|
# have_library('curand')
|
|
144
144
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#ifndef CUMO_ATOMIC_H
|
|
2
|
+
#define CUMO_ATOMIC_H
|
|
3
|
+
|
|
4
|
+
#include <stddef.h>
|
|
5
|
+
|
|
6
|
+
// The compiler builtins rather than ruby/atomic.h: the size_t fetch-add
|
|
7
|
+
// there arrived after the oldest Ruby cumo builds with, and this header is
|
|
8
|
+
// read without ruby.h as well.
|
|
9
|
+
static inline size_t
|
|
10
|
+
cumo_atomic_size_fetch_add(size_t *var, size_t n)
|
|
11
|
+
{
|
|
12
|
+
return __atomic_fetch_add(var, n, __ATOMIC_SEQ_CST);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static inline size_t
|
|
16
|
+
cumo_atomic_size_load(const size_t *var)
|
|
17
|
+
{
|
|
18
|
+
return __atomic_load_n(var, __ATOMIC_SEQ_CST);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static inline void
|
|
22
|
+
cumo_atomic_size_store(size_t *var, size_t value)
|
|
23
|
+
{
|
|
24
|
+
__atomic_store_n(var, value, __ATOMIC_SEQ_CST);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#endif /* ifndef CUMO_ATOMIC_H */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#define CUMO_CUDA_RUNTIME_H
|
|
3
3
|
|
|
4
4
|
#include "cumo/narray.h"
|
|
5
|
+
#include "cumo/atomic.h"
|
|
5
6
|
#include <pthread.h>
|
|
6
7
|
#include <cuda_runtime.h>
|
|
7
8
|
|
|
@@ -25,17 +26,17 @@ cudaStream_t cumo_cuda_stream_get(VALUE stream);
|
|
|
25
26
|
// the moment the count has moved on. cumo_cuda_runtime_device_synchronize
|
|
26
27
|
// advances it, and so does a host read under a stream of the caller's, and a
|
|
27
28
|
// count that is behind costs a wait rather than correctness.
|
|
28
|
-
extern
|
|
29
|
+
extern size_t cumo_cuda_sync_epoch;
|
|
29
30
|
|
|
30
31
|
// How many times device memory was written from here: every kernel launch,
|
|
31
32
|
// copy into it and library call counts. A host loop reads a staged copy,
|
|
32
33
|
// and reads again once the count moves.
|
|
33
|
-
extern
|
|
34
|
+
extern size_t cumo_cuda_launch_epoch;
|
|
34
35
|
|
|
35
36
|
static inline void
|
|
36
37
|
cumo_cuda_runtime_note_device_write(void)
|
|
37
38
|
{
|
|
38
|
-
cumo_cuda_launch_epoch
|
|
39
|
+
cumo_atomic_size_fetch_add(&cumo_cuda_launch_epoch, 1);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
// A pinned host buffer for reading device memory back: a copy into pinned
|
|
@@ -67,11 +68,27 @@ cumo_cuda_runtime_check_status(cudaError_t status)
|
|
|
67
68
|
|
|
68
69
|
void cumo_cuda_runtime_return_scratch(char *ptr, int wait_for_stream, cudaError_t *status);
|
|
69
70
|
|
|
71
|
+
// The counts move before the wait, not after it. A view that records the
|
|
72
|
+
// count while another thread is already waiting then waits itself, where
|
|
73
|
+
// recording the count the wait left behind would have let it skip a wait
|
|
74
|
+
// that never covered its fill.
|
|
70
75
|
static inline void
|
|
71
76
|
cumo_cuda_runtime_device_synchronize(void)
|
|
72
77
|
{
|
|
78
|
+
cumo_atomic_size_fetch_add(&cumo_cuda_sync_epoch, 1);
|
|
73
79
|
cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
|
|
74
|
-
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static inline size_t
|
|
83
|
+
cumo_cuda_sync_epoch_now(void)
|
|
84
|
+
{
|
|
85
|
+
return cumo_atomic_size_load(&cumo_cuda_sync_epoch);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static inline size_t
|
|
89
|
+
cumo_cuda_launch_epoch_now(void)
|
|
90
|
+
{
|
|
91
|
+
return cumo_atomic_size_load(&cumo_cuda_launch_epoch);
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
// Asking costs less than half of waiting, and there is nothing to wait for
|
|
@@ -114,9 +131,9 @@ cumo_cuda_runtime_memcpy_to_pinned(void *dst, const void *src, size_t bytes)
|
|
|
114
131
|
{
|
|
115
132
|
cudaError_t status;
|
|
116
133
|
if (cumo_cuda_stream() != 0 && !cumo_cuda_runtime_streams_idle()) {
|
|
134
|
+
cumo_atomic_size_fetch_add(&cumo_cuda_sync_epoch, 1);
|
|
117
135
|
status = cudaDeviceSynchronize();
|
|
118
136
|
if (status != cudaSuccess) { return status; }
|
|
119
|
-
cumo_cuda_sync_epoch++;
|
|
120
137
|
}
|
|
121
138
|
status = cudaMemcpyAsync(dst, src, bytes, cudaMemcpyDeviceToHost, cumo_cuda_stream());
|
|
122
139
|
if (status != cudaSuccess) { return status; }
|
|
@@ -131,9 +148,13 @@ typedef struct {
|
|
|
131
148
|
size_t entry_size;
|
|
132
149
|
pthread_mutex_t lock;
|
|
133
150
|
void *spare;
|
|
151
|
+
void (*release)(void *entry);
|
|
134
152
|
} cumo_cuda_thread_local_t;
|
|
135
153
|
|
|
136
154
|
void cumo_cuda_thread_local_init(cumo_cuda_thread_local_t *local, size_t entry_size);
|
|
155
|
+
// Called on each filled entry of a thread that ends, without the GVL. An
|
|
156
|
+
// entry it empties is dropped instead of being kept for the next thread.
|
|
157
|
+
void cumo_cuda_thread_local_on_exit(cumo_cuda_thread_local_t *local, void (*release)(void *entry));
|
|
137
158
|
void *cumo_cuda_thread_local_get(cumo_cuda_thread_local_t *local);
|
|
138
159
|
|
|
139
160
|
static inline int
|
|
@@ -22,6 +22,7 @@ unsigned int cumo_na_element_stride(VALUE nary);
|
|
|
22
22
|
size_t cumo_na_dtype_element_stride(VALUE klass);
|
|
23
23
|
|
|
24
24
|
char *cumo_na_get_pointer(VALUE);
|
|
25
|
+
int cumo_na_has_pending_scalar(VALUE);
|
|
25
26
|
char *cumo_na_get_pointer_for_write(VALUE);
|
|
26
27
|
char *cumo_na_get_pointer_for_read(VALUE);
|
|
27
28
|
char *cumo_na_get_pointer_for_read_write(VALUE);
|
|
@@ -113,8 +114,7 @@ VALUE cumo_na_ary_composition_dtype(VALUE ary);
|
|
|
113
114
|
|
|
114
115
|
// defined in rand, used by the generated rand and rand_norm
|
|
115
116
|
u_int64_t cumo_cuda_rand_seed(void);
|
|
116
|
-
u_int64_t
|
|
117
|
-
void cumo_cuda_rand_set_offset(u_int64_t offset);
|
|
117
|
+
u_int64_t cumo_cuda_rand_reserve_offset(u_int64_t n);
|
|
118
118
|
|
|
119
119
|
#include "ruby/version.h"
|
|
120
120
|
|
|
@@ -253,8 +253,8 @@ typedef struct {
|
|
|
253
253
|
// until it has been worked out. What a view reaches never changes, so it
|
|
254
254
|
// is worked out once, and it stays right even after the base has moved on.
|
|
255
255
|
size_t reach_end;
|
|
256
|
-
|
|
257
|
-
// issued;
|
|
256
|
+
size_t index_sync_epoch; // synchronizes counted when the index fills were
|
|
257
|
+
// issued; SIZE_MAX when that is not known
|
|
258
258
|
// A view made from another one can point at the index arrays it already
|
|
259
259
|
// has rather than copy them. index_owner keeps that view alive for as long
|
|
260
260
|
// as this one borrows from it, and index_owned says which dimensions are
|
|
@@ -18,7 +18,7 @@ __host__ __device__ static inline dtype int_reciprocal(dtype x) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
__device__ static dtype pow_int(dtype x,
|
|
21
|
+
__device__ static dtype pow_int(dtype x, uint64_t p)
|
|
22
22
|
{
|
|
23
23
|
dtype r = m_one;
|
|
24
24
|
switch(p) {
|
|
@@ -27,7 +27,6 @@ __device__ static dtype pow_int(dtype x, int p)
|
|
|
27
27
|
case 2: return x*x;
|
|
28
28
|
case 3: return x*x*x;
|
|
29
29
|
}
|
|
30
|
-
if (p<0) return 0;
|
|
31
30
|
while (p) {
|
|
32
31
|
if (p&1) r *= x;
|
|
33
32
|
x *= x;
|
data/ext/cumo/include/cumo.h
CHANGED
data/ext/cumo/narray/array.c
CHANGED
|
@@ -449,8 +449,8 @@ cumo_na_s_array_shape(VALUE mod, VALUE ary)
|
|
|
449
449
|
Cumo::DFloat.new_like(obj) returns DFloat instance.
|
|
450
450
|
|
|
451
451
|
@overload new_like(obj)
|
|
452
|
-
|
|
453
|
-
|
|
452
|
+
@param [Numeric,Array,Cumo::NArray] obj
|
|
453
|
+
@return [Cumo::NArray]
|
|
454
454
|
@example
|
|
455
455
|
Cumo::NArray.new_like([[1,2,3],[4,5,6]])
|
|
456
456
|
# => Cumo::Int32#shape=[2,3](empty)
|
|
@@ -490,8 +490,8 @@ cumo_na_s_array_type(VALUE mod, VALUE ary)
|
|
|
490
490
|
/*
|
|
491
491
|
Generate NArray object. NArray datatype is automatically selected.
|
|
492
492
|
@overload [](elements)
|
|
493
|
-
|
|
494
|
-
|
|
493
|
+
@param [Numeric,Array] elements
|
|
494
|
+
@return [NArray]
|
|
495
495
|
*/
|
|
496
496
|
static VALUE
|
|
497
497
|
cumo_na_s_bracket(VALUE klass, VALUE ary)
|
data/ext/cumo/narray/data.c
CHANGED
|
@@ -230,9 +230,9 @@ check_axis(int axis, int ndim)
|
|
|
230
230
|
/*
|
|
231
231
|
Interchange two axes.
|
|
232
232
|
@overload swapaxes(axis1,axis2)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
@param [Integer] axis1
|
|
234
|
+
@param [Integer] axis2
|
|
235
|
+
@return [Cumo::NArray] view of NArray.
|
|
236
236
|
@example
|
|
237
237
|
x = Cumo::Int32[[1,2,3]]
|
|
238
238
|
|
|
@@ -452,9 +452,8 @@ cumo_na_check_reshape(int argc, VALUE *argv, VALUE self, size_t *shape)
|
|
|
452
452
|
Raise exception if self is non-contiguous.
|
|
453
453
|
|
|
454
454
|
@overload reshape!(size0,size1,...)
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
@example
|
|
455
|
+
@param sizeN [Integer] new shape
|
|
456
|
+
@return [Cumo::NArray] return self.
|
|
458
457
|
*/
|
|
459
458
|
static VALUE
|
|
460
459
|
cumo_na_reshape_bang(int argc, VALUE *argv, VALUE self)
|
|
@@ -510,9 +509,8 @@ cumo_na_reshape_bang(int argc, VALUE *argv, VALUE self)
|
|
|
510
509
|
Returns a copied NArray.
|
|
511
510
|
|
|
512
511
|
@overload reshape(size0,size1,...)
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
@example
|
|
512
|
+
@param sizeN [Integer] new shape
|
|
513
|
+
@return [Cumo::NArray] a copy carrying the new shape.
|
|
516
514
|
*/
|
|
517
515
|
static VALUE
|
|
518
516
|
cumo_na_reshape(int argc, VALUE *argv, VALUE self)
|
|
@@ -673,13 +671,13 @@ void cumo_na_diagonal_stride_index_kernel_launch(size_t *idx, ssize_t s0, size_t
|
|
|
673
671
|
/*
|
|
674
672
|
Returns a diagonal view of NArray
|
|
675
673
|
@overload diagonal([offset,axes])
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
674
|
+
@param [Integer] offset Diagonal offset from the main diagonal.
|
|
675
|
+
The default is 0. k>0 for diagonals above the main diagonal,
|
|
676
|
+
and k<0 for diagonals below the main diagonal.
|
|
677
|
+
@param [Array] axes Array of axes to be used as the 2-d sub-arrays
|
|
678
|
+
from which the diagonals should be taken. Defaults to last-two
|
|
679
|
+
axes ([-2,-1]).
|
|
680
|
+
@return [Cumo::NArray] diagonal view of NArray.
|
|
683
681
|
@example
|
|
684
682
|
a = Cumo::DFloat.new(4,5).seq
|
|
685
683
|
# => Cumo::DFloat#shape=[4,5]
|
|
@@ -52,13 +52,35 @@ TEMPLATE_KERNEL_PARTS = {
|
|
|
52
52
|
"bit_count" => %w[reduce],
|
|
53
53
|
"bit_reduce" => %w[reduce],
|
|
54
54
|
"bit_stat" => %w[reduce],
|
|
55
|
+
"cond_binary" => %w[compare],
|
|
56
|
+
"cond_unary" => %w[compare],
|
|
57
|
+
"rand" => %w[misc],
|
|
58
|
+
"rand_norm" => %w[misc],
|
|
59
|
+
"poly" => %w[misc],
|
|
60
|
+
"quantize_symmetric" => %w[misc],
|
|
61
|
+
"unary_ret2" => %w[misc],
|
|
55
62
|
}.freeze
|
|
56
63
|
|
|
64
|
+
MATH_TEMPLATES = %w[unary_s binary_s ternary_s frexp].freeze
|
|
65
|
+
COMMON_MATH = %w[sqrt log log2 log10 exp exp2 sin cos tan tanh erf gelu gelu_tanh silu sigmoid softplus].freeze
|
|
66
|
+
|
|
57
67
|
abort "unknown kernel part: #{$kernel_part}" unless KERNEL_PARTS.include?($kernel_part)
|
|
68
|
+
undeclared_math = COMMON_MATH - File.read(File.join(thisdir, "spec.rb")).scan(/^\s*math "(\w+)"/).flatten
|
|
69
|
+
abort "COMMON_MATH names no math function in spec.rb: #{undeclared_math.join(', ')}" unless undeclared_math.empty?
|
|
58
70
|
|
|
59
71
|
class ErbPP
|
|
60
72
|
def kernel_parts
|
|
61
|
-
|
|
73
|
+
erb_base = get(:erb_base)
|
|
74
|
+
return TEMPLATE_KERNEL_PARTS[erb_base] if TEMPLATE_KERNEL_PARTS.key?(erb_base)
|
|
75
|
+
return [COMMON_MATH.include?(@opts[:name]) ? "math" : "math_rare"] if MATH_TEMPLATES.include?(erb_base)
|
|
76
|
+
return @children.flat_map(&:kernel_parts).uniq unless @children.empty?
|
|
77
|
+
return [@opts[:type_name] == get(:class_name) ? "main" : "cast"] if %w[store_from store_bit].include?(erb_base)
|
|
78
|
+
|
|
79
|
+
%w[main]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def kernel_children
|
|
83
|
+
@children.select { |c| c.kernel_parts.include?($kernel_part) }
|
|
62
84
|
end
|
|
63
85
|
|
|
64
86
|
def kernel_part?(nan: false, from: nil)
|
|
@@ -87,7 +109,7 @@ end
|
|
|
87
109
|
|
|
88
110
|
class DefModule
|
|
89
111
|
def method_code
|
|
90
|
-
|
|
112
|
+
kernel_children.map { |c| c.result }.join("\n")
|
|
91
113
|
end
|
|
92
114
|
end
|
|
93
115
|
|
|
@@ -266,7 +266,13 @@ class DefMethod < ErbPP
|
|
|
266
266
|
|
|
267
267
|
def init_def
|
|
268
268
|
return if n_arg == :nodef
|
|
269
|
-
s =
|
|
269
|
+
s = if singleton
|
|
270
|
+
"_singleton"
|
|
271
|
+
elsif @opts[:private]
|
|
272
|
+
"_private"
|
|
273
|
+
else
|
|
274
|
+
""
|
|
275
|
+
end
|
|
270
276
|
"rb_define#{s}_method(#{define_method_args});"
|
|
271
277
|
end
|
|
272
278
|
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
KERNEL_PARTS = %w[main reduce reduce_nan reduce_from].freeze
|
|
3
|
+
KERNEL_PARTS = %w[main reduce reduce_nan reduce_from math math_rare compare cast misc].freeze
|
|
4
|
+
MATH_TYPES = %w[hfloat bfloat sfloat dfloat scomplex dcomplex].freeze
|
|
5
|
+
|
|
6
|
+
def kernel_parts_of(type_name)
|
|
7
|
+
return KERNEL_PARTS.first(4) if type_name == "robject"
|
|
8
|
+
|
|
9
|
+
KERNEL_PARTS.reject do |part|
|
|
10
|
+
(%w[math math_rare].include?(part) && !MATH_TYPES.include?(type_name)) ||
|
|
11
|
+
(%w[compare misc].include?(part) && type_name == "bit")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
4
14
|
|
|
5
15
|
def kernel_part_basename(type_name, part)
|
|
6
16
|
part == "main" ? "#{type_name}_kernel" : "#{type_name}_kernel_#{part}"
|
|
@@ -59,8 +59,8 @@ module NArrayMethod
|
|
|
59
59
|
def_method(meth, "bit_reduce", **h)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
def accum(meth, dtype, result_class)
|
|
63
|
-
h = {dtype:dtype, result_class:result_class}
|
|
62
|
+
def accum(meth, dtype, result_class, **opts)
|
|
63
|
+
h = {dtype:dtype, result_class:result_class, **opts}
|
|
64
64
|
def_method(meth, "accum", **h)
|
|
65
65
|
end
|
|
66
66
|
|
data/ext/cumo/narray/gen/spec.rb
CHANGED
|
@@ -341,6 +341,16 @@ elsif is_int && !is_object
|
|
|
341
341
|
accum "rms", "double", "cumo_cDFloat"
|
|
342
342
|
end
|
|
343
343
|
|
|
344
|
+
if %w[sfloat dfloat scomplex dcomplex].include?(get(:type_name))
|
|
345
|
+
%w[abs_sum abs_max abs_min].each do |name|
|
|
346
|
+
if is_complex
|
|
347
|
+
accum name, "rtype", "cRT", private: true, nan_forms: false
|
|
348
|
+
else
|
|
349
|
+
accum name, "dtype", "cT", private: true, nan_forms: false
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
344
354
|
if is_comparable
|
|
345
355
|
accum "min", "dtype", "cT"
|
|
346
356
|
accum "max", "dtype", "cT"
|