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_kernel_iterator.c
CHANGED
|
@@ -30,6 +30,106 @@
|
|
|
30
30
|
|
|
31
31
|
#include <assert.h>
|
|
32
32
|
#include <string.h>
|
|
33
|
+
#include <ruby/ractor.h>
|
|
34
|
+
|
|
35
|
+
/* Private flags bit, kept in ca_iter_state.flags like
|
|
36
|
+
CA_ITER_FLAG_WALK_MAY_RAISE below: src is a copy the walk owns (see
|
|
37
|
+
ca_iter_reopen_on_copy), freed when the walk finishes. */
|
|
38
|
+
#define CA_ITER_FLAG_OWNS_SRC 0x40000000u
|
|
39
|
+
|
|
40
|
+
/* Data scratch. A scratch of object cells holds VALUEs no Ruby object
|
|
41
|
+
owns while the kernel calls Ruby for each cell, so it is filled with
|
|
42
|
+
Qnil and held for the GC until finish releases it.
|
|
43
|
+
|
|
44
|
+
One large scratch is kept when a walk frees it and handed to the next
|
|
45
|
+
walk that fits in it: a fresh allocation of that size costs the page
|
|
46
|
+
faults of touching it, which for a reduction is several times the
|
|
47
|
+
reduction itself. The kept buffer is owned by nobody, and a walk that
|
|
48
|
+
takes it owns it alone until it frees it again. Each Ractor keeps its
|
|
49
|
+
own (ractor-local storage), since walks in different Ractors run at
|
|
50
|
+
the same time. */
|
|
51
|
+
|
|
52
|
+
#define KI_KEEP_MIN ((ca_size_t) 1 << 20)
|
|
53
|
+
#define KI_KEEP_MAX ((ca_size_t) 64 << 20)
|
|
54
|
+
|
|
55
|
+
typedef struct {
|
|
56
|
+
void *p;
|
|
57
|
+
ca_size_t bytes;
|
|
58
|
+
} ki_kept_t;
|
|
59
|
+
|
|
60
|
+
static rb_ractor_local_key_t ki_kept_key;
|
|
61
|
+
|
|
62
|
+
static void
|
|
63
|
+
ki_kept_free (void *ptr)
|
|
64
|
+
{
|
|
65
|
+
ki_kept_t *k = (ki_kept_t *) ptr;
|
|
66
|
+
if ( k ) {
|
|
67
|
+
if ( k->p ) ruby_xfree(k->p);
|
|
68
|
+
ruby_xfree(k);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static const struct rb_ractor_local_storage_type ki_kept_type = {
|
|
73
|
+
NULL, ki_kept_free
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
static ki_kept_t *
|
|
77
|
+
ki_kept_slot (void)
|
|
78
|
+
{
|
|
79
|
+
ki_kept_t *k = (ki_kept_t *) rb_ractor_local_storage_ptr(ki_kept_key);
|
|
80
|
+
if ( k == NULL ) {
|
|
81
|
+
k = ALLOC(ki_kept_t);
|
|
82
|
+
k->p = NULL;
|
|
83
|
+
k->bytes = 0;
|
|
84
|
+
rb_ractor_local_storage_ptr_set(ki_kept_key, k);
|
|
85
|
+
}
|
|
86
|
+
return k;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static void *
|
|
90
|
+
ki_data_alloc (int8_t data_type, ca_size_t bytes)
|
|
91
|
+
{
|
|
92
|
+
void *p = NULL;
|
|
93
|
+
if ( bytes >= KI_KEEP_MIN ) {
|
|
94
|
+
ki_kept_t *k = ki_kept_slot();
|
|
95
|
+
if ( k->p && bytes <= k->bytes ) {
|
|
96
|
+
p = k->p;
|
|
97
|
+
k->p = NULL;
|
|
98
|
+
k->bytes = 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if ( p == NULL ) {
|
|
102
|
+
p = xmalloc(bytes > 0 ? bytes : 1);
|
|
103
|
+
}
|
|
104
|
+
if ( data_type == CA_OBJECT ) {
|
|
105
|
+
VALUE *v = (VALUE *) p;
|
|
106
|
+
ca_size_t n = bytes / (ca_size_t) sizeof(VALUE);
|
|
107
|
+
ca_size_t i;
|
|
108
|
+
for ( i = 0; i < n; i++ ) v[i] = Qnil;
|
|
109
|
+
ca_gc_hold_buffer(p, n);
|
|
110
|
+
}
|
|
111
|
+
return p;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* `bytes` is the size p was allocated with (0 when unknown: never kept). */
|
|
115
|
+
static void
|
|
116
|
+
ki_data_free (void *p, ca_size_t bytes)
|
|
117
|
+
{
|
|
118
|
+
ca_gc_release_buffer(p);
|
|
119
|
+
if ( bytes >= KI_KEEP_MIN && bytes <= KI_KEEP_MAX ) {
|
|
120
|
+
ki_kept_t *k = ki_kept_slot();
|
|
121
|
+
if ( bytes > k->bytes ) {
|
|
122
|
+
void *old = k->p;
|
|
123
|
+
k->p = p;
|
|
124
|
+
k->bytes = bytes;
|
|
125
|
+
if ( old ) {
|
|
126
|
+
xfree(old);
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
xfree(p);
|
|
132
|
+
}
|
|
33
133
|
|
|
34
134
|
/* Defined in carray_core.c. (ca_is_readonly / ca_has_mask /
|
|
35
135
|
ca_sync_data are already declared in carray.h.) */
|
|
@@ -103,6 +203,7 @@ extern ca_operation_function_t ca_monop_func;
|
|
|
103
203
|
extern ca_operation_function_t ca_binop_func;
|
|
104
204
|
extern ca_operation_function_t ca_bincmp_func;
|
|
105
205
|
extern ca_operation_function_t ca_moncmp_func;
|
|
206
|
+
extern ca_operation_function_t ca_triop_func;
|
|
106
207
|
extern CArray *ca_remap_new (CArray *ref, CArray *idx);
|
|
107
208
|
|
|
108
209
|
/* ca_reduce_new is declared in carray.h; rb_cCAReduce defined in
|
|
@@ -236,6 +337,13 @@ ca_iter_classify_source (CArray *src)
|
|
|
236
337
|
if ( attach == ca_binop_func.attach ) return CA_ITER_SRC_ATTACH;
|
|
237
338
|
if ( attach == ca_bincmp_func.attach ) return CA_ITER_SRC_ATTACH;
|
|
238
339
|
if ( attach == ca_moncmp_func.attach ) return CA_ITER_SRC_ATTACH;
|
|
340
|
+
if ( attach == ca_triop_func.attach ) return CA_ITER_SRC_ATTACH;
|
|
341
|
+
|
|
342
|
+
/* Anything else is a view class installed from outside that did not
|
|
343
|
+
register. Attaching is the one thing every view can do, and it is
|
|
344
|
+
what a registration would declare, so the array is delivered that way
|
|
345
|
+
rather than refused. */
|
|
346
|
+
if ( attach != NULL ) return CA_ITER_SRC_ATTACH;
|
|
239
347
|
|
|
240
348
|
return CA_ITER_SRC_NONE;
|
|
241
349
|
}
|
|
@@ -270,6 +378,18 @@ ca_iter_route_source (CArray *src,
|
|
|
270
378
|
uint8_t kind = ca_iter_classify_source(src);
|
|
271
379
|
if ( kind != CA_ITER_SRC_DESCRIPTOR ) return kind;
|
|
272
380
|
|
|
381
|
+
/* The descriptor walk reads the parent's memory, which such a parent
|
|
382
|
+
only has after a whole materialise -- however few cells the view
|
|
383
|
+
selects. Deliver through the view's own transfer instead: SRC_ATTACH
|
|
384
|
+
gathers the view into scratch with ca_xfer_all, and the view asks its
|
|
385
|
+
parent for the selected cells alone. */
|
|
386
|
+
{
|
|
387
|
+
CArray *parent = ((CAView *) src)->parent;
|
|
388
|
+
if ( ! parent->ptr && ca_parent_lends_no_memory(parent) ) {
|
|
389
|
+
return CA_ITER_SRC_ATTACH;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
273
393
|
/* Descriptor source: describe_axes + inspect innermost. */
|
|
274
394
|
ca_iter_describe_axes(src, out_descs, out_parent_dims, out_ndim);
|
|
275
395
|
if ( ca_axis_dispatch_is_innermost_stride(out_descs, *out_ndim) ) {
|
|
@@ -485,39 +605,33 @@ ca_iter_validate_inputs (ca_iter_state *st,
|
|
|
485
605
|
if ( policy != CA_SLAB_WHOLE && policy != CA_SLAB_AXES )
|
|
486
606
|
return CA_ITER_ERR_POLICY;
|
|
487
607
|
|
|
488
|
-
/*
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
lands in step 7; step 6 accepts the flag but does not enforce.
|
|
492
|
-
CA_KERNEL_FIBER_CONTIG (PROPOSAL_FIBER_DELIVERY F.1a) accepted —
|
|
493
|
-
activates per-fiber contig delivery for naxes==1 in next_slab_axes. */
|
|
608
|
+
/* Accepted: CA_KERNEL_WRITE, CA_KERNEL_NO_MASK (enforced below) and
|
|
609
|
+
CA_KERNEL_FIBER_CONTIG (per-fiber contig delivery for naxes==1 in
|
|
610
|
+
next_slab_axes). CA_KERNEL_CHUNK_HINT is reserved and rejected. */
|
|
494
611
|
const uint32_t accepted = CA_KERNEL_WRITE | CA_KERNEL_NO_MASK
|
|
495
612
|
| CA_KERNEL_FIBER_CONTIG;
|
|
496
613
|
if ( flags & ~accepted ) return CA_ITER_ERR_FLAGS;
|
|
497
614
|
|
|
498
|
-
/* WRITE on a readonly view (CARepeat stride-0 /
|
|
499
|
-
CAWrap
|
|
500
|
-
write. */
|
|
615
|
+
/* WRITE on a readonly view (CARepeat stride-0 / a lazy expression /
|
|
616
|
+
a read-only CAWrap / any view of a frozen or read-only array) --
|
|
617
|
+
explicit reject, would otherwise SEGV on write. */
|
|
501
618
|
if ( (flags & CA_KERNEL_WRITE) && ca_is_readonly(src) ) {
|
|
502
619
|
return CA_ITER_ERR_READONLY;
|
|
503
620
|
}
|
|
504
621
|
|
|
505
|
-
/*
|
|
506
|
-
CA_ITER_ERR_MASK
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
so the caller can decide whether to peel via .value /
|
|
511
|
-
.strip_mask(fill) or pick a mask-aware kernel. */
|
|
622
|
+
/* Masked sources are accepted; the mask travels with the slab, so
|
|
623
|
+
nothing returns CA_ITER_ERR_MASK. CA_KERNEL_NO_MASK is the kernel
|
|
624
|
+
declaring it cannot handle a mask: a masked source is then refused
|
|
625
|
+
with a dedicated code, so the caller can decide whether to peel via
|
|
626
|
+
.value / .strip_mask(fill) or pick a mask-aware kernel. */
|
|
512
627
|
if ( (flags & CA_KERNEL_NO_MASK) && ca_has_mask(src) ) {
|
|
513
628
|
return CA_ITER_ERR_MASK_NOT_ALLOWED;
|
|
514
629
|
}
|
|
515
630
|
|
|
516
|
-
/* Gate: classify source.
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
5.2 and Phase 2 respectively. */
|
|
631
|
+
/* Gate: classify source. Entity, CAStride family, descriptor views
|
|
632
|
+
and SRC_ATTACH views are accepted; a source the classifier does not
|
|
633
|
+
recognise (an externally installed view that has not registered a
|
|
634
|
+
kind) is refused. */
|
|
521
635
|
if ( ca_iter_classify_source(src) == CA_ITER_SRC_NONE ) {
|
|
522
636
|
return CA_ITER_ERR_NOT_CHEAP;
|
|
523
637
|
}
|
|
@@ -553,14 +667,165 @@ ca_iter_strip_storage_wrapper (CArray *src)
|
|
|
553
667
|
return src;
|
|
554
668
|
}
|
|
555
669
|
|
|
670
|
+
/* Raise unless a and b have the same shape. The INOUT and PAIR fiber
|
|
671
|
+
macros call it before opening either walk, so a refusal leaves nothing
|
|
672
|
+
to close. */
|
|
556
673
|
int
|
|
557
|
-
|
|
674
|
+
ca_iter_check_same_shape (struct _CArray *a, struct _CArray *b)
|
|
675
|
+
{
|
|
676
|
+
int8_t k;
|
|
677
|
+
int same = ( a->ndim == b->ndim );
|
|
678
|
+
for ( k = 0; same && k < a->ndim; k++ ) {
|
|
679
|
+
if ( a->dim[k] != b->dim[k] ) same = 0;
|
|
680
|
+
}
|
|
681
|
+
if ( ! same ) {
|
|
682
|
+
VALUE sa = rb_ary_new(), sb = rb_ary_new();
|
|
683
|
+
for ( k = 0; k < a->ndim; k++ ) rb_ary_push(sa, SIZE2NUM(a->dim[k]));
|
|
684
|
+
for ( k = 0; k < b->ndim; k++ ) rb_ary_push(sb, SIZE2NUM(b->dim[k]));
|
|
685
|
+
rb_raise(rb_eArgError,
|
|
686
|
+
"kernel iterator: the two arrays of a paired walk "
|
|
687
|
+
"differ in shape (%"PRIsVALUE" vs %"PRIsVALUE")",
|
|
688
|
+
rb_inspect(sa), rb_inspect(sb));
|
|
689
|
+
}
|
|
690
|
+
return 0;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
int
|
|
694
|
+
ca_iter_check_init (int rc)
|
|
695
|
+
{
|
|
696
|
+
const char *why;
|
|
697
|
+
|
|
698
|
+
if ( rc == CA_ITER_OK ) return rc;
|
|
699
|
+
|
|
700
|
+
switch ( rc ) {
|
|
701
|
+
case CA_ITER_ERR_NOT_CHEAP:
|
|
702
|
+
why = "the iterator does not recognise this kind of source";
|
|
703
|
+
break;
|
|
704
|
+
case CA_ITER_ERR_POLICY:
|
|
705
|
+
why = "the slab policy or the axes given do not apply to this source";
|
|
706
|
+
break;
|
|
707
|
+
case CA_ITER_ERR_FLAGS:
|
|
708
|
+
why = "this flag combination is not supported for this source";
|
|
709
|
+
break;
|
|
710
|
+
case CA_ITER_ERR_READONLY:
|
|
711
|
+
why = "the array is read-only and the kernel asked to write";
|
|
712
|
+
break;
|
|
713
|
+
case CA_ITER_ERR_MASK:
|
|
714
|
+
why = "the source carries a mask";
|
|
715
|
+
break;
|
|
716
|
+
case CA_ITER_ERR_MASK_NOT_ALLOWED:
|
|
717
|
+
why = "the kernel declared CA_KERNEL_NO_MASK and the source carries a mask";
|
|
718
|
+
break;
|
|
719
|
+
default:
|
|
720
|
+
why = "the request was refused";
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
rb_raise(rb_eRuntimeError, "kernel iterator: %s (rc=%d)", why, rc);
|
|
724
|
+
return rc; /* not reached */
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/* Whole-view scratch. The view is gathered into the walk's scratch,
|
|
728
|
+
by the view's own transfer (by_copy = 0) or by ca_copy_data (by_copy =
|
|
729
|
+
1, the CAStride compose-fold). A WRITE walk sends back only the cells
|
|
730
|
+
the kernel changed (ki_scratch_push_changed), so the scratch is twice
|
|
731
|
+
the view and its second half keeps what was gathered: a cell the
|
|
732
|
+
kernel left alone must not be sent back, for it may be another copy
|
|
733
|
+
of a cell the kernel did write (a tile, a stack of one array with
|
|
734
|
+
itself) or a cell a conversion view would not bring back unchanged. */
|
|
735
|
+
static void
|
|
736
|
+
ki_gather_view (ca_iter_state *st, CArray *src, uint32_t flags, int by_copy)
|
|
737
|
+
{
|
|
738
|
+
ca_size_t view_bytes = (ca_size_t) src->elements * src->bytes;
|
|
739
|
+
st->scratch_cap = (flags & CA_KERNEL_WRITE) ? 2 * view_bytes : view_bytes;
|
|
740
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
741
|
+
if ( src->elements > 0 ) {
|
|
742
|
+
if ( by_copy ) {
|
|
743
|
+
ca_copy_data(src, st->scratch_ptr);
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
747
|
+
}
|
|
748
|
+
if ( flags & CA_KERNEL_WRITE ) {
|
|
749
|
+
memcpy(st->scratch_ptr + view_bytes, st->scratch_ptr, view_bytes);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* Send back the cells of the current slab (the whole view for a WHOLE
|
|
755
|
+
walk) that differ from what was gathered, and record them as sent.
|
|
756
|
+
The slab of a CA_SLAB_AXES walk starts at last_data_off in the
|
|
757
|
+
scratch, which is laid out row-major over the view, so a cell's
|
|
758
|
+
offset divided by the cell size is its address in the view. */
|
|
759
|
+
static void
|
|
760
|
+
ki_scratch_push_changed (ca_iter_state *st)
|
|
761
|
+
{
|
|
762
|
+
CArray *src = st->src;
|
|
763
|
+
ca_size_t bytes = src->bytes;
|
|
764
|
+
ca_size_t view_bytes = (ca_size_t) src->elements * bytes;
|
|
765
|
+
char *now = st->scratch_ptr;
|
|
766
|
+
char *was = st->scratch_ptr + view_bytes;
|
|
767
|
+
int whole = ! ( st->policy == CA_SLAB_AXES && st->level == 2 );
|
|
768
|
+
ca_size_t n = whole ? src->elements : st->slab_elements;
|
|
769
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
770
|
+
ca_size_t *addrs;
|
|
771
|
+
char *vals;
|
|
772
|
+
ca_size_t n_changed = 0;
|
|
773
|
+
ca_size_t i;
|
|
774
|
+
int8_t k;
|
|
775
|
+
volatile VALUE h_addrs = 0, h_vals = 0;
|
|
776
|
+
|
|
777
|
+
if ( n <= 0 ) return;
|
|
778
|
+
|
|
779
|
+
addrs = ALLOCV_N(ca_size_t, h_addrs, n);
|
|
780
|
+
vals = (char *) ALLOCV(h_vals, n * bytes);
|
|
781
|
+
for ( k = 0; k < st->slab_ndim; k++ ) idx[k] = 0;
|
|
782
|
+
|
|
783
|
+
for ( i = 0; i < n; i++ ) {
|
|
784
|
+
ca_size_t off;
|
|
785
|
+
if ( whole ) {
|
|
786
|
+
off = i * bytes;
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
off = st->last_data_off;
|
|
790
|
+
for ( k = 0; k < st->slab_ndim; k++ ) off += idx[k] * st->slab_strides[k];
|
|
791
|
+
for ( k = st->slab_ndim - 1; k >= 0; k-- ) {
|
|
792
|
+
if ( ++idx[k] < st->slab_dims[k] ) break;
|
|
793
|
+
idx[k] = 0;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if ( memcmp(now + off, was + off, bytes) != 0 ) {
|
|
797
|
+
memcpy(was + off, now + off, bytes);
|
|
798
|
+
memcpy(vals + n_changed * bytes, now + off, bytes);
|
|
799
|
+
addrs[n_changed++] = off / bytes;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if ( whole && n_changed == n ) {
|
|
804
|
+
ca_xfer_all(src, now, CA_XFER_PUT);
|
|
805
|
+
}
|
|
806
|
+
else if ( n_changed > 0 ) {
|
|
807
|
+
ca_xfer_addrs(src, n_changed, addrs, vals, CA_XFER_PUT);
|
|
808
|
+
}
|
|
809
|
+
ALLOCV_END(h_vals);
|
|
810
|
+
ALLOCV_END(h_addrs);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
static int
|
|
814
|
+
ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
558
815
|
struct _CArray *src,
|
|
559
816
|
ca_slab_policy_t policy,
|
|
560
817
|
int8_t *axes,
|
|
561
818
|
int8_t naxes,
|
|
562
819
|
uint32_t flags)
|
|
563
820
|
{
|
|
821
|
+
/* Leave the state defined before anything can return. Every error
|
|
822
|
+
return below hands control back to a caller that may not look at the
|
|
823
|
+
code, so what it is left holding has to be a state that iterates zero
|
|
824
|
+
times rather than whatever its stack frame happened to contain. */
|
|
825
|
+
if ( st == NULL ) return CA_ITER_ERR_FLAGS;
|
|
826
|
+
memset(st, 0, sizeof(*st));
|
|
827
|
+
if ( src == NULL ) return CA_ITER_ERR_FLAGS;
|
|
828
|
+
|
|
564
829
|
/* PROPOSAL_CAFACE_PHASE_2 F.2.6 + PROPOSAL_LAZY_MARKER_LIFT Phase 0:
|
|
565
830
|
storage-identical wrapper strip at entry (= same rationale as init_l2
|
|
566
831
|
below). Strip before validate_inputs.
|
|
@@ -586,7 +851,6 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
586
851
|
|
|
587
852
|
uint8_t src_kind = ca_iter_classify_source(src);
|
|
588
853
|
|
|
589
|
-
memset(st, 0, sizeof(*st));
|
|
590
854
|
st->src = src;
|
|
591
855
|
st->src_kind = src_kind;
|
|
592
856
|
st->level = 1;
|
|
@@ -594,7 +858,6 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
594
858
|
st->ndim = src->ndim;
|
|
595
859
|
st->flags = flags;
|
|
596
860
|
st->bytes = src->bytes;
|
|
597
|
-
st->axes = axes;
|
|
598
861
|
st->naxes = naxes;
|
|
599
862
|
|
|
600
863
|
st->slab_n = src->elements;
|
|
@@ -612,11 +875,7 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
612
875
|
Decouples kernel_iterator from per-view attach/sync lifecycle
|
|
613
876
|
and inherits xfer reform improvements (transform-fused, etc.)
|
|
614
877
|
automatically. */
|
|
615
|
-
st
|
|
616
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0 ? st->scratch_cap : 1);
|
|
617
|
-
if ( src->elements > 0 ) {
|
|
618
|
-
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
619
|
-
}
|
|
878
|
+
ki_gather_view(st, src, flags, 0);
|
|
620
879
|
st->alias_mode = CA_ITER_ALIAS_NONE; /* scratch-owned, no src.detach */
|
|
621
880
|
st->alias_ptr = st->scratch_ptr;
|
|
622
881
|
st->composed_strides[0] = src->bytes;
|
|
@@ -677,12 +936,11 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
677
936
|
if ( ca_func[src->obj_type].attach == ca_window_func.attach ) {
|
|
678
937
|
bound_fill = ((CAWindow *) src)->fill;
|
|
679
938
|
}
|
|
680
|
-
st->
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
bound_fill);
|
|
939
|
+
st->scratch_cap = st->total_elements * src->bytes;
|
|
940
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
941
|
+
ca_axis_dispatch_gather(parent, st->parent_axis_dims, raw_descs, raw_ndim,
|
|
942
|
+
src->bytes, st->total_elements, bound_fill,
|
|
943
|
+
st->scratch_ptr);
|
|
686
944
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
687
945
|
st->alias_ptr = st->scratch_ptr;
|
|
688
946
|
|
|
@@ -712,12 +970,7 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
712
970
|
to ca_stride_func_copy_data which composes leaf strides up to
|
|
713
971
|
the root entity and gathers in one pass — no per-intermediate
|
|
714
972
|
view materialise. */
|
|
715
|
-
|
|
716
|
-
st->scratch_cap = cap;
|
|
717
|
-
st->scratch_ptr = xmalloc(cap > 0 ? cap : 1);
|
|
718
|
-
if ( cap > 0 ) {
|
|
719
|
-
ca_copy_data(src, st->scratch_ptr);
|
|
720
|
-
}
|
|
973
|
+
ki_gather_view(st, src, flags, 1);
|
|
721
974
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
722
975
|
st->alias_ptr = st->scratch_ptr;
|
|
723
976
|
}
|
|
@@ -740,14 +993,22 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
740
993
|
return CA_ITER_OK;
|
|
741
994
|
}
|
|
742
995
|
|
|
743
|
-
int
|
|
744
|
-
|
|
996
|
+
static int
|
|
997
|
+
ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
745
998
|
struct _CArray *src,
|
|
746
999
|
ca_slab_policy_t policy,
|
|
747
1000
|
int8_t *axes,
|
|
748
1001
|
int8_t naxes,
|
|
749
1002
|
uint32_t flags)
|
|
750
1003
|
{
|
|
1004
|
+
/* Leave the state defined before anything can return. Every error
|
|
1005
|
+
return below hands control back to a caller that may not look at the
|
|
1006
|
+
code, so what it is left holding has to be a state that iterates zero
|
|
1007
|
+
times rather than whatever its stack frame happened to contain. */
|
|
1008
|
+
if ( st == NULL ) return CA_ITER_ERR_FLAGS;
|
|
1009
|
+
memset(st, 0, sizeof(*st));
|
|
1010
|
+
if ( src == NULL ) return CA_ITER_ERR_FLAGS;
|
|
1011
|
+
|
|
751
1012
|
/* PROPOSAL_CAFACE_PHASE_2 F.2.6 (= MEMO §3.5 kernel_iterator entry strip)
|
|
752
1013
|
+ PROPOSAL_LAZY_MARKER_LIFT Phase 0.
|
|
753
1014
|
|
|
@@ -815,7 +1076,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
815
1076
|
and use per-fiber ca_xfer_stride which routes to the view's
|
|
816
1077
|
X.1 OOB-fused per-region fast path. */
|
|
817
1078
|
if ( (flags & CA_KERNEL_FIBER_CONTIG) && naxes == 1
|
|
818
|
-
&& raw_ndim == src->ndim ) {
|
|
1079
|
+
&& raw_ndim == src->ndim && ca_fast_paths_enabled() ) {
|
|
819
1080
|
int8_t fiber_ax = axes[0];
|
|
820
1081
|
ca_size_t row_byte_strides[CA_RANK_MAX];
|
|
821
1082
|
{
|
|
@@ -828,7 +1089,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
828
1089
|
if ( ca_iter_should_per_fiber_fused(src, src_kind, fiber_ax,
|
|
829
1090
|
row_byte_strides[fiber_ax],
|
|
830
1091
|
flags) ) {
|
|
831
|
-
memset(st, 0, sizeof(*st));
|
|
832
1092
|
st->src = src;
|
|
833
1093
|
st->src_kind = src_kind;
|
|
834
1094
|
st->level = 2;
|
|
@@ -836,7 +1096,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
836
1096
|
st->ndim = src->ndim;
|
|
837
1097
|
st->flags = flags;
|
|
838
1098
|
st->bytes = src->bytes;
|
|
839
|
-
st->axes = axes;
|
|
840
1099
|
st->naxes = naxes;
|
|
841
1100
|
|
|
842
1101
|
st->alias_mode = CA_ITER_ALIAS_PER_FIBER_FUSED;
|
|
@@ -910,19 +1169,29 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
910
1169
|
return CA_ITER_ERR_POLICY;
|
|
911
1170
|
}
|
|
912
1171
|
int slab_has_non_stride = 0;
|
|
1172
|
+
int slab_has_index = 0;
|
|
913
1173
|
for ( k = 0; k < src->ndim; k++ ) {
|
|
914
1174
|
if ( in_slab[k] && raw_descs[k].kind != CA_AXIS_KIND_STRIDE ) {
|
|
915
1175
|
slab_has_non_stride = 1;
|
|
916
|
-
|
|
1176
|
+
if ( raw_descs[k].kind == CA_AXIS_KIND_INDEX ) {
|
|
1177
|
+
slab_has_index = 1;
|
|
1178
|
+
}
|
|
917
1179
|
}
|
|
918
1180
|
}
|
|
919
|
-
|
|
1181
|
+
/* A slab with a SHIFT axis that leaves out the innermost view axis
|
|
1182
|
+
would be gathered one strided cell at a time, once per slab. Read
|
|
1183
|
+
walks take the whole-view path below instead: the view is gathered
|
|
1184
|
+
once, row by row, and the slabs are walked in the copy. */
|
|
1185
|
+
int whole_view = slab_has_non_stride && ! slab_has_index
|
|
1186
|
+
&& ! in_slab[src->ndim - 1]
|
|
1187
|
+
&& ! ( flags & CA_KERNEL_WRITE )
|
|
1188
|
+
&& ca_fast_paths_enabled();
|
|
1189
|
+
if ( slab_has_non_stride && ! whole_view ) {
|
|
920
1190
|
/* C.1 scope: READ-only. WRITE = future sub-step (C.1c). */
|
|
921
1191
|
if ( flags & CA_KERNEL_WRITE ) {
|
|
922
1192
|
return CA_ITER_ERR_FLAGS;
|
|
923
1193
|
}
|
|
924
1194
|
|
|
925
|
-
memset(st, 0, sizeof(*st));
|
|
926
1195
|
st->src = src;
|
|
927
1196
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
928
1197
|
st->level = 2;
|
|
@@ -930,7 +1199,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
930
1199
|
st->ndim = src->ndim;
|
|
931
1200
|
st->flags = flags;
|
|
932
1201
|
st->bytes = src->bytes;
|
|
933
|
-
st->axes = axes;
|
|
934
1202
|
st->naxes = naxes;
|
|
935
1203
|
|
|
936
1204
|
CArray *parent = CAVIEW(src)->parent;
|
|
@@ -1030,7 +1298,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1030
1298
|
full-view materialise). */
|
|
1031
1299
|
ca_size_t slab_bytes = st->slab_elements * src->bytes;
|
|
1032
1300
|
st->scratch_cap = slab_bytes > 0 ? slab_bytes : 1;
|
|
1033
|
-
st->scratch_ptr = (char *)
|
|
1301
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
1034
1302
|
st->alias_ptr = st->scratch_ptr; /* refilled per slab in next_slab_axes */
|
|
1035
1303
|
|
|
1036
1304
|
/* Specialisation (B-1b, C.1b): if innermost slab axis is STRIDE
|
|
@@ -1038,7 +1306,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1038
1306
|
manual gather path (= outer + non-innermost-slab hoist,
|
|
1039
1307
|
inner pure STRIDE linear memcpy). Else (innermost INDEX /
|
|
1040
1308
|
SHIFT-anywhere): use the engine fallback (A). */
|
|
1041
|
-
int specialised_eligible = (sp > 0);
|
|
1309
|
+
int specialised_eligible = (sp > 0) && ca_fast_paths_enabled();
|
|
1042
1310
|
if ( specialised_eligible ) {
|
|
1043
1311
|
int8_t inner_view_ax = st->slab_axes_buf[sp - 1];
|
|
1044
1312
|
if ( raw_descs[inner_view_ax].kind != CA_AXIS_KIND_STRIDE ) {
|
|
@@ -1090,8 +1358,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1090
1358
|
}
|
|
1091
1359
|
}
|
|
1092
1360
|
|
|
1093
|
-
if ( outer_has_shift ) {
|
|
1094
|
-
memset(st, 0, sizeof(*st));
|
|
1361
|
+
if ( outer_has_shift || whole_view ) {
|
|
1095
1362
|
st->src = src;
|
|
1096
1363
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
1097
1364
|
st->level = 2;
|
|
@@ -1099,7 +1366,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1099
1366
|
st->ndim = src->ndim;
|
|
1100
1367
|
st->flags = flags;
|
|
1101
1368
|
st->bytes = src->bytes;
|
|
1102
|
-
st->axes = axes;
|
|
1103
1369
|
st->naxes = naxes;
|
|
1104
1370
|
|
|
1105
1371
|
CArray *parent = CAVIEW(src)->parent;
|
|
@@ -1113,10 +1379,12 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1113
1379
|
bound_fill = ((CAWindow *) src)->fill;
|
|
1114
1380
|
}
|
|
1115
1381
|
st->scratch_cap = src->elements * src->bytes;
|
|
1116
|
-
st->scratch_ptr =
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1382
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
1383
|
+
ca_axis_dispatch_gather(parent, raw_pdims, local_descs, src->ndim,
|
|
1384
|
+
src->bytes, src->elements, bound_fill,
|
|
1385
|
+
st->scratch_ptr);
|
|
1386
|
+
/* sync_slab scatters the whole scratch back by this count. */
|
|
1387
|
+
st->total_elements = src->elements;
|
|
1120
1388
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
1121
1389
|
st->alias_ptr = st->scratch_ptr;
|
|
1122
1390
|
|
|
@@ -1185,7 +1453,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1185
1453
|
return CA_ITER_OK;
|
|
1186
1454
|
}
|
|
1187
1455
|
|
|
1188
|
-
memset(st, 0, sizeof(*st));
|
|
1189
1456
|
st->src = src;
|
|
1190
1457
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR; /* Phase B alias path */
|
|
1191
1458
|
st->level = 2;
|
|
@@ -1193,7 +1460,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1193
1460
|
st->ndim = src->ndim;
|
|
1194
1461
|
st->flags = flags;
|
|
1195
1462
|
st->bytes = src->bytes;
|
|
1196
|
-
st->axes = axes;
|
|
1197
1463
|
st->naxes = naxes;
|
|
1198
1464
|
|
|
1199
1465
|
/* Parent row-major byte strides for offset computation. */
|
|
@@ -1333,7 +1599,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1333
1599
|
in_slab[ax] = 1;
|
|
1334
1600
|
}
|
|
1335
1601
|
|
|
1336
|
-
memset(st, 0, sizeof(*st));
|
|
1337
1602
|
st->src = src;
|
|
1338
1603
|
st->src_kind = CA_ITER_SRC_ATTACH;
|
|
1339
1604
|
st->level = 2;
|
|
@@ -1341,7 +1606,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1341
1606
|
st->ndim = src->ndim;
|
|
1342
1607
|
st->flags = flags;
|
|
1343
1608
|
st->bytes = src->bytes;
|
|
1344
|
-
st->axes = axes;
|
|
1345
1609
|
st->naxes = naxes;
|
|
1346
1610
|
|
|
1347
1611
|
/* Row-major byte / element strides on the attached view buffer.
|
|
@@ -1386,7 +1650,9 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1386
1650
|
k_axis..N-2]; either way outer_idx[m] = parent axis m). */
|
|
1387
1651
|
if ( ca_func[src->obj_type].attach == ca_stack_func.attach
|
|
1388
1652
|
&& !ca_has_mask(src)
|
|
1389
|
-
&&
|
|
1653
|
+
&& !(flags & CA_KERNEL_WRITE)
|
|
1654
|
+
&& naxes == 1 && axes[0] == ((CAStack *) src)->k_axis
|
|
1655
|
+
&& ca_fast_paths_enabled() ) {
|
|
1390
1656
|
CAStack *stack = (CAStack *) src;
|
|
1391
1657
|
int8_t parent_ndim = src->ndim - 1;
|
|
1392
1658
|
int8_t sp = 0, op = 0;
|
|
@@ -1435,12 +1701,15 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1435
1701
|
guarantees uniform shape (MEMO §3.2) so one set of parent
|
|
1436
1702
|
native byte strides covers all K (= parents[0]->dim is
|
|
1437
1703
|
canonical). */
|
|
1438
|
-
|
|
1704
|
+
/* stack_n_parents counts the parents attached so far: an attach
|
|
1705
|
+
that raises leaves finish with exactly those to detach. */
|
|
1706
|
+
st->stack_n_parents = 0;
|
|
1439
1707
|
st->stack_parent_ptrs =
|
|
1440
1708
|
(char **) xmalloc(stack->n_parents * sizeof(char *));
|
|
1441
1709
|
for ( int32_t kk = 0; kk < stack->n_parents; kk++ ) {
|
|
1442
|
-
ca_attach(stack->parents[kk]);
|
|
1710
|
+
ca_attach(stack->parents[kk]); /* window: finish detaches the counted parents */
|
|
1443
1711
|
st->stack_parent_ptrs[kk] = (char *) stack->parents[kk]->ptr;
|
|
1712
|
+
st->stack_n_parents = kk + 1;
|
|
1444
1713
|
}
|
|
1445
1714
|
{
|
|
1446
1715
|
ca_size_t s = src->bytes;
|
|
@@ -1452,7 +1721,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1452
1721
|
|
|
1453
1722
|
/* Slab-sized scratch (= K * bytes for slab_axes == [0]). */
|
|
1454
1723
|
st->scratch_cap = (ca_size_t) st->slab_elements * src->bytes;
|
|
1455
|
-
st->scratch_ptr = (char *)
|
|
1724
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
1456
1725
|
|
|
1457
1726
|
/* Tile cache (pilot/castack-axis0-loop-interchange): refill TILE
|
|
1458
1727
|
fibers per K parent reads, serve next TILE-1 fibers from L1d.
|
|
@@ -1467,7 +1736,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1467
1736
|
st->stack_tile_cap = tile;
|
|
1468
1737
|
st->stack_tile_pos = 0;
|
|
1469
1738
|
st->stack_tile_have = 0; /* force refill on first call */
|
|
1470
|
-
st->stack_tile_cache = (char *)
|
|
1739
|
+
st->stack_tile_cache = (char *) ki_data_alloc(src->data_type, K * tile * bytes);
|
|
1471
1740
|
}
|
|
1472
1741
|
|
|
1473
1742
|
st->alias_mode = CA_ITER_ALIAS_STACK;
|
|
@@ -1501,7 +1770,9 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1501
1770
|
s - 1); only the K stack axis (s == k_axis) has no parent
|
|
1502
1771
|
counterpart. */
|
|
1503
1772
|
if ( ca_func[src->obj_type].attach == ca_stack_func.attach
|
|
1504
|
-
&&
|
|
1773
|
+
&& !(flags & CA_KERNEL_WRITE)
|
|
1774
|
+
&& naxes >= 1 && !in_slab[((CAStack *) src)->k_axis]
|
|
1775
|
+
&& ca_fast_paths_enabled() ) {
|
|
1505
1776
|
CAStack *stack = (CAStack *) src;
|
|
1506
1777
|
int8_t k_axis = stack->k_axis;
|
|
1507
1778
|
int8_t parent_ndim = src->ndim - 1;
|
|
@@ -1582,25 +1853,42 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1582
1853
|
|
|
1583
1854
|
/* Attach K parents + cache ptr aliases. Symmetric with rev3
|
|
1584
1855
|
Case B; for entity parents attach is O(1). */
|
|
1585
|
-
|
|
1856
|
+
/* stack_n_parents counts the parents attached so far: an attach
|
|
1857
|
+
that raises leaves finish with exactly those to detach. */
|
|
1858
|
+
st->stack_n_parents = 0;
|
|
1586
1859
|
st->stack_parent_ptrs =
|
|
1587
1860
|
(char **) xmalloc(stack->n_parents * sizeof(char *));
|
|
1588
1861
|
for ( int32_t kk = 0; kk < stack->n_parents; kk++ ) {
|
|
1589
|
-
ca_attach(stack->parents[kk]);
|
|
1862
|
+
ca_attach(stack->parents[kk]); /* window: finish detaches the counted parents */
|
|
1590
1863
|
st->stack_parent_ptrs[kk] = (char *) stack->parents[kk]->ptr;
|
|
1864
|
+
st->stack_n_parents = kk + 1;
|
|
1591
1865
|
}
|
|
1592
1866
|
|
|
1593
1867
|
/* If CAStack carries mask (= horizontal propagation already
|
|
1594
|
-
applied at create_mask),
|
|
1595
|
-
|
|
1596
|
-
|
|
1868
|
+
applied at create_mask), copy the K parent masks as they are
|
|
1869
|
+
at the start of the walk; next_slab_axes points into the copy
|
|
1870
|
+
of parent k at mask_off. A copy, as on every other path: the
|
|
1871
|
+
cursor is the walk's own, and a write to it reaches nothing. */
|
|
1597
1872
|
if ( ca_has_mask(src) ) {
|
|
1873
|
+
/* The stack's mask may still read stand-ins for parents that
|
|
1874
|
+
have gained a mask since; read through to those. */
|
|
1875
|
+
ca_multi_parent_mask_refresh(src->mask, stack->parents,
|
|
1876
|
+
stack->mask_standins,
|
|
1877
|
+
stack->n_parents, 0);
|
|
1878
|
+
/* Zero-filled: a slot is set once its copy is made, and finish
|
|
1879
|
+
frees the copies whose slot is set. */
|
|
1598
1880
|
st->stack_parent_mask_ptrs =
|
|
1599
1881
|
(boolean8_t **) xmalloc(stack->n_parents * sizeof(boolean8_t *));
|
|
1882
|
+
memset(st->stack_parent_mask_ptrs, 0,
|
|
1883
|
+
stack->n_parents * sizeof(boolean8_t *));
|
|
1600
1884
|
for ( int32_t kk = 0; kk < stack->n_parents; kk++ ) {
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1885
|
+
CArray *pm = ((CAStack *) src->mask)->parents[kk];
|
|
1886
|
+
ca_size_t n = pm->elements;
|
|
1887
|
+
boolean8_t *copy = (boolean8_t *) xmalloc(n > 0 ? n : 1);
|
|
1888
|
+
st->stack_parent_mask_ptrs[kk] = copy;
|
|
1889
|
+
ca_attach(pm); /* window: only a memcpy before the detach */
|
|
1890
|
+
memcpy(copy, pm->ptr, n);
|
|
1891
|
+
ca_detach(pm);
|
|
1604
1892
|
}
|
|
1605
1893
|
} else {
|
|
1606
1894
|
st->stack_parent_mask_ptrs = NULL;
|
|
@@ -1620,7 +1908,8 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1620
1908
|
is called on demand in next_slab_axes). Predicate is stubbed
|
|
1621
1909
|
in F.6.1 (returns 0); F.6.2+ enables specific source kinds. */
|
|
1622
1910
|
int per_fiber_fused = 0;
|
|
1623
|
-
if ( (flags & CA_KERNEL_FIBER_CONTIG) && naxes == 1
|
|
1911
|
+
if ( (flags & CA_KERNEL_FIBER_CONTIG) && naxes == 1
|
|
1912
|
+
&& ca_fast_paths_enabled() ) {
|
|
1624
1913
|
int8_t fiber_ax = axes[0];
|
|
1625
1914
|
ca_size_t fiber_ax_stride = row_byte_strides[fiber_ax];
|
|
1626
1915
|
if ( ca_iter_should_per_fiber_fused(src, src_kind, fiber_ax,
|
|
@@ -1638,11 +1927,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1638
1927
|
if ( !per_fiber_fused ) {
|
|
1639
1928
|
/* 2026-05-31 refactor: iter-owns scratch via ca_xfer_all (was
|
|
1640
1929
|
ca_attach(src) + alias src->ptr). */
|
|
1641
|
-
st
|
|
1642
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0 ? st->scratch_cap : 1);
|
|
1643
|
-
if ( src->elements > 0 ) {
|
|
1644
|
-
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
1645
|
-
}
|
|
1930
|
+
ki_gather_view(st, src, flags, 0);
|
|
1646
1931
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
1647
1932
|
st->alias_ptr = st->scratch_ptr;
|
|
1648
1933
|
}
|
|
@@ -1721,7 +2006,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1721
2006
|
/ CATile / CARoll). Same shape as L1 SRC_ATTACH: iterator-owns
|
|
1722
2007
|
scratch + xfer_all GET/PUT. Yield as one 1-D strided slab. */
|
|
1723
2008
|
if ( src_kind == CA_ITER_SRC_ATTACH ) {
|
|
1724
|
-
memset(st, 0, sizeof(*st));
|
|
1725
2009
|
st->src = src;
|
|
1726
2010
|
st->src_kind = CA_ITER_SRC_ATTACH;
|
|
1727
2011
|
st->level = 2;
|
|
@@ -1729,14 +2013,9 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1729
2013
|
st->ndim = 1; /* logical 1-D L2 layout */
|
|
1730
2014
|
st->flags = flags;
|
|
1731
2015
|
st->bytes = src->bytes;
|
|
1732
|
-
st->axes = axes;
|
|
1733
2016
|
st->naxes = naxes;
|
|
1734
2017
|
|
|
1735
|
-
st
|
|
1736
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0 ? st->scratch_cap : 1);
|
|
1737
|
-
if ( src->elements > 0 ) {
|
|
1738
|
-
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
1739
|
-
}
|
|
2018
|
+
ki_gather_view(st, src, flags, 0);
|
|
1740
2019
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
1741
2020
|
st->alias_ptr = st->scratch_ptr;
|
|
1742
2021
|
st->composed_strides[0] = src->bytes;
|
|
@@ -1773,7 +2052,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1773
2052
|
int8_t nd = raw_ndim;
|
|
1774
2053
|
int8_t k;
|
|
1775
2054
|
|
|
1776
|
-
memset(st, 0, sizeof(*st));
|
|
1777
2055
|
st->src = src;
|
|
1778
2056
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR_L2_ALIASABLE;
|
|
1779
2057
|
st->level = 2;
|
|
@@ -1781,7 +2059,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1781
2059
|
st->ndim = nd;
|
|
1782
2060
|
st->flags = flags;
|
|
1783
2061
|
st->bytes = src->bytes;
|
|
1784
|
-
st->axes = axes;
|
|
1785
2062
|
st->naxes = naxes;
|
|
1786
2063
|
|
|
1787
2064
|
/* Persist descs / parent_axis_dims in state; build parent row-major
|
|
@@ -1864,7 +2141,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1864
2141
|
/* raw_descs / raw_pdims / raw_ndim were populated by route_source
|
|
1865
2142
|
above so we skip the local describe_axes call. Kept locals
|
|
1866
2143
|
named raw_* to match the original code. */
|
|
1867
|
-
memset(st, 0, sizeof(*st));
|
|
1868
2144
|
st->src = src;
|
|
1869
2145
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
1870
2146
|
st->level = 2;
|
|
@@ -1872,7 +2148,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1872
2148
|
st->ndim = src->ndim;
|
|
1873
2149
|
st->flags = flags;
|
|
1874
2150
|
st->bytes = src->bytes;
|
|
1875
|
-
st->axes = axes;
|
|
1876
2151
|
st->naxes = naxes;
|
|
1877
2152
|
|
|
1878
2153
|
memcpy(st->parent_axis_dims, raw_pdims, raw_ndim * sizeof(ca_size_t));
|
|
@@ -1899,12 +2174,11 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1899
2174
|
if ( ca_func[src->obj_type].attach == ca_window_func.attach ) {
|
|
1900
2175
|
bound_fill = ((CAWindow *) src)->fill;
|
|
1901
2176
|
}
|
|
1902
|
-
st->
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
bound_fill);
|
|
2177
|
+
st->scratch_cap = st->total_elements * src->bytes;
|
|
2178
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
2179
|
+
ca_axis_dispatch_gather(parent, st->parent_axis_dims, raw_descs, raw_ndim,
|
|
2180
|
+
src->bytes, st->total_elements, bound_fill,
|
|
2181
|
+
st->scratch_ptr);
|
|
1908
2182
|
|
|
1909
2183
|
/* Lay out as a single 1-D L2 strided slab: ptr = scratch,
|
|
1910
2184
|
n = total_elements, stride = bytes. next_slab_strided reads
|
|
@@ -1938,7 +2212,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1938
2212
|
}
|
|
1939
2213
|
|
|
1940
2214
|
/* === CAStride / entity L2 path === */
|
|
1941
|
-
memset(st, 0, sizeof(*st));
|
|
1942
2215
|
st->src = src;
|
|
1943
2216
|
st->src_kind = CA_ITER_SRC_CASTRIDE;
|
|
1944
2217
|
st->level = 2;
|
|
@@ -1946,7 +2219,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1946
2219
|
st->ndim = src->ndim;
|
|
1947
2220
|
st->flags = flags;
|
|
1948
2221
|
st->bytes = src->bytes;
|
|
1949
|
-
st->axes = axes;
|
|
1950
2222
|
st->naxes = naxes;
|
|
1951
2223
|
|
|
1952
2224
|
/* Compute composed strides + base. For entity / CAStride contig we
|
|
@@ -2062,18 +2334,13 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
2062
2334
|
}
|
|
2063
2335
|
|
|
2064
2336
|
if ( use_strided ) {
|
|
2065
|
-
st->root
|
|
2066
|
-
|
|
2337
|
+
ca_attach(root); /* window: finish detaches st->root */
|
|
2338
|
+
st->root = root; /* recorded once attached */
|
|
2067
2339
|
st->alias_mode = CA_ITER_ALIAS_STRIDED;
|
|
2068
2340
|
st->alias_ptr = (char *) root->ptr;
|
|
2069
2341
|
} else if ( use_view_scratch ) {
|
|
2070
2342
|
st->root = NULL;
|
|
2071
|
-
st
|
|
2072
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0
|
|
2073
|
-
? st->scratch_cap : 1);
|
|
2074
|
-
if ( src->elements > 0 ) {
|
|
2075
|
-
ca_copy_data(src, st->scratch_ptr);
|
|
2076
|
-
}
|
|
2343
|
+
ki_gather_view(st, src, flags, 1);
|
|
2077
2344
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
2078
2345
|
st->alias_ptr = st->scratch_ptr;
|
|
2079
2346
|
} else {
|
|
@@ -2116,18 +2383,13 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
2116
2383
|
st->chunk_size = st->slab_n;
|
|
2117
2384
|
|
|
2118
2385
|
if ( use_strided ) {
|
|
2119
|
-
st->root
|
|
2120
|
-
|
|
2386
|
+
ca_attach(root); /* window: finish detaches st->root */
|
|
2387
|
+
st->root = root; /* recorded once attached */
|
|
2121
2388
|
st->alias_mode = CA_ITER_ALIAS_STRIDED;
|
|
2122
2389
|
st->alias_ptr = (char *) root->ptr;
|
|
2123
2390
|
} else if ( use_view_scratch ) {
|
|
2124
2391
|
st->root = NULL;
|
|
2125
|
-
st
|
|
2126
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0
|
|
2127
|
-
? st->scratch_cap : 1);
|
|
2128
|
-
if ( src->elements > 0 ) {
|
|
2129
|
-
ca_copy_data(src, st->scratch_ptr);
|
|
2130
|
-
}
|
|
2392
|
+
ki_gather_view(st, src, flags, 1);
|
|
2131
2393
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
2132
2394
|
st->alias_ptr = st->scratch_ptr;
|
|
2133
2395
|
} else {
|
|
@@ -2136,11 +2398,22 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
2136
2398
|
st->alias_mode = CA_ITER_ALIAS_CONTIG;
|
|
2137
2399
|
st->alias_ptr = (char *) src->ptr;
|
|
2138
2400
|
}
|
|
2401
|
+
|
|
2402
|
+
/* Mask: gathered in view row-major order, as on the AXES path above;
|
|
2403
|
+
next_slab_strided hands out alias_mask + slab * slab_n. */
|
|
2404
|
+
if ( ca_has_mask(src) ) {
|
|
2405
|
+
ca_size_t mcap = src->elements > 0 ? src->elements : 1;
|
|
2406
|
+
st->scratch_mask = (boolean8_t *) xmalloc(mcap);
|
|
2407
|
+
if ( src->elements > 0 ) {
|
|
2408
|
+
ca_copy_data(src->mask, (char *) st->scratch_mask);
|
|
2409
|
+
}
|
|
2410
|
+
st->alias_mask = st->scratch_mask;
|
|
2411
|
+
}
|
|
2139
2412
|
return CA_ITER_OK;
|
|
2140
2413
|
}
|
|
2141
2414
|
|
|
2142
|
-
int
|
|
2143
|
-
|
|
2415
|
+
static int
|
|
2416
|
+
ca_iter_state_next_slab_unprotected (ca_iter_state *st,
|
|
2144
2417
|
char **out_ptr,
|
|
2145
2418
|
boolean8_t **out_mask,
|
|
2146
2419
|
ca_size_t *out_n)
|
|
@@ -2162,8 +2435,8 @@ ca_iter_state_next_slab (ca_iter_state *st,
|
|
|
2162
2435
|
return 1;
|
|
2163
2436
|
}
|
|
2164
2437
|
|
|
2165
|
-
int
|
|
2166
|
-
|
|
2438
|
+
static int
|
|
2439
|
+
ca_iter_state_next_slab_strided_unprotected (ca_iter_state *st,
|
|
2167
2440
|
char **out_ptr,
|
|
2168
2441
|
boolean8_t **out_mask,
|
|
2169
2442
|
ca_size_t *out_n,
|
|
@@ -2231,8 +2504,57 @@ ca_iter_state_next_slab_strided (ca_iter_state *st,
|
|
|
2231
2504
|
return 1;
|
|
2232
2505
|
}
|
|
2233
2506
|
|
|
2234
|
-
|
|
2235
|
-
|
|
2507
|
+
/* CA_KERNEL_FIBER_CONTIG: a fiber (a walk with one slab axis) reaches the
|
|
2508
|
+
kernel as a contiguous run of cells and of mask flags. Each path of
|
|
2509
|
+
next_slab_axes finds the fiber's first cell and the step along it, and
|
|
2510
|
+
hands both through these two functions, which copy a fiber with any
|
|
2511
|
+
other step into the walk's fiber scratch. Other walks get the pointer
|
|
2512
|
+
back unchanged. */
|
|
2513
|
+
static int
|
|
2514
|
+
ki_fiber_contig_wanted (const ca_iter_state *st)
|
|
2515
|
+
{
|
|
2516
|
+
return (st->flags & CA_KERNEL_FIBER_CONTIG)
|
|
2517
|
+
&& st->naxes == 1 && st->slab_ndim == 1;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
static char *
|
|
2521
|
+
ki_fiber_contig_data (ca_iter_state *st, char *data, ca_size_t step)
|
|
2522
|
+
{
|
|
2523
|
+
ca_size_t n = st->slab_dims[0];
|
|
2524
|
+
ca_size_t bytes = st->bytes;
|
|
2525
|
+
ca_size_t need = n * bytes;
|
|
2526
|
+
if ( ! ki_fiber_contig_wanted(st) || step == bytes ) {
|
|
2527
|
+
return data;
|
|
2528
|
+
}
|
|
2529
|
+
if ( st->fiber_data_scratch_cap < need ) {
|
|
2530
|
+
if ( st->fiber_data_scratch ) ki_data_free(st->fiber_data_scratch, st->fiber_data_scratch_cap);
|
|
2531
|
+
st->fiber_data_scratch = (char *) ki_data_alloc(st->src->data_type, need);
|
|
2532
|
+
st->fiber_data_scratch_cap = need;
|
|
2533
|
+
}
|
|
2534
|
+
ca_stride_gather_run(st->fiber_data_scratch, data, bytes, n, step);
|
|
2535
|
+
return st->fiber_data_scratch;
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
static boolean8_t *
|
|
2539
|
+
ki_fiber_contig_mask (ca_iter_state *st, boolean8_t *mask, ca_size_t step)
|
|
2540
|
+
{
|
|
2541
|
+
ca_size_t n = st->slab_dims[0];
|
|
2542
|
+
if ( mask == NULL || ! ki_fiber_contig_wanted(st) || step == 1 ) {
|
|
2543
|
+
return mask;
|
|
2544
|
+
}
|
|
2545
|
+
if ( st->fiber_mask_scratch_cap < n ) {
|
|
2546
|
+
if ( st->fiber_mask_scratch ) xfree(st->fiber_mask_scratch);
|
|
2547
|
+
st->fiber_mask_scratch = (boolean8_t *) xmalloc(n > 0 ? n : 1);
|
|
2548
|
+
st->fiber_mask_scratch_cap = n;
|
|
2549
|
+
}
|
|
2550
|
+
for ( ca_size_t i = 0; i < n; i++ ) {
|
|
2551
|
+
st->fiber_mask_scratch[i] = mask[i * step];
|
|
2552
|
+
}
|
|
2553
|
+
return st->fiber_mask_scratch;
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
static int
|
|
2557
|
+
ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
2236
2558
|
char **out_ptr,
|
|
2237
2559
|
boolean8_t **out_mask)
|
|
2238
2560
|
{
|
|
@@ -2330,7 +2652,11 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2330
2652
|
}
|
|
2331
2653
|
|
|
2332
2654
|
if ( out_ptr ) *out_ptr = st->scratch_ptr;
|
|
2333
|
-
if ( out_mask )
|
|
2655
|
+
if ( out_mask ) {
|
|
2656
|
+
*out_mask = ki_fiber_contig_mask(st,
|
|
2657
|
+
st->scratch_mask ? st->scratch_mask + mask_off : NULL,
|
|
2658
|
+
st->slab_mask_strides[0]);
|
|
2659
|
+
}
|
|
2334
2660
|
|
|
2335
2661
|
st->slabs_emitted += 1;
|
|
2336
2662
|
for ( int8_t m = st->outer_ndim - 1; m >= 0; m-- ) {
|
|
@@ -2366,11 +2692,15 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2366
2692
|
mask_off += st->outer_idx[m] * st->stack_parent_mask_strides[parent_ax];
|
|
2367
2693
|
}
|
|
2368
2694
|
|
|
2369
|
-
if ( out_ptr )
|
|
2695
|
+
if ( out_ptr ) {
|
|
2696
|
+
*out_ptr = ki_fiber_contig_data(st, st->stack_parent_ptrs[k] + parent_off,
|
|
2697
|
+
st->slab_strides[0]);
|
|
2698
|
+
}
|
|
2370
2699
|
if ( out_mask ) {
|
|
2371
|
-
*out_mask = st
|
|
2372
|
-
|
|
2373
|
-
|
|
2700
|
+
*out_mask = ki_fiber_contig_mask(st,
|
|
2701
|
+
st->stack_parent_mask_ptrs
|
|
2702
|
+
? st->stack_parent_mask_ptrs[k] + mask_off : NULL,
|
|
2703
|
+
st->slab_mask_strides[0]);
|
|
2374
2704
|
}
|
|
2375
2705
|
|
|
2376
2706
|
st->slabs_emitted += 1;
|
|
@@ -2521,7 +2851,11 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2521
2851
|
}
|
|
2522
2852
|
|
|
2523
2853
|
if ( out_ptr ) *out_ptr = st->scratch_ptr;
|
|
2524
|
-
if ( out_mask )
|
|
2854
|
+
if ( out_mask ) {
|
|
2855
|
+
*out_mask = ki_fiber_contig_mask(st,
|
|
2856
|
+
st->scratch_mask ? st->scratch_mask + mask_off : NULL,
|
|
2857
|
+
st->slab_mask_strides[0]);
|
|
2858
|
+
}
|
|
2525
2859
|
|
|
2526
2860
|
st->slabs_emitted += 1;
|
|
2527
2861
|
/* Advance outer_idx row-major (innermost outer axis ticks first). */
|
|
@@ -2582,8 +2916,8 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2582
2916
|
ca_size_t counts[CA_RANK_MAX];
|
|
2583
2917
|
|
|
2584
2918
|
if ( st->fiber_data_scratch_cap < need ) {
|
|
2585
|
-
if ( st->fiber_data_scratch )
|
|
2586
|
-
st->fiber_data_scratch = (char *)
|
|
2919
|
+
if ( st->fiber_data_scratch ) ki_data_free(st->fiber_data_scratch, st->fiber_data_scratch_cap);
|
|
2920
|
+
st->fiber_data_scratch = (char *) ki_data_alloc(st->src->data_type, need);
|
|
2587
2921
|
st->fiber_data_scratch_cap = need;
|
|
2588
2922
|
}
|
|
2589
2923
|
|
|
@@ -2661,72 +2995,14 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2661
2995
|
Capture last_data_off BEFORE the outer_idx advance below; sync_slab
|
|
2662
2996
|
consumes it for WRITE scatter. See header field doc + PROPOSAL
|
|
2663
2997
|
§4.3.2 hazard comment in sync_slab. */
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
st->last_data_off = data_off;
|
|
2673
|
-
|
|
2674
|
-
if ( data_step == (ca_size_t) bytes ) {
|
|
2675
|
-
/* Fast path: fiber is already contig (= innermost-axis or stride
|
|
2676
|
-
coincidentally == bytes). No gather needed. */
|
|
2677
|
-
yield_ptr = src_data;
|
|
2678
|
-
} else {
|
|
2679
|
-
/* Per-fiber gather via the typed-store inline helper
|
|
2680
|
-
(ca_iter_substrate.h). For bytes in {1,2,4,8} this uses a
|
|
2681
|
-
compiler-vectorize-friendly `*dp++ = v; sp += step` loop;
|
|
2682
|
-
other sizes fall back to per-element memcpy. Lazy-alloc
|
|
2683
|
-
scratch sized to max fiber bytes (slab_dims[0] constant per
|
|
2684
|
-
walk → single alloc in practice). */
|
|
2685
|
-
ca_size_t need = n * bytes;
|
|
2686
|
-
if ( st->fiber_data_scratch_cap < need ) {
|
|
2687
|
-
if ( st->fiber_data_scratch ) xfree(st->fiber_data_scratch);
|
|
2688
|
-
st->fiber_data_scratch = (char *) xmalloc(need);
|
|
2689
|
-
st->fiber_data_scratch_cap = need;
|
|
2690
|
-
}
|
|
2691
|
-
ca_stride_gather_run(st->fiber_data_scratch, src_data,
|
|
2692
|
-
bytes, n, data_step);
|
|
2693
|
-
yield_ptr = st->fiber_data_scratch;
|
|
2694
|
-
}
|
|
2695
|
-
} else {
|
|
2696
|
-
yield_ptr = st->alias_ptr + data_off;
|
|
2697
|
-
}
|
|
2698
|
-
|
|
2699
|
-
/* PROPOSAL_FIBER_DELIVERY F.1b: per-fiber contig mask delivery.
|
|
2700
|
-
Symmetric to F.1a data path above. When the source has a mask
|
|
2701
|
-
(= alias_mask != NULL) and the fiber's mask is not innermost-contig
|
|
2702
|
-
(= slab_mask_strides[0] != 1), gather it into fiber_mask_scratch
|
|
2703
|
-
so the author can write m[i] without stride math. Mask is
|
|
2704
|
-
read-only here (= L2 WRITE never propagates to mask state), so no
|
|
2705
|
-
scatter is needed in sync_slab. */
|
|
2706
|
-
boolean8_t *yield_mask;
|
|
2707
|
-
if ( (st->flags & CA_KERNEL_FIBER_CONTIG)
|
|
2708
|
-
&& st->naxes == 1 && st->slab_ndim == 1
|
|
2709
|
-
&& st->alias_mask != NULL ) {
|
|
2710
|
-
ca_size_t n = st->slab_dims[0];
|
|
2711
|
-
ca_size_t mask_step = st->slab_mask_strides[0];
|
|
2712
|
-
boolean8_t *src_mask = st->alias_mask + mask_off;
|
|
2713
|
-
|
|
2714
|
-
if ( mask_step == 1 ) {
|
|
2715
|
-
yield_mask = src_mask;
|
|
2716
|
-
} else {
|
|
2717
|
-
if ( st->fiber_mask_scratch_cap < (ca_size_t) n ) {
|
|
2718
|
-
if ( st->fiber_mask_scratch ) xfree(st->fiber_mask_scratch);
|
|
2719
|
-
st->fiber_mask_scratch = (boolean8_t *) xmalloc(n);
|
|
2720
|
-
st->fiber_mask_scratch_cap = n;
|
|
2721
|
-
}
|
|
2722
|
-
for ( ca_size_t i = 0; i < n; i++ ) {
|
|
2723
|
-
st->fiber_mask_scratch[i] = src_mask[i * mask_step];
|
|
2724
|
-
}
|
|
2725
|
-
yield_mask = st->fiber_mask_scratch;
|
|
2726
|
-
}
|
|
2727
|
-
} else {
|
|
2728
|
-
yield_mask = st->alias_mask ? st->alias_mask + mask_off : NULL;
|
|
2729
|
-
}
|
|
2998
|
+
/* sync_slab finds the slab here: the fiber it scatters back, and the
|
|
2999
|
+
cells of a whole-view scratch it compares. */
|
|
3000
|
+
st->last_data_off = data_off;
|
|
3001
|
+
char *yield_ptr = ki_fiber_contig_data(st, st->alias_ptr + data_off,
|
|
3002
|
+
st->slab_strides[0]);
|
|
3003
|
+
boolean8_t *yield_mask = ki_fiber_contig_mask(st,
|
|
3004
|
+
st->alias_mask ? st->alias_mask + mask_off : NULL,
|
|
3005
|
+
st->slab_mask_strides[0]);
|
|
2730
3006
|
|
|
2731
3007
|
if ( out_ptr ) *out_ptr = yield_ptr;
|
|
2732
3008
|
if ( out_mask ) *out_mask = yield_mask;
|
|
@@ -2742,38 +3018,22 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2742
3018
|
return 1;
|
|
2743
3019
|
}
|
|
2744
3020
|
|
|
2745
|
-
void
|
|
2746
|
-
|
|
3021
|
+
static void
|
|
3022
|
+
ca_iter_state_sync_slab_unprotected (ca_iter_state *st)
|
|
2747
3023
|
{
|
|
2748
3024
|
/* READ walk: nothing to sync. */
|
|
2749
3025
|
if ( st == NULL || !(st->flags & CA_KERNEL_WRITE) ) return;
|
|
2750
3026
|
|
|
2751
|
-
/*
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
3027
|
+
/* Neither stack mode can be reached with WRITE set: both are declined
|
|
3028
|
+
at init, which sends a write destination down the generic SRC_ATTACH
|
|
3029
|
+
path instead. They cannot serve a write themselves -- ALIAS_STACK
|
|
3030
|
+
hands out a tile cache that finish frees, and STACK_OUTER_K aliases
|
|
3031
|
+
parents[k]->ptr, which is the attach buffer rather than the parent's
|
|
3032
|
+
own memory whenever the parent is a view. Scattering per parent
|
|
3033
|
+
would let the fast paths carry writes too; until then this branch is
|
|
3034
|
+
just the assertion that they are not asked to. */
|
|
2757
3035
|
if ( st->alias_mode == CA_ITER_ALIAS_STACK
|
|
2758
3036
|
|| st->alias_mode == CA_ITER_ALIAS_STACK_OUTER_K ) {
|
|
2759
|
-
/* STACK_OUTER_K (P.2 Case A) is READ-only scope: slabs are direct
|
|
2760
|
-
aliases into parents[k]->ptr, kernel WRITE would scatter into
|
|
2761
|
-
parent memory which is out of scope (see proposal R1). Skip
|
|
2762
|
-
sync. */
|
|
2763
|
-
st->write_dirty = 0;
|
|
2764
|
-
return;
|
|
2765
|
-
}
|
|
2766
|
-
|
|
2767
|
-
/* SRC_ATTACH path (step 9 + 2026-05-31 refactor): kernel wrote into
|
|
2768
|
-
iterator-owned scratch (= scratch_ptr). Push back via xfer_all PUT
|
|
2769
|
-
which routes through the view's xfer_all slot -- handles CAFake
|
|
2770
|
-
(cast back), CAByteSwap (swap back), CABitfield/CABitarray (bit
|
|
2771
|
-
pack back), CAReduce (broadcast across reduce window). Inherits
|
|
2772
|
-
transform-fused / partial materialise / etc. automatically. */
|
|
2773
|
-
if ( st->src_kind == CA_ITER_SRC_ATTACH ) {
|
|
2774
|
-
if ( st->src->elements > 0 ) {
|
|
2775
|
-
ca_xfer_all(st->src, st->scratch_ptr, CA_XFER_PUT);
|
|
2776
|
-
}
|
|
2777
3037
|
st->write_dirty = 0;
|
|
2778
3038
|
return;
|
|
2779
3039
|
}
|
|
@@ -2852,12 +3112,27 @@ ca_iter_state_sync_slab (ca_iter_state *st)
|
|
|
2852
3112
|
ca_stride_scatter_run(dst, st->fiber_data_scratch,
|
|
2853
3113
|
bytes, n, data_step);
|
|
2854
3114
|
}
|
|
2855
|
-
/* Fall through
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
3115
|
+
/* Fall through. The gather above is not specific to a src_kind --
|
|
3116
|
+
it fires for any source whose fiber is not innermost-contig -- so
|
|
3117
|
+
for SRC_ATTACH this has just written the fiber back into the
|
|
3118
|
+
whole-view scratch, and the push-back below carries it to the
|
|
3119
|
+
source. For the alias paths scratch_ptr is NULL and the switch
|
|
3120
|
+
below early-returns. */
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
/* SRC_ATTACH path: the kernel wrote into the iterator's whole-view
|
|
3124
|
+
scratch. The changed cells go back through the view's own transfer,
|
|
3125
|
+
which converts, packs or scatters them as the view requires.
|
|
3126
|
+
|
|
3127
|
+
This has to stay below the two per-fiber blocks: consulting
|
|
3128
|
+
src_kind first would push back the whole-view buffer while the
|
|
3129
|
+
fiber the author actually wrote sat unscattered in
|
|
3130
|
+
fiber_data_scratch, and would push back a NULL one for
|
|
3131
|
+
PER_FIBER_FUSED, which owns no whole-view buffer at all. */
|
|
3132
|
+
if ( st->src_kind == CA_ITER_SRC_ATTACH ) {
|
|
3133
|
+
ki_scratch_push_changed(st);
|
|
3134
|
+
st->write_dirty = 0;
|
|
3135
|
+
return;
|
|
2861
3136
|
}
|
|
2862
3137
|
|
|
2863
3138
|
/* alias path: kernel wrote through alias_ptr into parent directly
|
|
@@ -2874,11 +3149,10 @@ ca_iter_state_sync_slab (ca_iter_state *st)
|
|
|
2874
3149
|
case CA_ITER_SRC_CASTRIDE:
|
|
2875
3150
|
/* Two producers of CAStride + scratch: L1 non-contig, and the L2
|
|
2876
3151
|
non-entity-root path (init_l2's use_view_scratch). Both gathered
|
|
2877
|
-
with ca_copy_data into a view row-major buffer
|
|
2878
|
-
back the
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
ca_sync_data(st->src, st->scratch_ptr);
|
|
3152
|
+
with ca_copy_data into a view row-major buffer; the changed
|
|
3153
|
+
cells go back through the view's own transfer, which asks the
|
|
3154
|
+
root for the region it owns. */
|
|
3155
|
+
ki_scratch_push_changed(st);
|
|
2882
3156
|
break;
|
|
2883
3157
|
|
|
2884
3158
|
case CA_ITER_SRC_DESCRIPTOR: {
|
|
@@ -2911,12 +3185,17 @@ ca_iter_state_sync_slab (ca_iter_state *st)
|
|
|
2911
3185
|
st->write_dirty = 0;
|
|
2912
3186
|
}
|
|
2913
3187
|
|
|
3188
|
+
static VALUE ca_iter_finish_sync (VALUE arg);
|
|
3189
|
+
|
|
2914
3190
|
void
|
|
2915
3191
|
ca_iter_state_finish (ca_iter_state *st)
|
|
2916
3192
|
{
|
|
2917
3193
|
if ( st == NULL || st->src == NULL ) {
|
|
2918
3194
|
return;
|
|
2919
3195
|
}
|
|
3196
|
+
/* A slab still handed out is dropped: finish abandons it. The block
|
|
3197
|
+
macros close with ca_iter_state_close, which writes it back first. */
|
|
3198
|
+
st->write_dirty = 0;
|
|
2920
3199
|
/* composed_strides is inline — no free needed. outer_idx is heap
|
|
2921
3200
|
for L2 multi-d sources (NULL on L1 paths and on L2 0/1-d). */
|
|
2922
3201
|
if ( st->outer_idx ) {
|
|
@@ -2933,7 +3212,7 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2933
3212
|
ca_detach.
|
|
2934
3213
|
- else (alias paths): src was attached at init, detach. */
|
|
2935
3214
|
if ( st->scratch_ptr ) {
|
|
2936
|
-
|
|
3215
|
+
ki_data_free(st->scratch_ptr, st->scratch_cap);
|
|
2937
3216
|
st->scratch_ptr = NULL;
|
|
2938
3217
|
st->scratch_cap = 0;
|
|
2939
3218
|
}
|
|
@@ -2943,7 +3222,7 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2943
3222
|
}
|
|
2944
3223
|
/* PROPOSAL_FIBER_DELIVERY F.1a/F.1b: per-fiber scratch lifecycle. */
|
|
2945
3224
|
if ( st->fiber_data_scratch ) {
|
|
2946
|
-
|
|
3225
|
+
ki_data_free(st->fiber_data_scratch, st->fiber_data_scratch_cap);
|
|
2947
3226
|
st->fiber_data_scratch = NULL;
|
|
2948
3227
|
st->fiber_data_scratch_cap = 0;
|
|
2949
3228
|
}
|
|
@@ -2965,24 +3244,34 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2965
3244
|
}
|
|
2966
3245
|
/* pilot/castack-axis0-loop-interchange: free tile cache. */
|
|
2967
3246
|
if ( st->stack_tile_cache ) {
|
|
2968
|
-
|
|
3247
|
+
ki_data_free(st->stack_tile_cache, 0);
|
|
2969
3248
|
st->stack_tile_cache = NULL;
|
|
2970
3249
|
st->stack_tile_cap = 0;
|
|
2971
3250
|
st->stack_tile_pos = 0;
|
|
2972
3251
|
st->stack_tile_have = 0;
|
|
2973
3252
|
}
|
|
2974
3253
|
if ( st->stack_parent_mask_ptrs ) {
|
|
2975
|
-
CAStack *stack = (CAStack *) st->src;
|
|
2976
3254
|
for ( int32_t kk = 0; kk < st->stack_n_parents; kk++ ) {
|
|
2977
|
-
|
|
3255
|
+
if ( st->stack_parent_mask_ptrs[kk] ) {
|
|
3256
|
+
xfree(st->stack_parent_mask_ptrs[kk]);
|
|
3257
|
+
}
|
|
2978
3258
|
}
|
|
2979
3259
|
xfree(st->stack_parent_mask_ptrs);
|
|
2980
3260
|
st->stack_parent_mask_ptrs = NULL;
|
|
2981
3261
|
}
|
|
2982
3262
|
st->stack_n_parents = 0;
|
|
2983
3263
|
if ( st->root ) {
|
|
2984
|
-
|
|
3264
|
+
/* A write walk wrote into the root's attach buffer, which is the root
|
|
3265
|
+
itself only for an entity: a view root (a transpose, a non-contig
|
|
3266
|
+
block, a view lending no memory) gave a buffer of its own. */
|
|
3267
|
+
CArray *root = st->root;
|
|
2985
3268
|
st->root = NULL;
|
|
3269
|
+
if ( st->flags & CA_KERNEL_WRITE ) {
|
|
3270
|
+
ca_sync_detach(root);
|
|
3271
|
+
}
|
|
3272
|
+
else {
|
|
3273
|
+
ca_detach(root);
|
|
3274
|
+
}
|
|
2986
3275
|
} else if ( st->alias_mode == CA_ITER_ALIAS_CONTIG
|
|
2987
3276
|
|| st->alias_mode == CA_ITER_ALIAS_STRIDED ) {
|
|
2988
3277
|
/* alias path (CONTIG/STRIDED for CAStride family): we attached
|
|
@@ -2992,10 +3281,429 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2992
3281
|
NONE, scratch_ptr xfree'd above), so no src.detach needed. */
|
|
2993
3282
|
ca_detach(st->src);
|
|
2994
3283
|
}
|
|
3284
|
+
if ( st->flags & CA_ITER_FLAG_OWNS_SRC ) {
|
|
3285
|
+
CArray *own = st->src;
|
|
3286
|
+
st->flags &= ~CA_ITER_FLAG_OWNS_SRC;
|
|
3287
|
+
if ( ca_is_object_type(own) ) {
|
|
3288
|
+
ca_gc_release_buffer(own->ptr);
|
|
3289
|
+
}
|
|
3290
|
+
ca_free(own);
|
|
3291
|
+
}
|
|
2995
3292
|
st->src = NULL;
|
|
2996
3293
|
st->alias_ptr = NULL;
|
|
2997
3294
|
}
|
|
2998
3295
|
|
|
3296
|
+
/* Finish a walk the way the block macros leave it: a slab of a write walk
|
|
3297
|
+
still handed out -- the body left with `break` -- is written back
|
|
3298
|
+
first. A raise from the write-back is passed on once the walk is
|
|
3299
|
+
finished. */
|
|
3300
|
+
void
|
|
3301
|
+
ca_iter_state_close (ca_iter_state *st)
|
|
3302
|
+
{
|
|
3303
|
+
int tag = 0;
|
|
3304
|
+
if ( st != NULL && st->src != NULL && st->write_dirty ) {
|
|
3305
|
+
rb_protect(ca_iter_finish_sync, (VALUE) st, &tag);
|
|
3306
|
+
}
|
|
3307
|
+
ca_iter_state_finish(st);
|
|
3308
|
+
if ( tag ) {
|
|
3309
|
+
rb_jump_tag(tag);
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
/* ---- Raise-safe entry points ----------------------------------------
|
|
3314
|
+
*
|
|
3315
|
+
* A walk reads its source, and a source that converts as it is read (a
|
|
3316
|
+
* lazy view over an object array, say) raises when it meets a cell it
|
|
3317
|
+
* cannot convert. The caller's loop then never reaches
|
|
3318
|
+
* ca_iter_state_finish -- the block macros put it in the `for`
|
|
3319
|
+
* increment, which a raise jumps over, and it is past the raise in
|
|
3320
|
+
* hand-written walks too. So the walk finishes itself on the way out.
|
|
3321
|
+
*
|
|
3322
|
+
* Every entry point that can raise is called through rb_protect here,
|
|
3323
|
+
* and ca_iter_state_finish is idempotent (it clears st->src), so the
|
|
3324
|
+
* caller's own finish after an ordinary walk stays correct.
|
|
3325
|
+
*
|
|
3326
|
+
* Not covered here: a kernel body that raises. It runs in the caller's
|
|
3327
|
+
* frame, between two calls of these functions, where the engine has no
|
|
3328
|
+
* hold on it. A body that can raise runs through ca_iter_ensure below.
|
|
3329
|
+
*
|
|
3330
|
+
* init runs protected always -- once per walk, next to a materialise.
|
|
3331
|
+
* next_slab / sync_slab are called once per slab, in walks whose whole
|
|
3332
|
+
* per-fiber cost can be a few nanoseconds, so they are protected only
|
|
3333
|
+
* when this walk can raise at all: when it gathers each fiber through
|
|
3334
|
+
* the source's own transfer slots, or when it writes scratch back
|
|
3335
|
+
* through them. Every other shape hands out pointers into memory that
|
|
3336
|
+
* init already materialised, and moves it with memcpy. */
|
|
3337
|
+
|
|
3338
|
+
/* Private flags bit, kept in ca_iter_state.flags rather than a field of
|
|
3339
|
+
its own: the state is stack-allocated by ext authors through the block
|
|
3340
|
+
macros, so growing it would overrun states built against an older
|
|
3341
|
+
header. */
|
|
3342
|
+
#define CA_ITER_FLAG_WALK_MAY_RAISE 0x80000000u
|
|
3343
|
+
|
|
3344
|
+
|
|
3345
|
+
typedef struct {
|
|
3346
|
+
ca_iter_state *st;
|
|
3347
|
+
CArray *src;
|
|
3348
|
+
ca_slab_policy_t policy;
|
|
3349
|
+
int8_t *axes;
|
|
3350
|
+
int8_t naxes;
|
|
3351
|
+
uint32_t flags;
|
|
3352
|
+
char **out_ptr;
|
|
3353
|
+
boolean8_t **out_mask;
|
|
3354
|
+
ca_size_t *out_n;
|
|
3355
|
+
ca_size_t *out_stride_bytes;
|
|
3356
|
+
int rc;
|
|
3357
|
+
} ca_iter_call_t;
|
|
3358
|
+
|
|
3359
|
+
/* Whether next_slab / sync_slab on this walk need the protection. */
|
|
3360
|
+
static void
|
|
3361
|
+
ca_iter_mark_walk_may_raise (ca_iter_state *st)
|
|
3362
|
+
{
|
|
3363
|
+
if ( st == NULL ) return;
|
|
3364
|
+
if ( st->alias_mode == CA_ITER_ALIAS_PER_FIBER_FUSED ) {
|
|
3365
|
+
/* gathers each fiber through the source's xfer_stride slot */
|
|
3366
|
+
st->flags |= CA_ITER_FLAG_WALK_MAY_RAISE;
|
|
3367
|
+
}
|
|
3368
|
+
else if ( (st->flags & CA_KERNEL_WRITE)
|
|
3369
|
+
&& (st->scratch_ptr != NULL
|
|
3370
|
+
|| st->src_kind == CA_ITER_SRC_ATTACH) ) {
|
|
3371
|
+
/* writes back out of iterator-owned scratch, through the source's
|
|
3372
|
+
xfer_all / sync_data slot. A write into aliased memory needs no
|
|
3373
|
+
push-back at all: sync_slab returns at once. */
|
|
3374
|
+
st->flags |= CA_ITER_FLAG_WALK_MAY_RAISE;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
/* When body raises, finish st -- and the state it is paired with (see
|
|
3379
|
+
ca_iter_state_init_l2_paired), which is open in the same frame and
|
|
3380
|
+
would otherwise be jumped over. */
|
|
3381
|
+
static void
|
|
3382
|
+
ca_iter_protect (ca_iter_state *st, VALUE (*body)(VALUE), VALUE arg)
|
|
3383
|
+
{
|
|
3384
|
+
int tag = 0;
|
|
3385
|
+
rb_protect(body, arg, &tag);
|
|
3386
|
+
if ( tag ) {
|
|
3387
|
+
ca_iter_state *pair = (ca_iter_state *) st->pair;
|
|
3388
|
+
ca_iter_state_finish(st);
|
|
3389
|
+
if ( pair != NULL ) {
|
|
3390
|
+
ca_iter_state_finish(pair);
|
|
3391
|
+
}
|
|
3392
|
+
rb_jump_tag(tag);
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
static VALUE
|
|
3397
|
+
ca_iter_call_init_l1 (VALUE arg)
|
|
3398
|
+
{
|
|
3399
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3400
|
+
c->rc = ca_iter_state_init_l1_unprotected(c->st, c->src, c->policy,
|
|
3401
|
+
c->axes, c->naxes, c->flags);
|
|
3402
|
+
return Qnil;
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
static VALUE
|
|
3406
|
+
ca_iter_call_init_l2 (VALUE arg)
|
|
3407
|
+
{
|
|
3408
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3409
|
+
c->rc = ca_iter_state_init_l2_unprotected(c->st, c->src, c->policy,
|
|
3410
|
+
c->axes, c->naxes, c->flags);
|
|
3411
|
+
return Qnil;
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
static VALUE
|
|
3415
|
+
ca_iter_call_next_slab (VALUE arg)
|
|
3416
|
+
{
|
|
3417
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3418
|
+
c->rc = ca_iter_state_next_slab_unprotected(c->st, c->out_ptr,
|
|
3419
|
+
c->out_mask, c->out_n);
|
|
3420
|
+
return Qnil;
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
static VALUE
|
|
3424
|
+
ca_iter_call_next_slab_strided (VALUE arg)
|
|
3425
|
+
{
|
|
3426
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3427
|
+
c->rc = ca_iter_state_next_slab_strided_unprotected(c->st, c->out_ptr,
|
|
3428
|
+
c->out_mask, c->out_n,
|
|
3429
|
+
c->out_stride_bytes);
|
|
3430
|
+
return Qnil;
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
static VALUE
|
|
3434
|
+
ca_iter_call_next_slab_axes (VALUE arg)
|
|
3435
|
+
{
|
|
3436
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3437
|
+
c->rc = ca_iter_state_next_slab_axes_unprotected(c->st, c->out_ptr,
|
|
3438
|
+
c->out_mask);
|
|
3439
|
+
return Qnil;
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
static VALUE
|
|
3443
|
+
ca_iter_call_sync_slab (VALUE arg)
|
|
3444
|
+
{
|
|
3445
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3446
|
+
ca_iter_state_sync_slab_unprotected(c->st);
|
|
3447
|
+
return Qnil;
|
|
3448
|
+
}
|
|
3449
|
+
|
|
3450
|
+
int
|
|
3451
|
+
ca_iter_state_init_l1 (ca_iter_state *st,
|
|
3452
|
+
struct _CArray *src,
|
|
3453
|
+
ca_slab_policy_t policy,
|
|
3454
|
+
int8_t *axes,
|
|
3455
|
+
int8_t naxes,
|
|
3456
|
+
uint32_t flags)
|
|
3457
|
+
{
|
|
3458
|
+
ca_iter_call_t c;
|
|
3459
|
+
c.st = st; c.src = src; c.policy = policy;
|
|
3460
|
+
c.axes = axes; c.naxes = naxes; c.flags = flags; c.rc = CA_ITER_OK;
|
|
3461
|
+
if ( st != NULL ) {
|
|
3462
|
+
st->pair = NULL; /* read by ca_iter_protect if the init raises */
|
|
3463
|
+
}
|
|
3464
|
+
ca_iter_protect(st, ca_iter_call_init_l1, (VALUE) &c);
|
|
3465
|
+
if ( c.rc == CA_ITER_OK ) ca_iter_mark_walk_may_raise(st);
|
|
3466
|
+
return c.rc;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
int
|
|
3470
|
+
ca_iter_state_init_l2 (ca_iter_state *st,
|
|
3471
|
+
struct _CArray *src,
|
|
3472
|
+
ca_slab_policy_t policy,
|
|
3473
|
+
int8_t *axes,
|
|
3474
|
+
int8_t naxes,
|
|
3475
|
+
uint32_t flags)
|
|
3476
|
+
{
|
|
3477
|
+
ca_iter_call_t c;
|
|
3478
|
+
c.st = st; c.src = src; c.policy = policy;
|
|
3479
|
+
c.axes = axes; c.naxes = naxes; c.flags = flags; c.rc = CA_ITER_OK;
|
|
3480
|
+
if ( st != NULL ) {
|
|
3481
|
+
st->pair = NULL; /* read by ca_iter_protect if the init raises */
|
|
3482
|
+
}
|
|
3483
|
+
ca_iter_protect(st, ca_iter_call_init_l2, (VALUE) &c);
|
|
3484
|
+
if ( c.rc == CA_ITER_OK ) ca_iter_mark_walk_may_raise(st);
|
|
3485
|
+
return c.rc;
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
/* A slab handed out by a write walk is dirty until sync_slab writes it
|
|
3489
|
+
back; finish writes back one the caller left with `break`. */
|
|
3490
|
+
static int
|
|
3491
|
+
ca_iter_mark_dirty (ca_iter_state *st, int rc)
|
|
3492
|
+
{
|
|
3493
|
+
if ( rc && st != NULL && (st->flags & CA_KERNEL_WRITE) ) {
|
|
3494
|
+
st->write_dirty = 1;
|
|
3495
|
+
}
|
|
3496
|
+
return rc;
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
static VALUE
|
|
3500
|
+
ca_iter_finish_sync (VALUE arg)
|
|
3501
|
+
{
|
|
3502
|
+
ca_iter_state_sync_slab_unprotected((ca_iter_state *) arg);
|
|
3503
|
+
return Qnil;
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
int
|
|
3507
|
+
ca_iter_state_next_slab (ca_iter_state *st,
|
|
3508
|
+
char **out_ptr,
|
|
3509
|
+
boolean8_t **out_mask,
|
|
3510
|
+
ca_size_t *out_n)
|
|
3511
|
+
{
|
|
3512
|
+
ca_iter_call_t c;
|
|
3513
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3514
|
+
return ca_iter_mark_dirty(st,
|
|
3515
|
+
ca_iter_state_next_slab_unprotected(st, out_ptr, out_mask, out_n));
|
|
3516
|
+
}
|
|
3517
|
+
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.out_n = out_n;
|
|
3518
|
+
c.rc = 0;
|
|
3519
|
+
ca_iter_protect(st, ca_iter_call_next_slab, (VALUE) &c);
|
|
3520
|
+
return ca_iter_mark_dirty(st, c.rc);
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
int
|
|
3524
|
+
ca_iter_state_next_slab_strided (ca_iter_state *st,
|
|
3525
|
+
char **out_ptr,
|
|
3526
|
+
boolean8_t **out_mask,
|
|
3527
|
+
ca_size_t *out_n,
|
|
3528
|
+
ca_size_t *out_stride_bytes)
|
|
3529
|
+
{
|
|
3530
|
+
ca_iter_call_t c;
|
|
3531
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3532
|
+
return ca_iter_mark_dirty(st,
|
|
3533
|
+
ca_iter_state_next_slab_strided_unprotected(st, out_ptr, out_mask,
|
|
3534
|
+
out_n, out_stride_bytes));
|
|
3535
|
+
}
|
|
3536
|
+
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.out_n = out_n;
|
|
3537
|
+
c.out_stride_bytes = out_stride_bytes; c.rc = 0;
|
|
3538
|
+
ca_iter_protect(st, ca_iter_call_next_slab_strided, (VALUE) &c);
|
|
3539
|
+
return ca_iter_mark_dirty(st, c.rc);
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
int
|
|
3543
|
+
ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
3544
|
+
char **out_ptr,
|
|
3545
|
+
boolean8_t **out_mask)
|
|
3546
|
+
{
|
|
3547
|
+
ca_iter_call_t c;
|
|
3548
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3549
|
+
return ca_iter_mark_dirty(st,
|
|
3550
|
+
ca_iter_state_next_slab_axes_unprotected(st, out_ptr, out_mask));
|
|
3551
|
+
}
|
|
3552
|
+
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.rc = 0;
|
|
3553
|
+
ca_iter_protect(st, ca_iter_call_next_slab_axes, (VALUE) &c);
|
|
3554
|
+
return ca_iter_mark_dirty(st, c.rc);
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
void
|
|
3558
|
+
ca_iter_state_sync_slab (ca_iter_state *st)
|
|
3559
|
+
{
|
|
3560
|
+
ca_iter_call_t c;
|
|
3561
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3562
|
+
ca_iter_state_sync_slab_unprotected(st);
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
c.st = st;
|
|
3566
|
+
ca_iter_protect(st, ca_iter_call_sync_slab, (VALUE) &c);
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
typedef struct {
|
|
3570
|
+
ca_iter_state *st;
|
|
3571
|
+
CArray *src;
|
|
3572
|
+
CArray *copy;
|
|
3573
|
+
} ca_iter_reopen_t;
|
|
3574
|
+
|
|
3575
|
+
static VALUE
|
|
3576
|
+
ca_iter_reopen_copy (VALUE arg)
|
|
3577
|
+
{
|
|
3578
|
+
ca_iter_reopen_t *r = (ca_iter_reopen_t *) arg;
|
|
3579
|
+
r->copy = ca_copy(r->src);
|
|
3580
|
+
return Qnil;
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
/* A read walk whose source lives in the root a paired write walk writes
|
|
3584
|
+
into would read cells the kernel has already written: an aliased fiber
|
|
3585
|
+
is the written memory itself, and a gathered one is read from the root
|
|
3586
|
+
after earlier fibers were written back. Such a read walk is reopened
|
|
3587
|
+
on a copy of its source, taken before anything is written and owned by
|
|
3588
|
+
the walk. Returns the init's rc; a raise finishes `first` first. */
|
|
3589
|
+
static int
|
|
3590
|
+
ca_iter_reopen_on_copy (ca_iter_state *first)
|
|
3591
|
+
{
|
|
3592
|
+
ca_iter_reopen_t r;
|
|
3593
|
+
ca_iter_call_t c;
|
|
3594
|
+
int8_t axes[CA_RANK_MAX];
|
|
3595
|
+
int8_t naxes = first->naxes;
|
|
3596
|
+
uint32_t flags = first->flags & ~(CA_ITER_FLAG_WALK_MAY_RAISE
|
|
3597
|
+
| CA_ITER_FLAG_OWNS_SRC);
|
|
3598
|
+
ca_slab_policy_t policy = first->policy;
|
|
3599
|
+
int tag = 0;
|
|
3600
|
+
|
|
3601
|
+
memcpy(axes, first->slab_axes_buf, (size_t) naxes);
|
|
3602
|
+
r.st = first; r.src = first->src; r.copy = NULL;
|
|
3603
|
+
rb_protect(ca_iter_reopen_copy, (VALUE) &r, &tag);
|
|
3604
|
+
if ( tag ) {
|
|
3605
|
+
ca_iter_state_finish(first);
|
|
3606
|
+
rb_jump_tag(tag);
|
|
3607
|
+
}
|
|
3608
|
+
if ( ca_is_object_type(r.copy) ) {
|
|
3609
|
+
/* the walk overwrites the cells that held these VALUEs */
|
|
3610
|
+
ca_gc_hold_buffer(r.copy->ptr, r.copy->elements);
|
|
3611
|
+
}
|
|
3612
|
+
ca_iter_state_finish(first);
|
|
3613
|
+
|
|
3614
|
+
c.st = first; c.src = r.copy; c.policy = policy;
|
|
3615
|
+
c.axes = axes; c.naxes = naxes; c.flags = flags; c.rc = CA_ITER_OK;
|
|
3616
|
+
rb_protect(ca_iter_call_init_l2, (VALUE) &c, &tag);
|
|
3617
|
+
if ( tag || c.rc != CA_ITER_OK ) {
|
|
3618
|
+
ca_iter_state_finish(first);
|
|
3619
|
+
if ( ca_is_object_type(r.copy) ) {
|
|
3620
|
+
ca_gc_release_buffer(r.copy->ptr);
|
|
3621
|
+
}
|
|
3622
|
+
ca_free(r.copy);
|
|
3623
|
+
if ( tag ) {
|
|
3624
|
+
rb_jump_tag(tag);
|
|
3625
|
+
}
|
|
3626
|
+
return c.rc;
|
|
3627
|
+
}
|
|
3628
|
+
first->flags |= CA_ITER_FLAG_OWNS_SRC;
|
|
3629
|
+
ca_iter_mark_walk_may_raise(first);
|
|
3630
|
+
return CA_ITER_OK;
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
int
|
|
3634
|
+
ca_iter_state_init_l2_paired (ca_iter_state *st,
|
|
3635
|
+
ca_iter_state *first,
|
|
3636
|
+
struct _CArray *src,
|
|
3637
|
+
ca_slab_policy_t policy,
|
|
3638
|
+
int8_t *axes,
|
|
3639
|
+
int8_t naxes,
|
|
3640
|
+
uint32_t flags)
|
|
3641
|
+
{
|
|
3642
|
+
ca_iter_call_t c;
|
|
3643
|
+
int tag = 0;
|
|
3644
|
+
if ( (flags & CA_KERNEL_WRITE) && first->src != NULL &&
|
|
3645
|
+
! (first->flags & CA_KERNEL_WRITE) &&
|
|
3646
|
+
policy == CA_SLAB_AXES && first->policy == CA_SLAB_AXES &&
|
|
3647
|
+
ca_shares_root(first->src, src) ) {
|
|
3648
|
+
int rc = ca_iter_reopen_on_copy(first);
|
|
3649
|
+
if ( rc != CA_ITER_OK ) {
|
|
3650
|
+
return rc;
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
c.st = st; c.src = src; c.policy = policy;
|
|
3654
|
+
c.axes = axes; c.naxes = naxes; c.flags = flags; c.rc = CA_ITER_OK;
|
|
3655
|
+
rb_protect(ca_iter_call_init_l2, (VALUE) &c, &tag);
|
|
3656
|
+
if ( tag ) {
|
|
3657
|
+
ca_iter_state_finish(st);
|
|
3658
|
+
ca_iter_state_finish(first);
|
|
3659
|
+
rb_jump_tag(tag);
|
|
3660
|
+
}
|
|
3661
|
+
if ( c.rc != CA_ITER_OK ) {
|
|
3662
|
+
ca_iter_state_finish(first);
|
|
3663
|
+
return c.rc;
|
|
3664
|
+
}
|
|
3665
|
+
ca_iter_mark_walk_may_raise(st);
|
|
3666
|
+
st->pair = first;
|
|
3667
|
+
first->pair = st;
|
|
3668
|
+
return c.rc;
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
typedef struct {
|
|
3672
|
+
int32_t n;
|
|
3673
|
+
ca_iter_state *states;
|
|
3674
|
+
} ca_iter_ensure_t;
|
|
3675
|
+
|
|
3676
|
+
/* Finishes the walks in reverse order of their slots, as nested windows
|
|
3677
|
+
close. ca_iter_state_finish only detaches and frees, so it cannot
|
|
3678
|
+
raise in turn. */
|
|
3679
|
+
static VALUE
|
|
3680
|
+
ca_iter_ensure_close (VALUE arg)
|
|
3681
|
+
{
|
|
3682
|
+
ca_iter_ensure_t *e = (ca_iter_ensure_t *) arg;
|
|
3683
|
+
for ( int32_t i = e->n - 1; i >= 0; i-- ) {
|
|
3684
|
+
ca_iter_state_finish(&e->states[i]);
|
|
3685
|
+
}
|
|
3686
|
+
return Qnil;
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3689
|
+
VALUE
|
|
3690
|
+
ca_iter_ensure (int32_t n, ca_iter_state *states,
|
|
3691
|
+
VALUE (*body)(VALUE), VALUE arg)
|
|
3692
|
+
{
|
|
3693
|
+
ca_iter_ensure_t e;
|
|
3694
|
+
if ( n < 0 ) {
|
|
3695
|
+
rb_raise(rb_eArgError, "ca_iter_ensure: negative state count %d", (int) n);
|
|
3696
|
+
}
|
|
3697
|
+
/* Unopened: finish returns at once on a state whose src is NULL, and
|
|
3698
|
+
init clears the whole state before it takes anything. */
|
|
3699
|
+
for ( int32_t i = 0; i < n; i++ ) {
|
|
3700
|
+
states[i].src = NULL;
|
|
3701
|
+
}
|
|
3702
|
+
e.n = n;
|
|
3703
|
+
e.states = states;
|
|
3704
|
+
return rb_ensure(body, arg, ca_iter_ensure_close, (VALUE) &e);
|
|
3705
|
+
}
|
|
3706
|
+
|
|
2999
3707
|
#ifdef CARRAY_DEV_BUILD
|
|
3000
3708
|
/* ============================================================
|
|
3001
3709
|
* smoke surface (dev-only, stripped in release)
|
|
@@ -4152,9 +4860,13 @@ rb_caf_slab_bench_sort_copy_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4152
4860
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, out);
|
|
4153
4861
|
slab_axes[0] = (int8_t) axis;
|
|
4154
4862
|
|
|
4863
|
+
if ( axis < 0 || axis >= src->ndim ) {
|
|
4864
|
+
rb_raise(rb_eArgError, "caf_slab_bench_sort_copy_f64: axis out of range");
|
|
4865
|
+
}
|
|
4155
4866
|
ca_size_t fiber_n = src->dim[axis];
|
|
4156
4867
|
ca_size_t bytes = sizeof(double);
|
|
4157
|
-
|
|
4868
|
+
volatile VALUE holder; /* the walk can raise while buf is held */
|
|
4869
|
+
char *buf = ALLOCV_N(char, holder, fiber_n * bytes);
|
|
4158
4870
|
|
|
4159
4871
|
CA_FOR_EACH_SLAB_INOUT(st_in, st_out, src, out,
|
|
4160
4872
|
slab_axes, 1,
|
|
@@ -4186,7 +4898,7 @@ rb_caf_slab_bench_sort_copy_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4186
4898
|
}
|
|
4187
4899
|
}
|
|
4188
4900
|
}
|
|
4189
|
-
|
|
4901
|
+
ALLOCV_END(holder);
|
|
4190
4902
|
return vout;
|
|
4191
4903
|
}
|
|
4192
4904
|
|
|
@@ -4236,7 +4948,8 @@ rb_caf_bench_per_fiber_xfer_sum_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4236
4948
|
}
|
|
4237
4949
|
|
|
4238
4950
|
/* Fiber-sized contig scratch. */
|
|
4239
|
-
|
|
4951
|
+
volatile VALUE holder;
|
|
4952
|
+
char *buf = ALLOCV_N(char, holder, fiber_n * src->bytes);
|
|
4240
4953
|
|
|
4241
4954
|
for ( ca_size_t f = 0; f < total_fibers; f++ ) {
|
|
4242
4955
|
/* Build region: counts = 1 on all non-axis, fiber_n on axis;
|
|
@@ -4264,7 +4977,7 @@ rb_caf_bench_per_fiber_xfer_sum_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4264
4977
|
}
|
|
4265
4978
|
}
|
|
4266
4979
|
|
|
4267
|
-
|
|
4980
|
+
ALLOCV_END(holder);
|
|
4268
4981
|
return rb_float_new(total);
|
|
4269
4982
|
}
|
|
4270
4983
|
|
|
@@ -4273,6 +4986,8 @@ rb_caf_bench_per_fiber_xfer_sum_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4273
4986
|
void
|
|
4274
4987
|
Init_ca_kernel_iterator (void)
|
|
4275
4988
|
{
|
|
4989
|
+
ki_kept_key = rb_ractor_local_storage_ptr_newkey(&ki_kept_type);
|
|
4990
|
+
|
|
4276
4991
|
#ifdef CARRAY_DEV_BUILD
|
|
4277
4992
|
/* ==== smoke surface registrations (dev-only, stripped in release) ====
|
|
4278
4993
|
* See PROPOSAL_SMOKE_DEV_BUILD_GATE.md. All `t1_smoke_*`, `caf_smoke_*`,
|