cumo 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -2
  3. data/README.md +133 -0
  4. data/bench/cumo_sync_probe.rb +71 -8
  5. data/ext/cumo/cuda/cublas.c +0 -40
  6. data/ext/cumo/cuda/cudnn.c +48 -0
  7. data/ext/cumo/cuda/cudnn_impl.cpp +91 -62
  8. data/ext/cumo/cuda/runtime.c +3 -4
  9. data/ext/cumo/cumo.c +34 -0
  10. data/ext/cumo/extconf.rb +2 -0
  11. data/ext/cumo/include/cumo/cuda/cudnn.h +21 -2
  12. data/ext/cumo/include/cumo/cuda/cumo_thrust.hpp +1 -0
  13. data/ext/cumo/include/cumo/cuda/runtime.h +28 -0
  14. data/ext/cumo/include/cumo/intern.h +4 -1
  15. data/ext/cumo/include/cumo/narray.h +59 -3
  16. data/ext/cumo/include/cumo/template.h +35 -10
  17. data/ext/cumo/include/cumo/template_kernel.h +96 -0
  18. data/ext/cumo/include/cumo/types/bit.h +3 -0
  19. data/ext/cumo/include/cumo/types/bit_kernel.h +3 -0
  20. data/ext/cumo/include/cumo/types/complex_macro.h +2 -0
  21. data/ext/cumo/include/cumo/types/complex_macro_kernel.h +2 -0
  22. data/ext/cumo/include/cumo/types/float_macro.h +2 -0
  23. data/ext/cumo/include/cumo/types/float_macro_kernel.h +2 -0
  24. data/ext/cumo/include/cumo/types/half_def.h +129 -0
  25. data/ext/cumo/include/cumo/types/half_def_kernel.h +28 -0
  26. data/ext/cumo/include/cumo/types/half_macro.h +188 -0
  27. data/ext/cumo/include/cumo/types/half_macro_kernel.h +198 -0
  28. data/ext/cumo/include/cumo/types/hfloat.h +22 -0
  29. data/ext/cumo/include/cumo/types/hfloat_kernel.h +16 -0
  30. data/ext/cumo/include/cumo/types/real_accum.h +2 -0
  31. data/ext/cumo/include/cumo/types/real_accum_kernel.h +2 -0
  32. data/ext/cumo/include/cumo/types/robj_macro.h +3 -0
  33. data/ext/cumo/include/cumo/types/xint_macro.h +3 -0
  34. data/ext/cumo/include/cumo/types/xint_macro_kernel.h +2 -0
  35. data/ext/cumo/include/cumo.h +2 -2
  36. data/ext/cumo/narray/data.c +49 -174
  37. data/ext/cumo/narray/gen/def/bit.rb +2 -0
  38. data/ext/cumo/narray/gen/def/dcomplex.rb +2 -0
  39. data/ext/cumo/narray/gen/def/dfloat.rb +8 -0
  40. data/ext/cumo/narray/gen/def/hfloat.rb +47 -0
  41. data/ext/cumo/narray/gen/def/int16.rb +2 -0
  42. data/ext/cumo/narray/gen/def/int32.rb +2 -0
  43. data/ext/cumo/narray/gen/def/int64.rb +2 -0
  44. data/ext/cumo/narray/gen/def/int8.rb +2 -0
  45. data/ext/cumo/narray/gen/def/robject.rb +2 -0
  46. data/ext/cumo/narray/gen/def/scomplex.rb +2 -0
  47. data/ext/cumo/narray/gen/def/sfloat.rb +8 -0
  48. data/ext/cumo/narray/gen/def/uint16.rb +3 -1
  49. data/ext/cumo/narray/gen/def/uint32.rb +3 -1
  50. data/ext/cumo/narray/gen/def/uint64.rb +2 -0
  51. data/ext/cumo/narray/gen/def/uint8.rb +3 -1
  52. data/ext/cumo/narray/gen/erbpp2.rb +6 -0
  53. data/ext/cumo/narray/gen/spec.rb +1 -0
  54. data/ext/cumo/narray/gen/tmpl/accum.c +1 -1
  55. data/ext/cumo/narray/gen/tmpl/accum_arg.c +1 -1
  56. data/ext/cumo/narray/gen/tmpl/accum_arg_kernel.cu +5 -5
  57. data/ext/cumo/narray/gen/tmpl/accum_binary_kernel.cu +14 -1
  58. data/ext/cumo/narray/gen/tmpl/accum_index.c +1 -1
  59. data/ext/cumo/narray/gen/tmpl/accum_index_kernel.cu +5 -5
  60. data/ext/cumo/narray/gen/tmpl/alloc_func.c +4 -7
  61. data/ext/cumo/narray/gen/tmpl/allocate.c +1 -2
  62. data/ext/cumo/narray/gen/tmpl/aref_cpu.c +1 -1
  63. data/ext/cumo/narray/gen/tmpl/batch_norm.c +11 -23
  64. data/ext/cumo/narray/gen/tmpl/batch_norm_backward.c +12 -24
  65. data/ext/cumo/narray/gen/tmpl/binary_kernel.cu +69 -2
  66. data/ext/cumo/narray/gen/tmpl/clip.c +3 -3
  67. data/ext/cumo/narray/gen/tmpl/cond_unary.c +1 -1
  68. data/ext/cumo/narray/gen/tmpl/conv.c +11 -17
  69. data/ext/cumo/narray/gen/tmpl/conv_grad_w.c +11 -17
  70. data/ext/cumo/narray/gen/tmpl/conv_transpose.c +11 -17
  71. data/ext/cumo/narray/gen/tmpl/cum.c +24 -1
  72. data/ext/cumo/narray/gen/tmpl/cum_kernel.cu +29 -4
  73. data/ext/cumo/narray/gen/tmpl/each.c +2 -3
  74. data/ext/cumo/narray/gen/tmpl/each_with_index.c +5 -21
  75. data/ext/cumo/narray/gen/tmpl/extract_cpu.c +1 -1
  76. data/ext/cumo/narray/gen/tmpl/extract_data.c +1 -1
  77. data/ext/cumo/narray/gen/tmpl/fill.c +1 -1
  78. data/ext/cumo/narray/gen/tmpl/fixed_batch_norm.c +9 -21
  79. data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +42 -37
  80. data/ext/cumo/narray/gen/tmpl/format.c +1 -1
  81. data/ext/cumo/narray/gen/tmpl/format_to_a.c +1 -1
  82. data/ext/cumo/narray/gen/tmpl/gemm.c +78 -27
  83. data/ext/cumo/narray/gen/tmpl/init_class.c +0 -7
  84. data/ext/cumo/narray/gen/tmpl/init_upcast.c +6 -0
  85. data/ext/cumo/narray/gen/tmpl/inspect.c +1 -1
  86. data/ext/cumo/narray/gen/tmpl/lib.c +11 -1
  87. data/ext/cumo/narray/gen/tmpl/map_with_index.c +7 -14
  88. data/ext/cumo/narray/gen/tmpl/median.c +9 -47
  89. data/ext/cumo/narray/gen/tmpl/minmax.c +1 -1
  90. data/ext/cumo/narray/gen/tmpl/poly.c +1 -1
  91. data/ext/cumo/narray/gen/tmpl/pooling_backward.c +2 -14
  92. data/ext/cumo/narray/gen/tmpl/pooling_forward.c +2 -14
  93. data/ext/cumo/narray/gen/tmpl/qsort.c +0 -1
  94. data/ext/cumo/narray/gen/tmpl/rand.c +20 -2
  95. data/ext/cumo/narray/gen/tmpl/rand_kernel.cu +13 -0
  96. data/ext/cumo/narray/gen/tmpl/rand_norm.c +4 -4
  97. data/ext/cumo/narray/gen/tmpl/rand_norm_kernel.cu +7 -5
  98. data/ext/cumo/narray/gen/tmpl/real_accum_kernel.cu +83 -97
  99. data/ext/cumo/narray/gen/tmpl/sort.c +1 -1
  100. data/ext/cumo/narray/gen/tmpl/sort_index.c +6 -3
  101. data/ext/cumo/narray/gen/tmpl/store_array.c +21 -22
  102. data/ext/cumo/narray/gen/tmpl/store_bit.c +1 -1
  103. data/ext/cumo/narray/gen/tmpl/store_from.c +1 -1
  104. data/ext/cumo/narray/gen/tmpl/store_from_kernel.cu +37 -2
  105. data/ext/cumo/narray/gen/tmpl/to_a.c +1 -1
  106. data/ext/cumo/narray/gen/tmpl/unary.c +20 -3
  107. data/ext/cumo/narray/gen/tmpl/unary2.c +1 -1
  108. data/ext/cumo/narray/gen/tmpl/unary_s.c +1 -1
  109. data/ext/cumo/narray/gen/tmpl_bit/allocate.c +2 -3
  110. data/ext/cumo/narray/gen/tmpl_bit/aref_cpu.c +1 -1
  111. data/ext/cumo/narray/gen/tmpl_bit/bit_count_cpu.c +1 -1
  112. data/ext/cumo/narray/gen/tmpl_bit/each.c +2 -2
  113. data/ext/cumo/narray/gen/tmpl_bit/each_with_index.c +5 -20
  114. data/ext/cumo/narray/gen/tmpl_bit/extract_cpu.c +1 -1
  115. data/ext/cumo/narray/gen/tmpl_bit/format.c +1 -1
  116. data/ext/cumo/narray/gen/tmpl_bit/format_to_a.c +1 -1
  117. data/ext/cumo/narray/gen/tmpl_bit/inspect.c +1 -1
  118. data/ext/cumo/narray/gen/tmpl_bit/mask.c +38 -17
  119. data/ext/cumo/narray/gen/tmpl_bit/mask_kernel.cu +4 -4
  120. data/ext/cumo/narray/gen/tmpl_bit/store_array.c +10 -11
  121. data/ext/cumo/narray/gen/tmpl_bit/store_from.c +1 -1
  122. data/ext/cumo/narray/gen/tmpl_bit/to_a.c +1 -1
  123. data/ext/cumo/narray/gen/tmpl_bit/where.c +66 -13
  124. data/ext/cumo/narray/gen/tmpl_bit/where2.c +57 -20
  125. data/ext/cumo/narray/gen/tmpl_bit/where_kernel.cu +6 -6
  126. data/ext/cumo/narray/index.c +63 -18
  127. data/ext/cumo/narray/index_kernel.cu +15 -0
  128. data/ext/cumo/narray/math.c +2 -0
  129. data/ext/cumo/narray/narray.c +289 -183
  130. data/ext/cumo/narray/ndloop.c +91 -26
  131. data/ext/cumo/narray/sort_kernel.cu +39 -18
  132. data/ext/cumo/narray/struct.c +14 -17
  133. data/lib/cumo/cuda/cudnn.rb +1 -1
  134. data/lib/cumo/narray/extra.rb +11 -2
  135. data/test/bit_test.rb +147 -0
  136. data/test/cudnn_test.rb +132 -46
  137. data/test/extra_test.rb +1 -1
  138. data/test/hfloat_test.rb +717 -0
  139. data/test/math_test.rb +4 -1
  140. data/test/narray_alt_coverage_test.rb +7 -0
  141. data/test/narray_test.rb +1018 -11
  142. data/test/test_helper.rb +73 -0
  143. metadata +11 -1
@@ -1,4 +1,8 @@
1
1
  <%= load_erb('real_accum').result(binding) %>
2
+ <% acc = is_half ? 'float' : 'dtype' %>
3
+ <% to_acc = is_half ? 'cumo_half2float' : '' %>
4
+ <% from_acc = is_half ? 'cumo_float2half' : '' %>
5
+
2
6
 
3
7
  #if defined(__cplusplus)
4
8
  #if 0
@@ -14,47 +18,47 @@
14
18
  // divide 0 by 0 and leave the accumulator NaN.
15
19
  struct cumo_<%=type_name%>_moments_impl {
16
20
  struct Moments {
17
- rtype n;
18
- dtype mean;
19
- rtype m2;
21
+ <%=acc%> n;
22
+ <%=acc%> mean;
23
+ <%=acc%> m2;
20
24
  };
21
- __device__ Moments Identity(int64_t /*index*/) { return {0, m_zero, 0}; }
22
- __device__ Moments MapIn(dtype in, int64_t /*index*/) { return {1, in, 0}; }
25
+ __device__ Moments Identity(int64_t /*index*/) { return {0, 0, 0}; }
26
+ __device__ Moments MapIn(dtype in, int64_t /*index*/) { return {1, <%=to_acc%>(in), 0}; }
23
27
  __device__ void Reduce(Moments next, Moments& accum) {
24
28
  if (next.n == 0) { return; }
25
29
  if (accum.n == 0) { accum = next; return; }
26
- rtype n = accum.n + next.n;
27
- dtype delta = m_sub(next.mean, accum.mean);
28
- accum.mean = m_add(accum.mean, delta * (next.n / n));
30
+ <%=acc%> n = accum.n + next.n;
31
+ <%=acc%> delta = next.mean - accum.mean;
32
+ accum.mean = accum.mean + delta * (next.n / n);
29
33
  accum.m2 += next.m2 + delta * delta * accum.n * next.n / n;
30
34
  accum.n = n;
31
35
  }
32
36
  };
33
37
 
34
38
  struct cumo_<%=type_name%>_var_impl : cumo_<%=type_name%>_moments_impl {
35
- __device__ rtype MapOut(Moments accum) { return accum.m2 / (accum.n - 1); }
39
+ __device__ rtype MapOut(Moments accum) { return <%=from_acc%>(accum.m2 / (accum.n - 1)); }
36
40
  };
37
41
 
38
42
  struct cumo_<%=type_name%>_stddev_impl : cumo_<%=type_name%>_moments_impl {
39
- __device__ rtype MapOut(Moments accum) { return m_sqrt(accum.m2 / (accum.n - 1)); }
43
+ __device__ rtype MapOut(Moments accum) { return <%=from_acc%>(sqrt(accum.m2 / (accum.n - 1))); }
40
44
  };
41
45
 
42
46
  struct cumo_<%=type_name%>_mean_impl {
43
47
  // The reduce axis is the same length for every output, so the divisor is a
44
48
  // constant the launcher already knows rather than a count the tree carries.
45
- dtype n;
46
- __device__ dtype Identity(int64_t /*index*/) { return m_zero; }
47
- __device__ dtype MapIn(dtype in, int64_t /*index*/) { return in; }
48
- __device__ void Reduce(dtype next, dtype& accum) { accum = m_add(next, accum); }
49
- __device__ dtype MapOut(dtype accum) { return m_div(accum, n); }
49
+ <%=acc%> n;
50
+ __device__ <%=acc%> Identity(int64_t /*index*/) { return 0; }
51
+ __device__ <%=acc%> MapIn(dtype in, int64_t /*index*/) { return <%=to_acc%>(in); }
52
+ __device__ void Reduce(<%=acc%> next, <%=acc%>& accum) { accum = next + accum; }
53
+ __device__ dtype MapOut(<%=acc%> accum) { return <%=from_acc%>(accum / n); }
50
54
  };
51
55
 
52
56
  struct cumo_<%=type_name%>_rms_impl {
53
- rtype n;
54
- __device__ rtype Identity(int64_t /*index*/) { return 0; }
55
- __device__ rtype MapIn(dtype in, int64_t /*index*/) { return m_square(m_abs(in)); }
56
- __device__ void Reduce(rtype next, rtype& accum) { accum += next; }
57
- __device__ rtype MapOut(rtype accum) { return m_sqrt(accum / n); }
57
+ <%=acc%> n;
58
+ __device__ <%=acc%> Identity(int64_t /*index*/) { return 0; }
59
+ __device__ <%=acc%> MapIn(dtype in, int64_t /*index*/) { <%=acc%> x = <%=to_acc%>(in); return x * x; }
60
+ __device__ void Reduce(<%=acc%> next, <%=acc%>& accum) { accum += next; }
61
+ __device__ rtype MapOut(<%=acc%> accum) { return <%=from_acc%>(sqrt(accum / n)); }
58
62
  };
59
63
 
60
64
  // The nan-aware forms. A NaN maps to an accumulator that contributes nothing:
@@ -63,8 +67,8 @@ struct cumo_<%=type_name%>_rms_impl {
63
67
  // of the reduce axis.
64
68
  struct cumo_<%=type_name%>_moments_nan_impl : cumo_<%=type_name%>_moments_impl {
65
69
  __device__ Moments MapIn(dtype in, int64_t /*index*/) {
66
- if (!not_nan(in)) { return {0, m_zero, 0}; }
67
- return {1, in, 0};
70
+ if (!not_nan(in)) { return {0, 0, 0}; }
71
+ return {1, <%=to_acc%>(in), 0};
68
72
  }
69
73
  };
70
74
 
@@ -72,45 +76,46 @@ struct cumo_<%=type_name%>_var_nan_impl : cumo_<%=type_name%>_moments_nan_impl {
72
76
  // Every element being NaN leaves no count. numo divides by count-1 in
73
77
  // unsigned arithmetic there, so it answers +0 rather than the -0 that
74
78
  // dividing by -1 would give.
75
- __device__ rtype MapOut(Moments accum) { return accum.n == 0 ? 0 : accum.m2 / (accum.n - 1); }
79
+ __device__ rtype MapOut(Moments accum) { return accum.n == 0 ? <%=from_acc%>(0) : <%=from_acc%>(accum.m2 / (accum.n - 1)); }
76
80
  };
77
81
 
78
82
  struct cumo_<%=type_name%>_stddev_nan_impl : cumo_<%=type_name%>_moments_nan_impl {
79
- __device__ rtype MapOut(Moments accum) { return accum.n == 0 ? 0 : m_sqrt(accum.m2 / (accum.n - 1)); }
83
+ __device__ rtype MapOut(Moments accum) { return accum.n == 0 ? <%=from_acc%>(0) : <%=from_acc%>(sqrt(accum.m2 / (accum.n - 1))); }
80
84
  };
81
85
 
82
86
  struct cumo_<%=type_name%>_mean_nan_impl {
83
87
  struct SumAndCount {
84
- dtype sum;
85
- rtype n;
88
+ <%=acc%> sum;
89
+ <%=acc%> n;
86
90
  };
87
- __device__ SumAndCount Identity(int64_t /*index*/) { return {m_zero, 0}; }
91
+ __device__ SumAndCount Identity(int64_t /*index*/) { return {0, 0}; }
88
92
  __device__ SumAndCount MapIn(dtype in, int64_t /*index*/) {
89
- if (!not_nan(in)) { return {m_zero, 0}; }
90
- return {in, 1};
93
+ if (!not_nan(in)) { return {0, 0}; }
94
+ return {<%=to_acc%>(in), 1};
91
95
  }
92
96
  __device__ void Reduce(SumAndCount next, SumAndCount& accum) {
93
- accum.sum = m_add(next.sum, accum.sum);
97
+ accum.sum = next.sum + accum.sum;
94
98
  accum.n += next.n;
95
99
  }
96
- __device__ dtype MapOut(SumAndCount accum) { return m_div(accum.sum, m_from_real(accum.n)); }
100
+ __device__ dtype MapOut(SumAndCount accum) { return <%=from_acc%>(accum.sum / accum.n); }
97
101
  };
98
102
 
99
103
  struct cumo_<%=type_name%>_rms_nan_impl {
100
104
  struct SumAndCount {
101
- rtype sum;
102
- rtype n;
105
+ <%=acc%> sum;
106
+ <%=acc%> n;
103
107
  };
104
108
  __device__ SumAndCount Identity(int64_t /*index*/) { return {0, 0}; }
105
109
  __device__ SumAndCount MapIn(dtype in, int64_t /*index*/) {
106
110
  if (!not_nan(in)) { return {0, 0}; }
107
- return {m_square(m_abs(in)), 1};
111
+ <%=acc%> x = <%=to_acc%>(in);
112
+ return {x * x, 1};
108
113
  }
109
114
  __device__ void Reduce(SumAndCount next, SumAndCount& accum) {
110
115
  accum.sum += next.sum;
111
116
  accum.n += next.n;
112
117
  }
113
- __device__ rtype MapOut(SumAndCount accum) { return m_sqrt(accum.sum / accum.n); }
118
+ __device__ rtype MapOut(SumAndCount accum) { return <%=from_acc%>(sqrt(accum.sum / accum.n)); }
114
119
  };
115
120
 
116
121
  <% if is_double_precision %>
@@ -154,7 +159,7 @@ extern "C" {
154
159
 
155
160
  void cumo_<%=type_name%>_mean_kernel_launch(cumo_na_reduction_arg_t* arg)
156
161
  {
157
- dtype n = (dtype)(arg->in_indexer.total_size / arg->out_indexer.total_size);
162
+ <%=acc%> n = (<%=acc%>)(arg->in_indexer.total_size / arg->out_indexer.total_size);
158
163
  cumo_reduce_split<dtype, dtype, cumo_<%=type_name%>_mean_impl>(*arg, cumo_<%=type_name%>_mean_impl{n});
159
164
  }
160
165
 
@@ -170,7 +175,7 @@ void cumo_<%=type_name%>_stddev_kernel_launch(cumo_na_reduction_arg_t* arg)
170
175
 
171
176
  void cumo_<%=type_name%>_rms_kernel_launch(cumo_na_reduction_arg_t* arg)
172
177
  {
173
- rtype n = (rtype)(arg->in_indexer.total_size / arg->out_indexer.total_size);
178
+ <%=acc%> n = (<%=acc%>)(arg->in_indexer.total_size / arg->out_indexer.total_size);
174
179
  cumo_reduce_split<dtype, rtype, cumo_<%=type_name%>_rms_impl>(*arg, cumo_<%=type_name%>_rms_impl{n});
175
180
  }
176
181
 
@@ -65,6 +65,6 @@ static VALUE
65
65
  cumo_ndfunc_t ndf = { <%=c_iter%>, CUMO_FULL_LOOP_NIP, 2, 1, ain, aout };
66
66
 
67
67
  rb_scan_args(argc, argv, "01", &fmt);
68
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
68
+ cumo_cuda_runtime_device_synchronize();
69
69
  return cumo_na_ndloop(&ndf, 2, self, fmt);
70
70
  }
@@ -44,6 +44,6 @@ static VALUE
44
44
  cumo_ndfunc_t ndf = { <%=c_iter%>, CUMO_FULL_LOOP_NIP, 3, 1, ain, aout };
45
45
 
46
46
  rb_scan_args(argc, argv, "01", &fmt);
47
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
47
+ cumo_cuda_runtime_device_synchronize();
48
48
  return cumo_na_ndloop_cast_narray_to_rarray(&ndf, self, fmt);
49
49
  }
@@ -12,6 +12,8 @@
12
12
  end
13
13
  cutype =
14
14
  case type_name
15
+ when 'hfloat'
16
+ 'cumo_half'
15
17
  when 'sfloat'
16
18
  'float'
17
19
  when 'dfloat'
@@ -21,6 +23,12 @@
21
23
  when 'dcomplex'
22
24
  'cuDoubleComplex'
23
25
  end
26
+ # cublasGemmStridedBatchedEx multiplies in half and accumulates in float, and
27
+ # takes its scalars in the accumulator's type.
28
+ scalar_t = is_half ? 'float' : 'dtype'
29
+ num_to_scalar = is_half ? '(float)NUM2DBL' : 'm_num_to_data'
30
+ scalar_one = is_half ? '1.0f' : 'm_one'
31
+ scalar_zero = is_half ? '0.0f' : 'm_zero'
24
32
  %>
25
33
 
26
34
  #define ROW_SIZE(na) ((na)->shape[(na)->ndim-2])
@@ -102,18 +110,31 @@
102
110
  } \
103
111
  }
104
112
 
113
+ #include <limits.h>
114
+
105
115
  typedef struct {
106
- dtype alpha, beta;
116
+ <%=scalar_t%> alpha, beta;
107
117
  int m, n, k;
108
118
  } gemm_args_t;
109
119
 
110
120
  typedef struct {
111
121
  int ld;
112
- int stride; // in element count
122
+ long long int stride; // in element count
113
123
  cublasOperation_t trans;
114
124
  VALUE a;
115
125
  } gemm_layout_t;
116
126
 
127
+ // cuBLAS takes these as int, so a shape that does not fit has to be refused
128
+ // rather than wrapped into a smaller or negative one.
129
+ static int
130
+ gemm_int(size_t v, const char *name)
131
+ {
132
+ if (v > INT_MAX) {
133
+ rb_raise(rb_eRangeError, "%s=%"SZF"u is too large for cuBLAS", name, v);
134
+ }
135
+ return (int)v;
136
+ }
137
+
117
138
  static bool
118
139
  is_f_contiguous(VALUE a)
119
140
  {
@@ -192,7 +213,7 @@ static int
192
213
  gemm_batch_count(cumo_narray_t *na)
193
214
  {
194
215
  size_t matrix_size = ROW_SIZE(na) * COL_SIZE(na);
195
- return matrix_size == 0 ? 0 : (int)(CUMO_NA_SIZE(na) / matrix_size);
216
+ return matrix_size == 0 ? 0 : gemm_int(CUMO_NA_SIZE(na) / matrix_size, "batch count");
196
217
  }
197
218
 
198
219
  static gemm_layout_t
@@ -210,27 +231,27 @@ make_gemm_layout(VALUE a)
210
231
  }
211
232
 
212
233
  if ((CUMO_NA_NDIM(na) == 2 && is_f_contiguous(a)) || is_batched_f_contiguous(a)) {
213
- layout.ld = ROW_SIZE(na);
234
+ layout.ld = (int)ROW_SIZE(na);
214
235
  layout.trans = CUBLAS_OP_T;
215
236
  layout.a = a;
216
237
  } else {
217
- layout.ld = COL_SIZE(na);
238
+ layout.ld = (int)COL_SIZE(na);
218
239
  layout.trans = CUBLAS_OP_N; // transposed
219
240
  // force c-contiguous
220
241
  layout.a = is_c_contiguous(a) ? a : rb_funcall(a, rb_intern("dup"), 0);
221
242
  }
222
243
  // cuBLAS walks the operand by this stride once per batch, so an operand that
223
244
  // holds a single matrix has to be re-read rather than advanced past its end.
224
- layout.stride = gemm_batch_count(na) == 1 ? 0 : ROW_SIZE(na) * COL_SIZE(na);
245
+ layout.stride = gemm_batch_count(na) == 1 ? 0 : (long long int)(ROW_SIZE(na) * COL_SIZE(na));
225
246
  return layout;
226
247
  }
227
248
 
228
249
  extern int cumo_na_debug_flag; // narray.c
229
250
 
230
251
  static void
231
- print_gemm_args(gemm_args_t* g, gemm_layout_t* a_layout, gemm_layout_t* b_layout, int stridec, int batch_count)
252
+ print_gemm_args(gemm_args_t* g, gemm_layout_t* a_layout, gemm_layout_t* b_layout, long long int stridec, int batch_count)
232
253
  {
233
- printf("transb=%d transa=%d, n=%d, m=%d, k=%d, ldb=%d, lda=%d, ldc=n=%d, strideb=%d, stridea=%d stridec=%d batch_count=%d\n",
254
+ printf("transb=%d transa=%d, n=%d, m=%d, k=%d, ldb=%d, lda=%d, ldc=n=%d, strideb=%lld, stridea=%lld stridec=%lld batch_count=%d\n",
234
255
  (int)b_layout->trans,
235
256
  (int)a_layout->trans,
236
257
  (int)g->n,
@@ -239,9 +260,9 @@ print_gemm_args(gemm_args_t* g, gemm_layout_t* a_layout, gemm_layout_t* b_layout
239
260
  (int)b_layout->ld,
240
261
  (int)a_layout->ld,
241
262
  (int)g->n,
242
- (int)b_layout->stride,
243
- (int)a_layout->stride,
244
- (int)stridec,
263
+ b_layout->stride,
264
+ a_layout->stride,
265
+ stridec,
245
266
  (int)batch_count);
246
267
  }
247
268
 
@@ -252,7 +273,8 @@ static void
252
273
  cublasHandle_t handle = 0;
253
274
  cublasStatus_t status = 0;
254
275
  cumo_narray_t* nc;
255
- int stridec = 0;
276
+ size_t matrix_size;
277
+ long long int stridec = 0;
256
278
  int batch_count = 0;
257
279
 
258
280
  // Note that cuBLAS uses the column major matrix representation.
@@ -270,11 +292,38 @@ static void
270
292
  b_layout = make_gemm_layout(b);
271
293
 
272
294
  CumoGetNArray(c, nc);
273
- stridec = ROW_SIZE(nc) * COL_SIZE(nc);
274
- batch_count = CUMO_NA_SIZE(nc) / stridec;
295
+ matrix_size = ROW_SIZE(nc) * COL_SIZE(nc);
296
+ stridec = (long long int)matrix_size;
297
+ batch_count = gemm_int(CUMO_NA_SIZE(nc) / matrix_size, "batch count");
275
298
 
276
299
  if (cumo_na_debug_flag) print_gemm_args(g, &a_layout, &b_layout, stridec, batch_count);
277
300
  handle = cumo_cuda_cublas_handle();
301
+ <% if is_half %>
302
+ status = cublasGemmStridedBatchedEx(
303
+ handle,
304
+ b_layout.trans,
305
+ a_layout.trans,
306
+ g->n,
307
+ g->m,
308
+ g->k,
309
+ &g->alpha,
310
+ (const void*)(cumo_na_get_pointer_for_read(b_layout.a) + cumo_na_get_offset(b_layout.a)),
311
+ CUDA_R_16F,
312
+ b_layout.ld,
313
+ b_layout.stride,
314
+ (const void*)(cumo_na_get_pointer_for_read(a_layout.a) + cumo_na_get_offset(a_layout.a)),
315
+ CUDA_R_16F,
316
+ a_layout.ld,
317
+ a_layout.stride,
318
+ &g->beta,
319
+ (void*)(cumo_na_get_pointer_for_write(c) + cumo_na_get_offset(c)),
320
+ CUDA_R_16F,
321
+ g->n,
322
+ stridec,
323
+ batch_count,
324
+ CUBLAS_COMPUTE_32F,
325
+ CUBLAS_GEMM_DEFAULT);
326
+ <% else %>
278
327
  status = cublas<%=func_prefix%>gemmStridedBatched(
279
328
  handle,
280
329
  b_layout.trans,
@@ -294,6 +343,7 @@ static void
294
343
  g->n,
295
344
  stridec,
296
345
  batch_count);
346
+ <% end %>
297
347
  cumo_cuda_cublas_check_status(status);
298
348
  }
299
349
 
@@ -350,9 +400,9 @@ static VALUE
350
400
  rb_scan_args(argc, argv, "11:", &b, &c, &kw_hash);
351
401
  rb_get_kwargs(kw_hash, kw_table, 0, 2, opts);
352
402
  alpha = cumo_cuda_cublas_option_value(opts[0],Qnil);
353
- g.alpha = RTEST(alpha) ? m_num_to_data(alpha) : m_one;
403
+ g.alpha = RTEST(alpha) ? <%=num_to_scalar%>(alpha) : <%=scalar_one%>;
354
404
  beta = cumo_cuda_cublas_option_value(opts[1],Qnil);
355
- g.beta = RTEST(beta) ? m_num_to_data(beta) : m_zero;
405
+ g.beta = RTEST(beta) ? <%=num_to_scalar%>(beta) : <%=scalar_zero%>;
356
406
 
357
407
  // b is handed to cuBLAS as a raw <%=cutype%>*, so another dtype would be
358
408
  // reinterpreted, and a narrower one read past its end.
@@ -368,13 +418,13 @@ static VALUE
368
418
  CHECK_NON_EMPTY(nb);
369
419
 
370
420
  if (ROW_SIZE(nb) != COL_SIZE(na)) {
371
- rb_raise(cumo_na_eShapeError,"ROW_SIZE(b)=%d must equal to COL_SIZE(a)=%d",
372
- (int)ROW_SIZE(nb), (int)COL_SIZE(na));
421
+ rb_raise(cumo_na_eShapeError,"ROW_SIZE(b)=%"SZF"u must equal to COL_SIZE(a)=%"SZF"u",
422
+ ROW_SIZE(nb), COL_SIZE(na));
373
423
  }
374
424
 
375
- g.m = ROW_SIZE(na);
376
- g.k = COL_SIZE(na);
377
- g.n = COL_SIZE(nb);
425
+ g.m = gemm_int(ROW_SIZE(na), "row size of a");
426
+ g.k = gemm_int(COL_SIZE(na), "column size of a");
427
+ g.n = gemm_int(COL_SIZE(nb), "column size of b");
378
428
 
379
429
  // The batch dimensions reach cuBLAS as one stride per operand, so both
380
430
  // operands must hold the same number of matrices. An operand holding a
@@ -402,16 +452,17 @@ static VALUE
402
452
  CumoGetNArray(c, nc);
403
453
  CHECK_DIM_GE(nc, 2);
404
454
  if (ROW_SIZE(nc) != ROW_SIZE(na)) {
405
- rb_raise(cumo_na_eShapeError,"ROW_SIZE(c)=%d must equal to ROW_SIZE(a)=%d",
406
- (int)ROW_SIZE(nc), (int)ROW_SIZE(na));
455
+ rb_raise(cumo_na_eShapeError,"ROW_SIZE(c)=%"SZF"u must equal to ROW_SIZE(a)=%"SZF"u",
456
+ ROW_SIZE(nc), ROW_SIZE(na));
407
457
  }
408
458
  if (COL_SIZE(nc) != COL_SIZE(nb)) {
409
- rb_raise(cumo_na_eShapeError,"COL_SIZE(c)=%d must equal to COL_SIZE(b)=%d",
410
- (int)COL_SIZE(nc), (int)COL_SIZE(nb));
459
+ rb_raise(cumo_na_eShapeError,"COL_SIZE(c)=%"SZF"u must equal to COL_SIZE(b)=%"SZF"u",
460
+ COL_SIZE(nc), COL_SIZE(nb));
411
461
  }
412
- if (gemm_batch_count(nc) != batch) {
462
+ int c_batch = gemm_batch_count(nc);
463
+ if (c_batch != batch) {
413
464
  rb_raise(cumo_na_eShapeError,"batch count of c=%d must equal to %d",
414
- gemm_batch_count(nc), batch);
465
+ c_batch, batch);
415
466
  }
416
467
  // a and b are duplicated when they are not contiguous, but c is written
417
468
  // in place, and cuBLAS writes it as ldc=n stridec=m*n from its offset
@@ -9,13 +9,6 @@
9
9
  rb_define_const(<%=ns_var%>, "<%=x%>", <%=type_var%>);
10
10
  <% end %>
11
11
 
12
- hCast = rb_hash_new();
13
- rb_define_const(cT, "UPCAST", hCast);
14
- rb_hash_aset(hCast, rb_cArray, cT);
15
- <% for x in upcast %>
16
- <%= x %><% end %>
17
- rb_obj_freeze(hCast);
18
-
19
12
  <% @children.each do |m| %>
20
13
  <%= m.init_def %><% end %>
21
14
  rb_define_singleton_method(cT, "[]", <%=find("cast").c_func%>, -2);
@@ -0,0 +1,6 @@
1
+ hCast = rb_hash_new();
2
+ rb_define_const(cT, "UPCAST", hCast);
3
+ rb_hash_aset(hCast, rb_cArray, cT);
4
+ <% for x in upcast %>
5
+ <%= x %><% end %>
6
+ rb_obj_freeze(hCast);
@@ -17,6 +17,6 @@ static VALUE
17
17
  <%=c_func(0)%>(VALUE ary)
18
18
  {
19
19
  CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>");
20
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
20
+ cumo_cuda_runtime_device_synchronize();
21
21
  return cumo_na_ndloop_inspect(ary, <%=c_iter%>, Qnil);
22
22
  }
@@ -37,7 +37,7 @@ extern VALUE cRT;
37
37
  void
38
38
  Init_<%=lib_name%>(void)
39
39
  {
40
- VALUE hCast, <%=ns_var%>;
40
+ VALUE <%=ns_var%>;
41
41
 
42
42
  <%=ns_var%> = rb_define_module("Cumo");
43
43
 
@@ -48,3 +48,13 @@ Init_<%=lib_name%>(void)
48
48
  <%= c.init_def %>
49
49
  <% end %>
50
50
  }
51
+
52
+ // cumo.c runs this after the last Init_cumo_*. Any class defined after this
53
+ // one is still 0 during Init, and its entry would land under the key false.
54
+ void
55
+ Init_<%=lib_name%>_upcast(void)
56
+ {
57
+ VALUE hCast;
58
+
59
+ <% children.each do |c| %><%= c.upcast_def %><% end %>
60
+ }
@@ -1,15 +1,7 @@
1
1
  static inline dtype
2
2
  yield_map_with_index(dtype x, size_t *c, VALUE *a, int nd, int md)
3
3
  {
4
- int j;
5
- VALUE y;
6
-
7
- a[0] = m_data_to_num(x);
8
- for (j=0; j<=nd; j++) {
9
- a[j+1] = SIZET2NUM(c[j]);
10
- }
11
- y = rb_yield(rb_ary_new4(md,a));
12
- return m_num_to_data(y);
4
+ return m_num_to_data(cumo_na_yield_with_index(m_data_to_num(x),c,a,nd,md));
13
5
  }
14
6
 
15
7
  static void
@@ -25,17 +17,14 @@ static void
25
17
  int nd, md;
26
18
 
27
19
  c = (size_t*)(lp->opt_ptr);
28
- nd = lp->ndim;
29
- if (nd > 0) {nd--;}
30
- md = nd + 2;
20
+ cumo_na_with_index_dims(lp->ndim, &nd, &md);
31
21
  a = ALLOCA_N(VALUE,md);
32
22
 
33
23
  CUMO_INIT_COUNTER(lp, i);
34
24
  CUMO_INIT_PTR_IDX(lp, 0, p1, s1, idx1);
35
25
  CUMO_INIT_PTR_IDX(lp, 1, p2, s2, idx2);
36
26
 
37
- CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>");
38
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
27
+ if (cumo_cuda_runtime_sync_if_busy()) { CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>"); }
39
28
 
40
29
  c[nd] = 0;
41
30
  if (idx1) {
@@ -43,6 +32,7 @@ static void
43
32
  for (; i--;) {
44
33
  CUMO_GET_DATA_INDEX(p1,idx1,dtype,x);
45
34
  x = yield_map_with_index(x,c,a,nd,md);
35
+ if (cumo_cuda_runtime_sync_if_busy()) { CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>"); }
46
36
  CUMO_SET_DATA_INDEX(p2,idx2,dtype,x);
47
37
  c[nd]++;
48
38
  }
@@ -50,6 +40,7 @@ static void
50
40
  for (; i--;) {
51
41
  CUMO_GET_DATA_INDEX(p1,idx1,dtype,x);
52
42
  x = yield_map_with_index(x,c,a,nd,md);
43
+ if (cumo_cuda_runtime_sync_if_busy()) { CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>"); }
53
44
  CUMO_SET_DATA_STRIDE(p2,s2,dtype,x);
54
45
  c[nd]++;
55
46
  }
@@ -59,6 +50,7 @@ static void
59
50
  for (; i--;) {
60
51
  CUMO_GET_DATA_STRIDE(p1,s1,dtype,x);
61
52
  x = yield_map_with_index(x,c,a,nd,md);
53
+ if (cumo_cuda_runtime_sync_if_busy()) { CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>"); }
62
54
  CUMO_SET_DATA_INDEX(p2,idx2,dtype,x);
63
55
  c[nd]++;
64
56
  }
@@ -66,6 +58,7 @@ static void
66
58
  for (; i--;) {
67
59
  CUMO_GET_DATA_STRIDE(p1,s1,dtype,x);
68
60
  x = yield_map_with_index(x,c,a,nd,md);
61
+ if (cumo_cuda_runtime_sync_if_busy()) { CUMO_SHOW_SYNCHRONIZE_WARNING_ONCE("<%=name%>", "<%=type_name%>"); }
69
62
  CUMO_SET_DATA_STRIDE(p2,s2,dtype,x);
70
63
  c[nd]++;
71
64
  }
@@ -1,10 +1,11 @@
1
- void cumo_<%=type_name%>_median_kernel_launch(cumo_na_reduction_arg_t* arg, int flat);
1
+ void cumo_<%=type_name%>_median_kernel_launch(cumo_na_reduction_arg_t* arg, int flat, int prnan);
2
2
 
3
3
  // The rows are sorted with one cub call and the middle of each is picked by a
4
- // kernel of its own. nan:true keeps the host path, as sort does: its comparator
5
- // leaves NaN unordered, so there is no sorted array to take a middle of.
4
+ // kernel of its own. The sort keys put every NaN last, so nan:true only has to
5
+ // notice that one is there.
6
+ <% (is_float ? ["_ignan","_prnan"] : [""]).each do |j| %>
6
7
  static void
7
- <%=c_iter%>_kernel(cumo_na_loop_t *const lp)
8
+ <%=c_iter%><%=j%>(cumo_na_loop_t *const lp)
8
9
  {
9
10
  cumo_na_reduction_arg_t arg = cumo_na_make_reduction_arg(lp, 1);
10
11
  ssize_t expect = sizeof(dtype);
@@ -19,41 +20,7 @@ static void
19
20
  expect *= (ssize_t)arg.in_indexer.shape[i];
20
21
  }
21
22
 
22
- cumo_<%=type_name%>_median_kernel_launch(&arg, flat);
23
- }
24
-
25
- <% (is_float ? ["_ignan","_prnan"] : [""]).each do |j| %>
26
- static void
27
- <%=c_iter%><%=j%>(cumo_na_loop_t *const lp)
28
- {
29
- size_t n;
30
- char *p1, *p2;
31
- dtype *buf;
32
-
33
- CUMO_INIT_COUNTER(lp, n);
34
- p1 = (lp->args[0]).ptr + (lp->args[0].iter[0]).pos;
35
- p2 = (lp->args[1]).ptr + (lp->args[1].iter[0]).pos;
36
- buf = (dtype*)p1;
37
-
38
- CUMO_SHOW_SYNCHRONIZE_FIXME_WARNING_ONCE("<%=name%><%=j%>", "<%=type_name%>");
39
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
40
- <%=type_name%>_qsort<%=j%>(buf, n, sizeof(dtype));
41
-
42
- <% if is_float %>
43
- for (; n; n--) {
44
- if (!isnan(buf[n-1])) break;
45
- }
46
- <% end %>
47
-
48
- if (n==0) {
49
- *(dtype*)p2 = buf[0];
50
- }
51
- else if (n%2==0) {
52
- *(dtype*)p2 = (buf[n/2-1]+buf[n/2])/2;
53
- }
54
- else {
55
- *(dtype*)p2 = buf[(n-1)/2];
56
- }
23
+ cumo_<%=type_name%>_median_kernel_launch(&arg, flat, <%= j == "_prnan" ? 1 : 0 %>);
57
24
  }
58
25
  <% end %>
59
26
 
@@ -82,18 +49,13 @@ static VALUE
82
49
  <% if is_float %>
83
50
  ndf.func = <%=c_iter%>_ignan;
84
51
  reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_prnan);
85
- if (ndf.func == <%=c_iter%>_ignan) {
86
- ndf.func = <%=c_iter%>_kernel;
87
- // or rather than assign: cumo_na_reduce_dimension may have set
88
- // CUMO_NDF_KEEP_DIM by then, and assigning would drop it
89
- ndf.flag |= CUMO_NDF_STRIDE_LOOP|CUMO_NDF_INDEXER_LOOP;
90
- }
91
52
  <% else %>
92
53
  ndf.func = <%=c_iter%>;
93
54
  reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
94
- ndf.func = <%=c_iter%>_kernel;
95
- ndf.flag |= CUMO_NDF_STRIDE_LOOP|CUMO_NDF_INDEXER_LOOP;
96
55
  <% end %>
56
+ // or rather than assign: cumo_na_reduce_dimension may have set
57
+ // CUMO_NDF_KEEP_DIM by then, and assigning would drop it
58
+ ndf.flag |= CUMO_NDF_STRIDE_LOOP|CUMO_NDF_INDEXER_LOOP;
97
59
  v = cumo_na_ndloop(&ndf, 2, self, reduce);
98
60
  return <%=type_name%>_extract(v);
99
61
  }
@@ -20,7 +20,7 @@ static void
20
20
  CUMO_INIT_PTR(lp, 0, p1, s1);
21
21
 
22
22
  CUMO_SHOW_SYNCHRONIZE_FIXME_WARNING_ONCE("<%=name%><%=j%>", "<%=type_name%>");
23
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
23
+ cumo_cuda_runtime_device_synchronize();
24
24
  f_<%=name%><%=j%>(n,p1,s1,&xmin,&xmax);
25
25
 
26
26
  *(dtype*)(lp->args[1].ptr + lp->args[1].iter[0].pos) = xmin;
@@ -27,7 +27,7 @@ static void
27
27
  dtype x, y, a;
28
28
 
29
29
  CUMO_SHOW_SYNCHRONIZE_FIXME_WARNING_ONCE("<%=name%>", "<%=type_name%>");
30
- cumo_cuda_runtime_check_status(cudaDeviceSynchronize());
30
+ cumo_cuda_runtime_device_synchronize();
31
31
  n = lp->narg - 2;
32
32
  x = *(dtype*)CUMO_NDL_PTR(lp,0);
33
33
  y = *(dtype*)CUMO_NDL_PTR(lp,n);
@@ -1,17 +1,5 @@
1
1
  #ifdef CUDNN_FOUND
2
2
 
3
- <%
4
- cudnn_dtype =
5
- case type_name
6
- when 'sfloat'
7
- 'CUDNN_DATA_FLOAT'
8
- when 'dfloat'
9
- 'CUDNN_DATA_DOUBLE'
10
- else
11
- # CUDNN_DATA_HALF
12
- raise 'not supported'
13
- end
14
- %>
15
3
 
16
4
  // cover_all=true is not supported with CUDNN
17
5
  // gy = x.pooling_backward(mode, y, kernel_size, stride: 1, pad: 0)
@@ -25,8 +13,8 @@ static VALUE
25
13
  cudnnDataType_t cudnn_dtype = <%= cudnn_dtype %>;
26
14
  cudnnStatus_t status = 0;
27
15
  cudnnHandle_t handle = 0;
28
- dtype alpha = 1;
29
- dtype beta = 0;
16
+ <%=cudnn_scalar_t%> alpha = 1;
17
+ <%=cudnn_scalar_t%> beta = 0;
30
18
 
31
19
  VALUE x=self, y, gy, mode, kernel_size, stride, pad, gx;
32
20
  VALUE kw_hash = Qnil;