carray 3.0.1 → 3.0.3
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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_sweep_engine.c
CHANGED
|
@@ -22,45 +22,161 @@
|
|
|
22
22
|
#include "ca_for_buffer.h"
|
|
23
23
|
#include <string.h>
|
|
24
24
|
|
|
25
|
+
/* "[2, 3]" for an operand's shape. */
|
|
26
|
+
static VALUE
|
|
27
|
+
ca_sweep_shape_str (CArray *ca)
|
|
28
|
+
{
|
|
29
|
+
volatile VALUE s = rb_str_new_cstr("[");
|
|
30
|
+
int k;
|
|
31
|
+
for (k = 0; k < ca->ndim; k++) {
|
|
32
|
+
if (k > 0) rb_str_cat_cstr(s, ", ");
|
|
33
|
+
rb_str_catf(s, "%lld", (long long) ca->dim[k]);
|
|
34
|
+
}
|
|
35
|
+
rb_str_cat_cstr(s, "]");
|
|
36
|
+
return s;
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
void
|
|
26
|
-
|
|
40
|
+
ca_sweep_refuse_shapes (CArray *a, CArray *b)
|
|
27
41
|
{
|
|
42
|
+
volatile VALUE sa = ca_sweep_shape_str(a);
|
|
43
|
+
volatile VALUE sb = ca_sweep_shape_str(b);
|
|
44
|
+
rb_raise(rb_eArgError,
|
|
45
|
+
"shape mismatch between operands (%s and %s); a scalar pairs "
|
|
46
|
+
"with any array, two arrays only when their shapes agree",
|
|
47
|
+
StringValueCStr(sa), StringValueCStr(sb));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
int
|
|
51
|
+
ca_sweep_same_shape (CArray *a, CArray *b)
|
|
52
|
+
{
|
|
53
|
+
int k;
|
|
54
|
+
if (a->ndim != b->ndim) return 0;
|
|
55
|
+
for (k = 0; k < a->ndim; k++) {
|
|
56
|
+
if (a->dim[k] != b->dim[k]) return 0;
|
|
57
|
+
}
|
|
58
|
+
return 1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Pair the operands: a scalar walks with stride 0, every other operand
|
|
62
|
+
* must have the shape of the first non-scalar one, which is returned (NULL
|
|
63
|
+
* when all operands are scalars). Sets stride[] and n_kernel. Allocates
|
|
64
|
+
* nothing, so it runs before any operand is acquired. */
|
|
65
|
+
static CArray *
|
|
66
|
+
ca_sweep_pair_operands (ca_sweep_state_t *st)
|
|
67
|
+
{
|
|
68
|
+
CArray *donor = NULL;
|
|
28
69
|
int k_op;
|
|
29
|
-
|
|
70
|
+
st->n_kernel = 1;
|
|
71
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
72
|
+
CArray *ca = st->cx[k_op];
|
|
73
|
+
if (ca_is_scalar(ca)) {
|
|
74
|
+
st->stride[k_op] = 0;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
st->stride[k_op] = ca->bytes;
|
|
78
|
+
if (!donor) {
|
|
79
|
+
donor = ca;
|
|
80
|
+
st->n_kernel = ca->elements;
|
|
81
|
+
} else if (!ca_sweep_same_shape(donor, ca)) {
|
|
82
|
+
ca_sweep_refuse_shapes(donor, ca);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return donor;
|
|
86
|
+
}
|
|
30
87
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
88
|
+
/* Non-zero when INPUT k_op lives in the same root as an OUTPUT other
|
|
89
|
+
* than itself. Read in place, or chunk by chunk after earlier chunks
|
|
90
|
+
* were written, it would show the kernel cells already written; such an
|
|
91
|
+
* input is read whole before the walk. An input that is the output
|
|
92
|
+
* itself is read in place: each cell is read before it is written. */
|
|
93
|
+
static int
|
|
94
|
+
ca_sweep_input_overlaps_output (ca_sweep_state_t *st, int k_op)
|
|
95
|
+
{
|
|
96
|
+
int j;
|
|
97
|
+
CArray *ca = st->cx[k_op];
|
|
98
|
+
if (st->fsync[k_op] != '0' || ca_is_scalar(ca)) return 0;
|
|
99
|
+
for (j = 0; j < st->n_ops; j++) {
|
|
100
|
+
if (st->fsync[j] == '1' && st->cx[j] != ca &&
|
|
101
|
+
ca_shares_root(ca, st->cx[j])) {
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
36
104
|
}
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
37
107
|
|
|
108
|
+
/* Non-zero when any INPUT operand carries a mask. Asks, allocates
|
|
109
|
+
* nothing. */
|
|
110
|
+
static int
|
|
111
|
+
ca_sweep_any_input_mask (ca_sweep_state_t *st)
|
|
112
|
+
{
|
|
113
|
+
int k_op;
|
|
38
114
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
39
|
-
st->
|
|
115
|
+
if (st->fsync[k_op] == '0' && ca_has_mask(st->cx[k_op])) return 1;
|
|
116
|
+
}
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Give back everything acquire has taken so far, without syncing: detach
|
|
121
|
+
* attached operands, free owned scratch (xmalloc on the whole-buffer path,
|
|
122
|
+
* arena on the chunked one) and the mask buffers. Called when a read
|
|
123
|
+
* raises part way through, so that the raise leaves nothing attached or
|
|
124
|
+
* allocated behind it. */
|
|
125
|
+
static void
|
|
126
|
+
ca_sweep_abort (ca_sweep_state_t *st, int chunked)
|
|
127
|
+
{
|
|
128
|
+
int k_op;
|
|
129
|
+
for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
|
|
130
|
+
if (st->attached[k_op]) {
|
|
131
|
+
st->attached[k_op] = 0;
|
|
132
|
+
ca_detach(st->cx[k_op]);
|
|
133
|
+
} else if (st->owned_buf[k_op]) {
|
|
134
|
+
if (chunked) ca_lazy_arena_release(st->owned_buf[k_op]);
|
|
135
|
+
else xfree(st->owned_buf[k_op]);
|
|
136
|
+
}
|
|
40
137
|
st->owned_buf[k_op] = NULL;
|
|
41
|
-
st->attached[k_op] = 0;
|
|
42
138
|
}
|
|
43
|
-
st->m0
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
139
|
+
if (st->m0) {
|
|
140
|
+
if (chunked) ca_lazy_arena_release(st->m0);
|
|
141
|
+
else xfree(st->m0);
|
|
142
|
+
st->m0 = NULL;
|
|
143
|
+
}
|
|
144
|
+
if (chunked && st->mask_scratch) {
|
|
145
|
+
ca_lazy_arena_release(st->mask_scratch);
|
|
146
|
+
st->mask_scratch = NULL;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
typedef struct {
|
|
151
|
+
ca_sweep_state_t *st;
|
|
152
|
+
int any_input_mask;
|
|
153
|
+
boolean8_t *ms; /* per-operand mask staging, whole path */
|
|
154
|
+
} ca_sweep_acquire_ctx_t;
|
|
155
|
+
|
|
156
|
+
/* The part of acquire that takes resources and reads operands, and so can
|
|
157
|
+
* raise holding them. Runs under rb_protect; every buffer is recorded in
|
|
158
|
+
* the state (or the ctx) before the read that may raise. */
|
|
159
|
+
static VALUE
|
|
160
|
+
ca_sweep_acquire_body (VALUE arg)
|
|
161
|
+
{
|
|
162
|
+
ca_sweep_acquire_ctx_t *ctx = (ca_sweep_acquire_ctx_t *) arg;
|
|
163
|
+
ca_sweep_state_t *st = ctx->st;
|
|
164
|
+
int k_op;
|
|
47
165
|
|
|
48
166
|
/* Per-operand acquire:
|
|
49
167
|
* OUTPUT (fsync == '1') -> ca_attach + base = ca->ptr
|
|
50
168
|
* INPUT alias -> ca_attach + base = ca->ptr
|
|
51
|
-
* INPUT non-alias non-scalar
|
|
169
|
+
* INPUT non-alias non-scalar,
|
|
170
|
+
* or sharing an OUTPUT's root -> xmalloc scratch + ca_xfer_all
|
|
52
171
|
* INPUT non-alias never attaches the operand itself; the scratch
|
|
53
172
|
* copy carries the values into the kernel. */
|
|
54
173
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
55
174
|
CArray *ca = st->cx[k_op];
|
|
56
|
-
if (st->fsync[k_op] == '1'
|
|
175
|
+
if (st->fsync[k_op] == '1' ||
|
|
176
|
+
(ca_attach_is_alias(ca) && ! ca_sweep_input_overlaps_output(st, k_op))) {
|
|
57
177
|
ca_attach(ca);
|
|
58
|
-
st->base[k_op] = (char *) ca->ptr;
|
|
59
178
|
st->attached[k_op] = 1;
|
|
60
|
-
} else if (ca_attach_is_alias(ca)) {
|
|
61
|
-
ca_attach(ca);
|
|
62
179
|
st->base[k_op] = (char *) ca->ptr;
|
|
63
|
-
st->attached[k_op] = 1;
|
|
64
180
|
} else {
|
|
65
181
|
ca_size_t bytes_total = ca->elements * ca->bytes;
|
|
66
182
|
st->owned_buf[k_op] = xmalloc(bytes_total);
|
|
@@ -69,36 +185,9 @@ ca_sweep_acquire (ca_sweep_state_t *st)
|
|
|
69
185
|
}
|
|
70
186
|
}
|
|
71
187
|
|
|
72
|
-
/* compute n_kernel (= broadcast shape) and per-cell strides */
|
|
73
|
-
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
74
|
-
CArray *ca = st->cx[k_op];
|
|
75
|
-
if (ca_is_scalar(ca)) {
|
|
76
|
-
st->stride[k_op] = 0;
|
|
77
|
-
} else {
|
|
78
|
-
st->stride[k_op] = ca->bytes;
|
|
79
|
-
if (st->n_kernel == 1) {
|
|
80
|
-
st->n_kernel = ca->elements;
|
|
81
|
-
} else if (ca->elements != st->n_kernel) {
|
|
82
|
-
rb_raise(rb_eRuntimeError, "data size mismatch in operation");
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
188
|
/* iter mask m0 = OR of INPUT operand masks, gathered via ca_xfer_all
|
|
88
189
|
so no operand mask attach happens. Stays NULL if no INPUT masks. */
|
|
89
|
-
|
|
90
|
-
if (st->fsync[k_op] == '0' && ca_has_mask(st->cx[k_op])) {
|
|
91
|
-
any_input_mask = 1;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (any_input_mask && st->no_mask) {
|
|
96
|
-
rb_raise(rb_eRuntimeError,
|
|
97
|
-
"%s: masked INPUT not allowed in NO_MASK form "
|
|
98
|
-
"(use the *_MASKED form to handle masked cells explicitly)",
|
|
99
|
-
st->src_label ? st->src_label : "ca_sweep_acquire");
|
|
100
|
-
}
|
|
101
|
-
if (any_input_mask) {
|
|
190
|
+
if (ctx->any_input_mask) {
|
|
102
191
|
st->m0 = xmalloc(st->n_kernel);
|
|
103
192
|
memset(st->m0, 0, st->n_kernel);
|
|
104
193
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
@@ -111,11 +200,10 @@ ca_sweep_acquire (ca_sweep_state_t *st)
|
|
|
111
200
|
ca_xfer_all(ca->mask, &bit, CA_XFER_GET);
|
|
112
201
|
if (bit) memset(st->m0, 1, st->n_kernel);
|
|
113
202
|
} else {
|
|
114
|
-
boolean8_t *ms = xmalloc(st->n_kernel);
|
|
115
203
|
ca_size_t j;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
204
|
+
if (!ctx->ms) ctx->ms = xmalloc(st->n_kernel);
|
|
205
|
+
ca_xfer_all(ca->mask, ctx->ms, CA_XFER_GET);
|
|
206
|
+
for (j = 0; j < st->n_kernel; j++) st->m0[j] |= ctx->ms[j];
|
|
119
207
|
}
|
|
120
208
|
}
|
|
121
209
|
}
|
|
@@ -126,21 +214,130 @@ ca_sweep_acquire (ca_sweep_state_t *st)
|
|
|
126
214
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
127
215
|
CArray *ca = st->cx[k_op];
|
|
128
216
|
if (st->fsync[k_op] != '1') continue;
|
|
129
|
-
|
|
130
|
-
if (!ca->mask) ca_create_mask(ca);
|
|
217
|
+
ca_create_mask(ca);
|
|
131
218
|
memcpy(ca->mask->ptr, st->m0, st->n_kernel);
|
|
132
219
|
}
|
|
133
220
|
}
|
|
221
|
+
return Qnil;
|
|
134
222
|
}
|
|
135
223
|
|
|
136
224
|
void
|
|
137
|
-
|
|
225
|
+
ca_sweep_acquire (ca_sweep_state_t *st)
|
|
138
226
|
{
|
|
227
|
+
ca_sweep_acquire_ctx_t ctx;
|
|
139
228
|
int k_op;
|
|
140
|
-
|
|
229
|
+
int tag = 0;
|
|
230
|
+
|
|
231
|
+
if ((int) strlen(st->fsync) != st->n_ops) {
|
|
232
|
+
rb_raise(rb_eRuntimeError,
|
|
233
|
+
"[BUG] invalid length of fsync arg in %s (expected %d)",
|
|
234
|
+
st->src_label ? st->src_label : "ca_sweep_acquire",
|
|
235
|
+
st->n_ops);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
239
|
+
st->base[k_op] = NULL;
|
|
240
|
+
st->owned_buf[k_op] = NULL;
|
|
241
|
+
st->attached[k_op] = 0;
|
|
242
|
+
}
|
|
243
|
+
st->m0 = NULL;
|
|
244
|
+
|
|
245
|
+
/* Refusals come first, while nothing is held. */
|
|
246
|
+
ca_sweep_pair_operands(st);
|
|
247
|
+
ctx.st = st;
|
|
248
|
+
ctx.ms = NULL;
|
|
249
|
+
ctx.any_input_mask = ca_sweep_any_input_mask(st);
|
|
250
|
+
|
|
251
|
+
rb_protect(ca_sweep_acquire_body, (VALUE) &ctx, &tag);
|
|
252
|
+
if (ctx.ms) xfree(ctx.ms);
|
|
253
|
+
if (tag) {
|
|
254
|
+
ca_sweep_abort(st, 0);
|
|
255
|
+
rb_jump_tag(tag);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
void
|
|
260
|
+
ca_sweep_run (ca_sweep_state_t *st, VALUE (*walk)(VALUE), VALUE arg)
|
|
261
|
+
{
|
|
262
|
+
int tag = 0;
|
|
263
|
+
rb_protect(walk, arg, &tag);
|
|
264
|
+
if (tag) {
|
|
265
|
+
ca_sweep_abort(st, 0);
|
|
266
|
+
rb_jump_tag(tag);
|
|
267
|
+
}
|
|
268
|
+
ca_sweep_release(st);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void
|
|
272
|
+
ca_sweep_run_chunked (ca_sweep_state_t *st, VALUE (*walk)(VALUE), VALUE arg)
|
|
273
|
+
{
|
|
274
|
+
int tag = 0;
|
|
275
|
+
rb_protect(walk, arg, &tag);
|
|
276
|
+
if (tag) {
|
|
277
|
+
/* a raise inside ca_sweep_next_chunk has already given back */
|
|
278
|
+
if (st->chunked_state != 3) {
|
|
279
|
+
ca_sweep_abort(st, 1);
|
|
280
|
+
st->chunked_state = 3;
|
|
281
|
+
}
|
|
282
|
+
rb_jump_tag(tag);
|
|
283
|
+
}
|
|
284
|
+
ca_sweep_release_chunked(st);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static VALUE
|
|
288
|
+
ca_sweep_sync_one (VALUE arg)
|
|
289
|
+
{
|
|
290
|
+
ca_sync((CArray *) arg);
|
|
291
|
+
return Qnil;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* Sync the OUTPUTs (reverse order). Writing back through a view's slots
|
|
295
|
+
* can raise (a CAObject's store hook); the raise is held so that release
|
|
296
|
+
* still detaches and frees everything, and ca_sweep_reraise propagates
|
|
297
|
+
* it afterwards. An entity's sync does nothing that can raise, so it is
|
|
298
|
+
* called directly: the outputs this library allocates itself pay nothing. */
|
|
299
|
+
static int
|
|
300
|
+
ca_sweep_sync_outputs (ca_sweep_state_t *st, volatile VALUE *error)
|
|
301
|
+
{
|
|
302
|
+
int k_op, first = 0;
|
|
141
303
|
for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
|
|
142
|
-
|
|
304
|
+
CArray *ca = st->cx[k_op];
|
|
305
|
+
if (st->fsync[k_op] != '1') {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (ca_is_entity(ca)) {
|
|
309
|
+
ca_sync(ca);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
int tag = 0;
|
|
313
|
+
rb_protect(ca_sweep_sync_one, (VALUE) ca, &tag);
|
|
314
|
+
if (tag) {
|
|
315
|
+
if (! first) {
|
|
316
|
+
first = tag;
|
|
317
|
+
*error = rb_errinfo();
|
|
318
|
+
}
|
|
319
|
+
rb_set_errinfo(Qnil);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
143
322
|
}
|
|
323
|
+
return first;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static void
|
|
327
|
+
ca_sweep_reraise (int tag, VALUE error)
|
|
328
|
+
{
|
|
329
|
+
if (tag) {
|
|
330
|
+
rb_set_errinfo(error);
|
|
331
|
+
rb_jump_tag(tag);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
void
|
|
336
|
+
ca_sweep_release (ca_sweep_state_t *st)
|
|
337
|
+
{
|
|
338
|
+
int k_op;
|
|
339
|
+
volatile VALUE error = Qnil;
|
|
340
|
+
int tag = ca_sweep_sync_outputs(st, &error);
|
|
144
341
|
/* detach attached / xfree owned buffers (reverse order) */
|
|
145
342
|
for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
|
|
146
343
|
if (st->attached[k_op]) {
|
|
@@ -154,86 +351,32 @@ ca_sweep_release (ca_sweep_state_t *st)
|
|
|
154
351
|
xfree(st->m0);
|
|
155
352
|
st->m0 = NULL;
|
|
156
353
|
}
|
|
354
|
+
ca_sweep_reraise(tag, error);
|
|
157
355
|
}
|
|
158
356
|
|
|
159
357
|
/* ===== Chunked path implementation ===== */
|
|
160
358
|
|
|
161
|
-
|
|
162
|
-
|
|
359
|
+
static VALUE
|
|
360
|
+
ca_sweep_acquire_chunked_body (VALUE arg)
|
|
163
361
|
{
|
|
362
|
+
ca_sweep_acquire_ctx_t *ctx = (ca_sweep_acquire_ctx_t *) arg;
|
|
363
|
+
ca_sweep_state_t *st = ctx->st;
|
|
164
364
|
int k_op;
|
|
165
|
-
int any_input_mask = 0;
|
|
166
|
-
CArray *shape_donor = NULL;
|
|
167
|
-
|
|
168
|
-
if ((int) strlen(st->fsync) != st->n_ops) {
|
|
169
|
-
rb_raise(rb_eRuntimeError,
|
|
170
|
-
"[BUG] invalid length of fsync arg in %s (expected %d)",
|
|
171
|
-
st->src_label ? st->src_label : "ca_sweep_acquire_chunked",
|
|
172
|
-
st->n_ops);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
176
|
-
st->base[k_op] = NULL;
|
|
177
|
-
st->base_orig[k_op] = NULL;
|
|
178
|
-
st->owned_buf[k_op] = NULL;
|
|
179
|
-
st->attached[k_op] = 0;
|
|
180
|
-
}
|
|
181
|
-
st->m0 = NULL;
|
|
182
|
-
st->mask_scratch = NULL;
|
|
183
|
-
st->n_kernel = 1;
|
|
184
|
-
st->chunk_off = 0;
|
|
185
|
-
st->chunk_n = 0;
|
|
186
|
-
st->chunk_n_max = 0;
|
|
187
|
-
st->inner = 1;
|
|
188
|
-
st->chunked_state = 0;
|
|
189
|
-
|
|
190
|
-
/* compute broadcast shape (n_kernel + strides) from operand shapes.
|
|
191
|
-
* scalar operands collapse to stride 0; non-scalar operands must agree
|
|
192
|
-
* on element count. shape_donor is the first non-scalar operand and
|
|
193
|
-
* defines the chunking inner-axis size. */
|
|
194
|
-
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
195
|
-
CArray *ca = st->cx[k_op];
|
|
196
|
-
if (ca_is_scalar(ca)) {
|
|
197
|
-
st->stride[k_op] = 0;
|
|
198
|
-
} else {
|
|
199
|
-
st->stride[k_op] = ca->bytes;
|
|
200
|
-
if (st->n_kernel == 1) {
|
|
201
|
-
st->n_kernel = ca->elements;
|
|
202
|
-
shape_donor = ca;
|
|
203
|
-
} else if (ca->elements != st->n_kernel) {
|
|
204
|
-
rb_raise(rb_eRuntimeError, "data size mismatch in operation");
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* chunk-size policy: inner = donor's product of dims[1..]; chunk_n_max
|
|
210
|
-
* = compute_n on donor->bytes (= type-dependent 32KB target). */
|
|
211
|
-
if (shape_donor) {
|
|
212
|
-
st->inner = ca_chunk_inner_size(shape_donor);
|
|
213
|
-
st->chunk_n_max = ca_chunk_compute_n(st->n_kernel, st->inner,
|
|
214
|
-
shape_donor->bytes);
|
|
215
|
-
} else {
|
|
216
|
-
/* all-scalar: single 1-cell chunk */
|
|
217
|
-
st->inner = 1;
|
|
218
|
-
st->chunk_n_max = 1;
|
|
219
|
-
}
|
|
220
365
|
|
|
221
366
|
/* per-operand acquire:
|
|
222
367
|
* OUTPUT (fsync == '1') : ca_attach + base_orig = ca->ptr (legitimate)
|
|
223
368
|
* INPUT alias : ca_attach + base_orig = ca->ptr (zero-copy)
|
|
224
|
-
* INPUT non-alias non-scalar
|
|
369
|
+
* INPUT non-alias non-scalar,
|
|
370
|
+
* or sharing an OUTPUT's root : arena chunk scratch of chunk_n_max bytes
|
|
225
371
|
* INPUT scalar : ca_attach + base_orig = ca->ptr (1 cell)
|
|
226
372
|
*/
|
|
227
373
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
228
374
|
CArray *ca = st->cx[k_op];
|
|
229
|
-
if (st->fsync[k_op] == '1')
|
|
375
|
+
if (st->fsync[k_op] == '1' || ca_is_scalar(ca) ||
|
|
376
|
+
(ca_attach_is_alias(ca) && ! ca_sweep_input_overlaps_output(st, k_op))) {
|
|
230
377
|
ca_attach(ca);
|
|
231
|
-
st->base_orig[k_op] = (char *) ca->ptr;
|
|
232
378
|
st->attached[k_op] = 1;
|
|
233
|
-
} else if (ca_is_scalar(ca) || ca_attach_is_alias(ca)) {
|
|
234
|
-
ca_attach(ca);
|
|
235
379
|
st->base_orig[k_op] = (char *) ca->ptr;
|
|
236
|
-
st->attached[k_op] = 1;
|
|
237
380
|
} else {
|
|
238
381
|
/* non-alias non-scalar INPUT: arena scratch sized for chunk_n_max */
|
|
239
382
|
ca_size_t scratch_bytes = st->chunk_n_max * ca->bytes;
|
|
@@ -251,19 +394,7 @@ ca_sweep_acquire_chunked (ca_sweep_state_t *st)
|
|
|
251
394
|
* scaling with the operand, which is the thing this path exists to avoid:
|
|
252
395
|
* at 1 byte per cell it is an eighth of an f64 operand, but an eighth of
|
|
253
396
|
* unbounded is still unbounded. */
|
|
254
|
-
|
|
255
|
-
if (st->fsync[k_op] == '0' && ca_has_mask(st->cx[k_op])) {
|
|
256
|
-
any_input_mask = 1;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
if (any_input_mask && st->no_mask) {
|
|
261
|
-
rb_raise(rb_eRuntimeError,
|
|
262
|
-
"%s: masked INPUT not allowed in NO_MASK form "
|
|
263
|
-
"(use the *_MASKED form to handle masked cells explicitly)",
|
|
264
|
-
st->src_label ? st->src_label : "ca_sweep_acquire_chunked");
|
|
265
|
-
}
|
|
266
|
-
if (any_input_mask) {
|
|
397
|
+
if (ctx->any_input_mask) {
|
|
267
398
|
st->m0 = (boolean8_t *) ca_lazy_arena_acquire(st->chunk_n_max);
|
|
268
399
|
st->mask_scratch = (boolean8_t *) ca_lazy_arena_acquire(st->chunk_n_max);
|
|
269
400
|
memset(st->m0, 0, st->chunk_n_max);
|
|
@@ -273,8 +404,7 @@ ca_sweep_acquire_chunked (ca_sweep_state_t *st)
|
|
|
273
404
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
274
405
|
CArray *ca = st->cx[k_op];
|
|
275
406
|
if (st->fsync[k_op] != '1') continue;
|
|
276
|
-
|
|
277
|
-
if (!ca->mask) ca_create_mask(ca);
|
|
407
|
+
ca_create_mask(ca);
|
|
278
408
|
}
|
|
279
409
|
}
|
|
280
410
|
|
|
@@ -283,6 +413,75 @@ ca_sweep_acquire_chunked (ca_sweep_state_t *st)
|
|
|
283
413
|
* once more in release), never at acquire. Author per-cell m_out writes
|
|
284
414
|
* land in m0 during the chunk loop and must be captured after that loop
|
|
285
415
|
* has run, not before it. */
|
|
416
|
+
return Qnil;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
void
|
|
420
|
+
ca_sweep_acquire_chunked (ca_sweep_state_t *st)
|
|
421
|
+
{
|
|
422
|
+
ca_sweep_acquire_ctx_t ctx;
|
|
423
|
+
int k_op;
|
|
424
|
+
int tag = 0;
|
|
425
|
+
CArray *shape_donor = NULL;
|
|
426
|
+
|
|
427
|
+
if ((int) strlen(st->fsync) != st->n_ops) {
|
|
428
|
+
rb_raise(rb_eRuntimeError,
|
|
429
|
+
"[BUG] invalid length of fsync arg in %s (expected %d)",
|
|
430
|
+
st->src_label ? st->src_label : "ca_sweep_acquire_chunked",
|
|
431
|
+
st->n_ops);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
435
|
+
st->base[k_op] = NULL;
|
|
436
|
+
st->base_orig[k_op] = NULL;
|
|
437
|
+
st->owned_buf[k_op] = NULL;
|
|
438
|
+
st->attached[k_op] = 0;
|
|
439
|
+
}
|
|
440
|
+
st->m0 = NULL;
|
|
441
|
+
st->mask_scratch = NULL;
|
|
442
|
+
st->chunk_off = 0;
|
|
443
|
+
st->chunk_n = 0;
|
|
444
|
+
st->chunk_n_max = 0;
|
|
445
|
+
st->inner = 1;
|
|
446
|
+
st->chunked_state = 0;
|
|
447
|
+
|
|
448
|
+
/* shape_donor is the first non-scalar operand and defines the chunking
|
|
449
|
+
* inner-axis size. */
|
|
450
|
+
shape_donor = ca_sweep_pair_operands(st);
|
|
451
|
+
|
|
452
|
+
/* chunk-size policy: inner = donor's product of dims[1..]; chunk_n_max
|
|
453
|
+
* = compute_n on donor->bytes (= type-dependent 32KB target). */
|
|
454
|
+
if (shape_donor) {
|
|
455
|
+
st->inner = ca_chunk_inner_size(shape_donor);
|
|
456
|
+
st->chunk_n_max = ca_chunk_compute_n(st->n_kernel, st->inner,
|
|
457
|
+
shape_donor->bytes);
|
|
458
|
+
} else {
|
|
459
|
+
/* all-scalar: single 1-cell chunk */
|
|
460
|
+
st->inner = 1;
|
|
461
|
+
st->chunk_n_max = 1;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/* An INPUT sharing an OUTPUT's root is read whole before anything is
|
|
465
|
+
written: the walk becomes a single chunk, so its data and its mask
|
|
466
|
+
are gathered before the first flush. */
|
|
467
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
468
|
+
if (ca_sweep_input_overlaps_output(st, k_op) && st->n_kernel > 0) {
|
|
469
|
+
st->chunk_n_max = st->n_kernel;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/* Refusals come first, while nothing is held. */
|
|
475
|
+
ctx.st = st;
|
|
476
|
+
ctx.ms = NULL;
|
|
477
|
+
ctx.any_input_mask = ca_sweep_any_input_mask(st);
|
|
478
|
+
|
|
479
|
+
rb_protect(ca_sweep_acquire_chunked_body, (VALUE) &ctx, &tag);
|
|
480
|
+
if (tag) {
|
|
481
|
+
ca_sweep_abort(st, 1);
|
|
482
|
+
st->chunked_state = 3;
|
|
483
|
+
rb_jump_tag(tag);
|
|
484
|
+
}
|
|
286
485
|
}
|
|
287
486
|
|
|
288
487
|
/* OR one INPUT operand's mask for the current chunk into m0. Gathered via
|
|
@@ -313,9 +512,7 @@ ca_sweep_gather_chunk_mask (ca_sweep_state_t *st, ca_size_t off, ca_size_t n)
|
|
|
313
512
|
}
|
|
314
513
|
}
|
|
315
514
|
|
|
316
|
-
/* Copy the chunk just finished out to every OUTPUT operand's mask.
|
|
317
|
-
* after the author's loop over that chunk, so m_out writes into m0 are
|
|
318
|
-
* carried through. */
|
|
515
|
+
/* Copy the chunk just finished out to every OUTPUT operand's mask. */
|
|
319
516
|
static void
|
|
320
517
|
ca_sweep_flush_chunk_mask (ca_sweep_state_t *st)
|
|
321
518
|
{
|
|
@@ -329,18 +526,46 @@ ca_sweep_flush_chunk_mask (ca_sweep_state_t *st)
|
|
|
329
526
|
}
|
|
330
527
|
}
|
|
331
528
|
|
|
529
|
+
/* Set up base[] for the chunk at chunk_off / chunk_n: gather each
|
|
530
|
+
non-alias INPUT into its arena scratch, then the chunk's mask. */
|
|
531
|
+
static VALUE
|
|
532
|
+
ca_sweep_next_chunk_body (VALUE arg)
|
|
533
|
+
{
|
|
534
|
+
ca_sweep_state_t *st = (ca_sweep_state_t *) arg;
|
|
535
|
+
ca_size_t off = st->chunk_off;
|
|
536
|
+
ca_size_t n = st->chunk_n;
|
|
537
|
+
int k_op;
|
|
538
|
+
|
|
539
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
540
|
+
CArray *ca = st->cx[k_op];
|
|
541
|
+
if (st->stride[k_op] == 0) {
|
|
542
|
+
/* scalar: stride 0, base is the single-cell ptr (base_orig) */
|
|
543
|
+
st->base[k_op] = st->base_orig[k_op];
|
|
544
|
+
} else if (st->base_orig[k_op]) {
|
|
545
|
+
/* alias INPUT or OUTPUT: walk through ca->ptr by chunk_off */
|
|
546
|
+
st->base[k_op] = st->base_orig[k_op] + off * st->stride[k_op];
|
|
547
|
+
} else {
|
|
548
|
+
/* non-alias INPUT: per-chunk gather into owned_buf (arena) */
|
|
549
|
+
ca_chunked_gather(ca, off, n, st->owned_buf[k_op]);
|
|
550
|
+
st->base[k_op] = st->owned_buf[k_op];
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (st->m0) ca_sweep_gather_chunk_mask(st, off, n);
|
|
555
|
+
return Qnil;
|
|
556
|
+
}
|
|
557
|
+
|
|
332
558
|
int
|
|
333
559
|
ca_sweep_next_chunk (ca_sweep_state_t *st)
|
|
334
560
|
{
|
|
335
|
-
int k_op;
|
|
336
561
|
ca_size_t off, n;
|
|
562
|
+
int tag = 0;
|
|
337
563
|
|
|
338
564
|
if (st->chunked_state == 0) {
|
|
339
565
|
/* first chunk */
|
|
340
566
|
st->chunk_off = 0;
|
|
341
567
|
st->chunked_state = 1;
|
|
342
568
|
} else {
|
|
343
|
-
/* the chunk that just finished is the author's last word on its mask */
|
|
344
569
|
ca_sweep_flush_chunk_mask(st);
|
|
345
570
|
/* advance */
|
|
346
571
|
st->chunk_off += st->chunk_n;
|
|
@@ -356,24 +581,16 @@ ca_sweep_next_chunk (ca_sweep_state_t *st)
|
|
|
356
581
|
if (off + n > st->n_kernel) n = st->n_kernel - off;
|
|
357
582
|
st->chunk_n = n;
|
|
358
583
|
|
|
359
|
-
/*
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
st->base[k_op] = st->base_orig[k_op] + off * st->stride[k_op];
|
|
368
|
-
} else {
|
|
369
|
-
/* non-alias INPUT: per-chunk gather into owned_buf (arena) */
|
|
370
|
-
ca_chunked_gather(ca, off, n, st->owned_buf[k_op]);
|
|
371
|
-
st->base[k_op] = st->owned_buf[k_op];
|
|
372
|
-
}
|
|
584
|
+
/* The gathers read the operands and so can raise; a raise gives back
|
|
585
|
+
the walk's resources before it propagates, since the caller's release
|
|
586
|
+
is never reached. */
|
|
587
|
+
rb_protect(ca_sweep_next_chunk_body, (VALUE) st, &tag);
|
|
588
|
+
if (tag) {
|
|
589
|
+
ca_sweep_abort(st, 1);
|
|
590
|
+
st->chunked_state = 3;
|
|
591
|
+
rb_jump_tag(tag);
|
|
373
592
|
}
|
|
374
593
|
|
|
375
|
-
if (st->m0) ca_sweep_gather_chunk_mask(st, off, n);
|
|
376
|
-
|
|
377
594
|
return 1;
|
|
378
595
|
}
|
|
379
596
|
|
|
@@ -381,14 +598,15 @@ void
|
|
|
381
598
|
ca_sweep_release_chunked (ca_sweep_state_t *st)
|
|
382
599
|
{
|
|
383
600
|
int k_op;
|
|
601
|
+
volatile VALUE error = Qnil;
|
|
602
|
+
int tag;
|
|
603
|
+
/* a walk that raised has already given everything back */
|
|
604
|
+
if (st->chunked_state == 3) return;
|
|
384
605
|
/* The final chunk has no next_chunk call to flush it, so it is flushed
|
|
385
|
-
* here.
|
|
386
|
-
* per-cell m_out writes over that last chunk. */
|
|
606
|
+
* here. */
|
|
387
607
|
ca_sweep_flush_chunk_mask(st);
|
|
388
|
-
/* sync OUTPUTs (
|
|
389
|
-
|
|
390
|
-
if (st->fsync[k_op] == '1') ca_sync(st->cx[k_op]);
|
|
391
|
-
}
|
|
608
|
+
/* sync OUTPUTs (regardless of whether chunk loop ran) */
|
|
609
|
+
tag = ca_sweep_sync_outputs(st, &error);
|
|
392
610
|
/* detach attached / release arena scratch buffers (reverse order) */
|
|
393
611
|
for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
|
|
394
612
|
if (st->attached[k_op]) {
|
|
@@ -406,13 +624,16 @@ ca_sweep_release_chunked (ca_sweep_state_t *st)
|
|
|
406
624
|
ca_lazy_arena_release(st->mask_scratch);
|
|
407
625
|
st->mask_scratch = NULL;
|
|
408
626
|
}
|
|
627
|
+
if (tag) {
|
|
628
|
+
st->chunked_state = 3; /* everything has been given back */
|
|
629
|
+
}
|
|
630
|
+
ca_sweep_reraise(tag, error);
|
|
409
631
|
}
|
|
410
632
|
|
|
411
633
|
/* ===== WHOLE_BUFFER function form (rb_ensure-protected) ===== */
|
|
412
634
|
|
|
413
635
|
typedef struct {
|
|
414
636
|
CArray *ca;
|
|
415
|
-
int writable;
|
|
416
637
|
ca_with_buffer_body_fn body_fn;
|
|
417
638
|
void *user_data;
|
|
418
639
|
} ca_with_buffer_ctx_t;
|
|
@@ -425,49 +646,15 @@ ca_with_buffer_body_trampoline (VALUE ctx_val)
|
|
|
425
646
|
return Qnil;
|
|
426
647
|
}
|
|
427
648
|
|
|
428
|
-
static VALUE
|
|
429
|
-
ca_with_buffer_ensure_trampoline (VALUE ctx_val)
|
|
430
|
-
{
|
|
431
|
-
ca_with_buffer_ctx_t *ctx = (ca_with_buffer_ctx_t *) ctx_val;
|
|
432
|
-
if (ctx->writable) ca_sync(ctx->ca);
|
|
433
|
-
ca_detach(ctx->ca);
|
|
434
|
-
return Qnil;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
649
|
void
|
|
438
650
|
rb_ca_call_with_buffer (VALUE r_ca, int writable,
|
|
439
651
|
ca_with_buffer_body_fn body, void *user_data)
|
|
440
652
|
{
|
|
441
653
|
ca_with_buffer_ctx_t ctx;
|
|
442
654
|
TypedData_Get_Struct(r_ca, CArray, &carray_data_type, ctx.ca);
|
|
443
|
-
/* CAREFUL: attach outside rb_ensure. If attach raises, we are not
|
|
444
|
-
* yet inside the ensure scope, so the ensure trampoline will not
|
|
445
|
-
* fire on a not-attached ca (which would try to detach and crash). */
|
|
446
|
-
ca_attach(ctx.ca);
|
|
447
|
-
ctx.writable = writable;
|
|
448
655
|
ctx.body_fn = body;
|
|
449
656
|
ctx.user_data = user_data;
|
|
450
|
-
|
|
451
|
-
|
|
657
|
+
ca_attach_window(1, &ctx.ca, writable ? "w" : "r",
|
|
658
|
+
ca_with_buffer_body_trampoline, (VALUE) &ctx);
|
|
452
659
|
}
|
|
453
660
|
|
|
454
|
-
void
|
|
455
|
-
ca_sweep_check_same_shape (CArray *ca_in, CArray *ca_out, const char *src_label)
|
|
456
|
-
{
|
|
457
|
-
int k;
|
|
458
|
-
const char *lbl = src_label ? src_label : "ca_sweep_check_same_shape";
|
|
459
|
-
if (ca_in->ndim != ca_out->ndim) {
|
|
460
|
-
rb_raise(rb_eRuntimeError,
|
|
461
|
-
"%s: shape mismatch (ndim %d vs %d)",
|
|
462
|
-
lbl, ca_in->ndim, ca_out->ndim);
|
|
463
|
-
}
|
|
464
|
-
for (k = 0; k < ca_in->ndim; k++) {
|
|
465
|
-
if (ca_in->dim[k] != ca_out->dim[k]) {
|
|
466
|
-
rb_raise(rb_eRuntimeError,
|
|
467
|
-
"%s: shape mismatch at dim[%d] (%lld vs %lld)",
|
|
468
|
-
lbl, k,
|
|
469
|
-
(long long) ca_in->dim[k],
|
|
470
|
-
(long long) ca_out->dim[k]);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|