carray 3.0.2 → 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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- 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 +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- 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 +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -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 +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -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 +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- 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 +149 -27
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +102 -79
- data/ext/ca_sweep_engine.h +7 -20
- 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 +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- 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 +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- 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 +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- 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 +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- 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 +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- 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/factorize.rb +2 -2
- 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 +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/record_order.rb +208 -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 +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- 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 +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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_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 +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- 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 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -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 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- 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,6 +667,29 @@ 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. */
|
|
673
|
+
int
|
|
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
|
+
|
|
556
693
|
int
|
|
557
694
|
ca_iter_check_init (int rc)
|
|
558
695
|
{
|
|
@@ -562,7 +699,7 @@ ca_iter_check_init (int rc)
|
|
|
562
699
|
|
|
563
700
|
switch ( rc ) {
|
|
564
701
|
case CA_ITER_ERR_NOT_CHEAP:
|
|
565
|
-
why = "the
|
|
702
|
+
why = "the iterator does not recognise this kind of source";
|
|
566
703
|
break;
|
|
567
704
|
case CA_ITER_ERR_POLICY:
|
|
568
705
|
why = "the slab policy or the axes given do not apply to this source";
|
|
@@ -587,6 +724,92 @@ ca_iter_check_init (int rc)
|
|
|
587
724
|
return rc; /* not reached */
|
|
588
725
|
}
|
|
589
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
|
+
|
|
590
813
|
static int
|
|
591
814
|
ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
592
815
|
struct _CArray *src,
|
|
@@ -601,6 +824,7 @@ ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
|
601
824
|
times rather than whatever its stack frame happened to contain. */
|
|
602
825
|
if ( st == NULL ) return CA_ITER_ERR_FLAGS;
|
|
603
826
|
memset(st, 0, sizeof(*st));
|
|
827
|
+
if ( src == NULL ) return CA_ITER_ERR_FLAGS;
|
|
604
828
|
|
|
605
829
|
/* PROPOSAL_CAFACE_PHASE_2 F.2.6 + PROPOSAL_LAZY_MARKER_LIFT Phase 0:
|
|
606
830
|
storage-identical wrapper strip at entry (= same rationale as init_l2
|
|
@@ -634,7 +858,6 @@ ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
|
634
858
|
st->ndim = src->ndim;
|
|
635
859
|
st->flags = flags;
|
|
636
860
|
st->bytes = src->bytes;
|
|
637
|
-
st->axes = axes;
|
|
638
861
|
st->naxes = naxes;
|
|
639
862
|
|
|
640
863
|
st->slab_n = src->elements;
|
|
@@ -652,11 +875,7 @@ ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
|
652
875
|
Decouples kernel_iterator from per-view attach/sync lifecycle
|
|
653
876
|
and inherits xfer reform improvements (transform-fused, etc.)
|
|
654
877
|
automatically. */
|
|
655
|
-
st
|
|
656
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0 ? st->scratch_cap : 1);
|
|
657
|
-
if ( src->elements > 0 ) {
|
|
658
|
-
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
659
|
-
}
|
|
878
|
+
ki_gather_view(st, src, flags, 0);
|
|
660
879
|
st->alias_mode = CA_ITER_ALIAS_NONE; /* scratch-owned, no src.detach */
|
|
661
880
|
st->alias_ptr = st->scratch_ptr;
|
|
662
881
|
st->composed_strides[0] = src->bytes;
|
|
@@ -717,12 +936,11 @@ ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
|
717
936
|
if ( ca_func[src->obj_type].attach == ca_window_func.attach ) {
|
|
718
937
|
bound_fill = ((CAWindow *) src)->fill;
|
|
719
938
|
}
|
|
720
|
-
st->
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
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);
|
|
726
944
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
727
945
|
st->alias_ptr = st->scratch_ptr;
|
|
728
946
|
|
|
@@ -752,12 +970,7 @@ ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
|
752
970
|
to ca_stride_func_copy_data which composes leaf strides up to
|
|
753
971
|
the root entity and gathers in one pass — no per-intermediate
|
|
754
972
|
view materialise. */
|
|
755
|
-
|
|
756
|
-
st->scratch_cap = cap;
|
|
757
|
-
st->scratch_ptr = xmalloc(cap > 0 ? cap : 1);
|
|
758
|
-
if ( cap > 0 ) {
|
|
759
|
-
ca_copy_data(src, st->scratch_ptr);
|
|
760
|
-
}
|
|
973
|
+
ki_gather_view(st, src, flags, 1);
|
|
761
974
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
762
975
|
st->alias_ptr = st->scratch_ptr;
|
|
763
976
|
}
|
|
@@ -794,6 +1007,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
794
1007
|
times rather than whatever its stack frame happened to contain. */
|
|
795
1008
|
if ( st == NULL ) return CA_ITER_ERR_FLAGS;
|
|
796
1009
|
memset(st, 0, sizeof(*st));
|
|
1010
|
+
if ( src == NULL ) return CA_ITER_ERR_FLAGS;
|
|
797
1011
|
|
|
798
1012
|
/* PROPOSAL_CAFACE_PHASE_2 F.2.6 (= MEMO §3.5 kernel_iterator entry strip)
|
|
799
1013
|
+ PROPOSAL_LAZY_MARKER_LIFT Phase 0.
|
|
@@ -862,7 +1076,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
862
1076
|
and use per-fiber ca_xfer_stride which routes to the view's
|
|
863
1077
|
X.1 OOB-fused per-region fast path. */
|
|
864
1078
|
if ( (flags & CA_KERNEL_FIBER_CONTIG) && naxes == 1
|
|
865
|
-
&& raw_ndim == src->ndim ) {
|
|
1079
|
+
&& raw_ndim == src->ndim && ca_fast_paths_enabled() ) {
|
|
866
1080
|
int8_t fiber_ax = axes[0];
|
|
867
1081
|
ca_size_t row_byte_strides[CA_RANK_MAX];
|
|
868
1082
|
{
|
|
@@ -882,7 +1096,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
882
1096
|
st->ndim = src->ndim;
|
|
883
1097
|
st->flags = flags;
|
|
884
1098
|
st->bytes = src->bytes;
|
|
885
|
-
st->axes = axes;
|
|
886
1099
|
st->naxes = naxes;
|
|
887
1100
|
|
|
888
1101
|
st->alias_mode = CA_ITER_ALIAS_PER_FIBER_FUSED;
|
|
@@ -956,13 +1169,24 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
956
1169
|
return CA_ITER_ERR_POLICY;
|
|
957
1170
|
}
|
|
958
1171
|
int slab_has_non_stride = 0;
|
|
1172
|
+
int slab_has_index = 0;
|
|
959
1173
|
for ( k = 0; k < src->ndim; k++ ) {
|
|
960
1174
|
if ( in_slab[k] && raw_descs[k].kind != CA_AXIS_KIND_STRIDE ) {
|
|
961
1175
|
slab_has_non_stride = 1;
|
|
962
|
-
|
|
1176
|
+
if ( raw_descs[k].kind == CA_AXIS_KIND_INDEX ) {
|
|
1177
|
+
slab_has_index = 1;
|
|
1178
|
+
}
|
|
963
1179
|
}
|
|
964
1180
|
}
|
|
965
|
-
|
|
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 ) {
|
|
966
1190
|
/* C.1 scope: READ-only. WRITE = future sub-step (C.1c). */
|
|
967
1191
|
if ( flags & CA_KERNEL_WRITE ) {
|
|
968
1192
|
return CA_ITER_ERR_FLAGS;
|
|
@@ -975,7 +1199,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
975
1199
|
st->ndim = src->ndim;
|
|
976
1200
|
st->flags = flags;
|
|
977
1201
|
st->bytes = src->bytes;
|
|
978
|
-
st->axes = axes;
|
|
979
1202
|
st->naxes = naxes;
|
|
980
1203
|
|
|
981
1204
|
CArray *parent = CAVIEW(src)->parent;
|
|
@@ -1075,7 +1298,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1075
1298
|
full-view materialise). */
|
|
1076
1299
|
ca_size_t slab_bytes = st->slab_elements * src->bytes;
|
|
1077
1300
|
st->scratch_cap = slab_bytes > 0 ? slab_bytes : 1;
|
|
1078
|
-
st->scratch_ptr = (char *)
|
|
1301
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
1079
1302
|
st->alias_ptr = st->scratch_ptr; /* refilled per slab in next_slab_axes */
|
|
1080
1303
|
|
|
1081
1304
|
/* Specialisation (B-1b, C.1b): if innermost slab axis is STRIDE
|
|
@@ -1083,7 +1306,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1083
1306
|
manual gather path (= outer + non-innermost-slab hoist,
|
|
1084
1307
|
inner pure STRIDE linear memcpy). Else (innermost INDEX /
|
|
1085
1308
|
SHIFT-anywhere): use the engine fallback (A). */
|
|
1086
|
-
int specialised_eligible = (sp > 0);
|
|
1309
|
+
int specialised_eligible = (sp > 0) && ca_fast_paths_enabled();
|
|
1087
1310
|
if ( specialised_eligible ) {
|
|
1088
1311
|
int8_t inner_view_ax = st->slab_axes_buf[sp - 1];
|
|
1089
1312
|
if ( raw_descs[inner_view_ax].kind != CA_AXIS_KIND_STRIDE ) {
|
|
@@ -1135,7 +1358,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1135
1358
|
}
|
|
1136
1359
|
}
|
|
1137
1360
|
|
|
1138
|
-
if ( outer_has_shift ) {
|
|
1361
|
+
if ( outer_has_shift || whole_view ) {
|
|
1139
1362
|
st->src = src;
|
|
1140
1363
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
1141
1364
|
st->level = 2;
|
|
@@ -1143,7 +1366,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1143
1366
|
st->ndim = src->ndim;
|
|
1144
1367
|
st->flags = flags;
|
|
1145
1368
|
st->bytes = src->bytes;
|
|
1146
|
-
st->axes = axes;
|
|
1147
1369
|
st->naxes = naxes;
|
|
1148
1370
|
|
|
1149
1371
|
CArray *parent = CAVIEW(src)->parent;
|
|
@@ -1157,10 +1379,12 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1157
1379
|
bound_fill = ((CAWindow *) src)->fill;
|
|
1158
1380
|
}
|
|
1159
1381
|
st->scratch_cap = src->elements * src->bytes;
|
|
1160
|
-
st->scratch_ptr =
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
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;
|
|
1164
1388
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
1165
1389
|
st->alias_ptr = st->scratch_ptr;
|
|
1166
1390
|
|
|
@@ -1236,7 +1460,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1236
1460
|
st->ndim = src->ndim;
|
|
1237
1461
|
st->flags = flags;
|
|
1238
1462
|
st->bytes = src->bytes;
|
|
1239
|
-
st->axes = axes;
|
|
1240
1463
|
st->naxes = naxes;
|
|
1241
1464
|
|
|
1242
1465
|
/* Parent row-major byte strides for offset computation. */
|
|
@@ -1383,7 +1606,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1383
1606
|
st->ndim = src->ndim;
|
|
1384
1607
|
st->flags = flags;
|
|
1385
1608
|
st->bytes = src->bytes;
|
|
1386
|
-
st->axes = axes;
|
|
1387
1609
|
st->naxes = naxes;
|
|
1388
1610
|
|
|
1389
1611
|
/* Row-major byte / element strides on the attached view buffer.
|
|
@@ -1429,7 +1651,8 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1429
1651
|
if ( ca_func[src->obj_type].attach == ca_stack_func.attach
|
|
1430
1652
|
&& !ca_has_mask(src)
|
|
1431
1653
|
&& !(flags & CA_KERNEL_WRITE)
|
|
1432
|
-
&& naxes == 1 && axes[0] == ((CAStack *) src)->k_axis
|
|
1654
|
+
&& naxes == 1 && axes[0] == ((CAStack *) src)->k_axis
|
|
1655
|
+
&& ca_fast_paths_enabled() ) {
|
|
1433
1656
|
CAStack *stack = (CAStack *) src;
|
|
1434
1657
|
int8_t parent_ndim = src->ndim - 1;
|
|
1435
1658
|
int8_t sp = 0, op = 0;
|
|
@@ -1478,12 +1701,15 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1478
1701
|
guarantees uniform shape (MEMO §3.2) so one set of parent
|
|
1479
1702
|
native byte strides covers all K (= parents[0]->dim is
|
|
1480
1703
|
canonical). */
|
|
1481
|
-
|
|
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;
|
|
1482
1707
|
st->stack_parent_ptrs =
|
|
1483
1708
|
(char **) xmalloc(stack->n_parents * sizeof(char *));
|
|
1484
1709
|
for ( int32_t kk = 0; kk < stack->n_parents; kk++ ) {
|
|
1485
|
-
ca_attach(stack->parents[kk]);
|
|
1710
|
+
ca_attach(stack->parents[kk]); /* window: finish detaches the counted parents */
|
|
1486
1711
|
st->stack_parent_ptrs[kk] = (char *) stack->parents[kk]->ptr;
|
|
1712
|
+
st->stack_n_parents = kk + 1;
|
|
1487
1713
|
}
|
|
1488
1714
|
{
|
|
1489
1715
|
ca_size_t s = src->bytes;
|
|
@@ -1495,7 +1721,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1495
1721
|
|
|
1496
1722
|
/* Slab-sized scratch (= K * bytes for slab_axes == [0]). */
|
|
1497
1723
|
st->scratch_cap = (ca_size_t) st->slab_elements * src->bytes;
|
|
1498
|
-
st->scratch_ptr = (char *)
|
|
1724
|
+
st->scratch_ptr = (char *) ki_data_alloc(src->data_type, st->scratch_cap);
|
|
1499
1725
|
|
|
1500
1726
|
/* Tile cache (pilot/castack-axis0-loop-interchange): refill TILE
|
|
1501
1727
|
fibers per K parent reads, serve next TILE-1 fibers from L1d.
|
|
@@ -1510,7 +1736,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1510
1736
|
st->stack_tile_cap = tile;
|
|
1511
1737
|
st->stack_tile_pos = 0;
|
|
1512
1738
|
st->stack_tile_have = 0; /* force refill on first call */
|
|
1513
|
-
st->stack_tile_cache = (char *)
|
|
1739
|
+
st->stack_tile_cache = (char *) ki_data_alloc(src->data_type, K * tile * bytes);
|
|
1514
1740
|
}
|
|
1515
1741
|
|
|
1516
1742
|
st->alias_mode = CA_ITER_ALIAS_STACK;
|
|
@@ -1545,7 +1771,8 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1545
1771
|
counterpart. */
|
|
1546
1772
|
if ( ca_func[src->obj_type].attach == ca_stack_func.attach
|
|
1547
1773
|
&& !(flags & CA_KERNEL_WRITE)
|
|
1548
|
-
&& naxes >= 1 && !in_slab[((CAStack *) src)->k_axis]
|
|
1774
|
+
&& naxes >= 1 && !in_slab[((CAStack *) src)->k_axis]
|
|
1775
|
+
&& ca_fast_paths_enabled() ) {
|
|
1549
1776
|
CAStack *stack = (CAStack *) src;
|
|
1550
1777
|
int8_t k_axis = stack->k_axis;
|
|
1551
1778
|
int8_t parent_ndim = src->ndim - 1;
|
|
@@ -1626,25 +1853,42 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1626
1853
|
|
|
1627
1854
|
/* Attach K parents + cache ptr aliases. Symmetric with rev3
|
|
1628
1855
|
Case B; for entity parents attach is O(1). */
|
|
1629
|
-
|
|
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;
|
|
1630
1859
|
st->stack_parent_ptrs =
|
|
1631
1860
|
(char **) xmalloc(stack->n_parents * sizeof(char *));
|
|
1632
1861
|
for ( int32_t kk = 0; kk < stack->n_parents; kk++ ) {
|
|
1633
|
-
ca_attach(stack->parents[kk]);
|
|
1862
|
+
ca_attach(stack->parents[kk]); /* window: finish detaches the counted parents */
|
|
1634
1863
|
st->stack_parent_ptrs[kk] = (char *) stack->parents[kk]->ptr;
|
|
1864
|
+
st->stack_n_parents = kk + 1;
|
|
1635
1865
|
}
|
|
1636
1866
|
|
|
1637
1867
|
/* If CAStack carries mask (= horizontal propagation already
|
|
1638
|
-
applied at create_mask),
|
|
1639
|
-
|
|
1640
|
-
|
|
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. */
|
|
1641
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. */
|
|
1642
1880
|
st->stack_parent_mask_ptrs =
|
|
1643
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 *));
|
|
1644
1884
|
for ( int32_t kk = 0; kk < stack->n_parents; kk++ ) {
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
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);
|
|
1648
1892
|
}
|
|
1649
1893
|
} else {
|
|
1650
1894
|
st->stack_parent_mask_ptrs = NULL;
|
|
@@ -1664,7 +1908,8 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1664
1908
|
is called on demand in next_slab_axes). Predicate is stubbed
|
|
1665
1909
|
in F.6.1 (returns 0); F.6.2+ enables specific source kinds. */
|
|
1666
1910
|
int per_fiber_fused = 0;
|
|
1667
|
-
if ( (flags & CA_KERNEL_FIBER_CONTIG) && naxes == 1
|
|
1911
|
+
if ( (flags & CA_KERNEL_FIBER_CONTIG) && naxes == 1
|
|
1912
|
+
&& ca_fast_paths_enabled() ) {
|
|
1668
1913
|
int8_t fiber_ax = axes[0];
|
|
1669
1914
|
ca_size_t fiber_ax_stride = row_byte_strides[fiber_ax];
|
|
1670
1915
|
if ( ca_iter_should_per_fiber_fused(src, src_kind, fiber_ax,
|
|
@@ -1682,11 +1927,7 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1682
1927
|
if ( !per_fiber_fused ) {
|
|
1683
1928
|
/* 2026-05-31 refactor: iter-owns scratch via ca_xfer_all (was
|
|
1684
1929
|
ca_attach(src) + alias src->ptr). */
|
|
1685
|
-
st
|
|
1686
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0 ? st->scratch_cap : 1);
|
|
1687
|
-
if ( src->elements > 0 ) {
|
|
1688
|
-
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
1689
|
-
}
|
|
1930
|
+
ki_gather_view(st, src, flags, 0);
|
|
1690
1931
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
1691
1932
|
st->alias_ptr = st->scratch_ptr;
|
|
1692
1933
|
}
|
|
@@ -1772,14 +2013,9 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1772
2013
|
st->ndim = 1; /* logical 1-D L2 layout */
|
|
1773
2014
|
st->flags = flags;
|
|
1774
2015
|
st->bytes = src->bytes;
|
|
1775
|
-
st->axes = axes;
|
|
1776
2016
|
st->naxes = naxes;
|
|
1777
2017
|
|
|
1778
|
-
st
|
|
1779
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0 ? st->scratch_cap : 1);
|
|
1780
|
-
if ( src->elements > 0 ) {
|
|
1781
|
-
ca_xfer_all(src, st->scratch_ptr, CA_XFER_GET);
|
|
1782
|
-
}
|
|
2018
|
+
ki_gather_view(st, src, flags, 0);
|
|
1783
2019
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
1784
2020
|
st->alias_ptr = st->scratch_ptr;
|
|
1785
2021
|
st->composed_strides[0] = src->bytes;
|
|
@@ -1823,7 +2059,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1823
2059
|
st->ndim = nd;
|
|
1824
2060
|
st->flags = flags;
|
|
1825
2061
|
st->bytes = src->bytes;
|
|
1826
|
-
st->axes = axes;
|
|
1827
2062
|
st->naxes = naxes;
|
|
1828
2063
|
|
|
1829
2064
|
/* Persist descs / parent_axis_dims in state; build parent row-major
|
|
@@ -1913,7 +2148,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1913
2148
|
st->ndim = src->ndim;
|
|
1914
2149
|
st->flags = flags;
|
|
1915
2150
|
st->bytes = src->bytes;
|
|
1916
|
-
st->axes = axes;
|
|
1917
2151
|
st->naxes = naxes;
|
|
1918
2152
|
|
|
1919
2153
|
memcpy(st->parent_axis_dims, raw_pdims, raw_ndim * sizeof(ca_size_t));
|
|
@@ -1940,12 +2174,11 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1940
2174
|
if ( ca_func[src->obj_type].attach == ca_window_func.attach ) {
|
|
1941
2175
|
bound_fill = ((CAWindow *) src)->fill;
|
|
1942
2176
|
}
|
|
1943
|
-
st->
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
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);
|
|
1949
2182
|
|
|
1950
2183
|
/* Lay out as a single 1-D L2 strided slab: ptr = scratch,
|
|
1951
2184
|
n = total_elements, stride = bytes. next_slab_strided reads
|
|
@@ -1986,7 +2219,6 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
1986
2219
|
st->ndim = src->ndim;
|
|
1987
2220
|
st->flags = flags;
|
|
1988
2221
|
st->bytes = src->bytes;
|
|
1989
|
-
st->axes = axes;
|
|
1990
2222
|
st->naxes = naxes;
|
|
1991
2223
|
|
|
1992
2224
|
/* Compute composed strides + base. For entity / CAStride contig we
|
|
@@ -2102,18 +2334,13 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
2102
2334
|
}
|
|
2103
2335
|
|
|
2104
2336
|
if ( use_strided ) {
|
|
2105
|
-
st->root
|
|
2106
|
-
|
|
2337
|
+
ca_attach(root); /* window: finish detaches st->root */
|
|
2338
|
+
st->root = root; /* recorded once attached */
|
|
2107
2339
|
st->alias_mode = CA_ITER_ALIAS_STRIDED;
|
|
2108
2340
|
st->alias_ptr = (char *) root->ptr;
|
|
2109
2341
|
} else if ( use_view_scratch ) {
|
|
2110
2342
|
st->root = NULL;
|
|
2111
|
-
st
|
|
2112
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0
|
|
2113
|
-
? st->scratch_cap : 1);
|
|
2114
|
-
if ( src->elements > 0 ) {
|
|
2115
|
-
ca_copy_data(src, st->scratch_ptr);
|
|
2116
|
-
}
|
|
2343
|
+
ki_gather_view(st, src, flags, 1);
|
|
2117
2344
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
2118
2345
|
st->alias_ptr = st->scratch_ptr;
|
|
2119
2346
|
} else {
|
|
@@ -2156,18 +2383,13 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
2156
2383
|
st->chunk_size = st->slab_n;
|
|
2157
2384
|
|
|
2158
2385
|
if ( use_strided ) {
|
|
2159
|
-
st->root
|
|
2160
|
-
|
|
2386
|
+
ca_attach(root); /* window: finish detaches st->root */
|
|
2387
|
+
st->root = root; /* recorded once attached */
|
|
2161
2388
|
st->alias_mode = CA_ITER_ALIAS_STRIDED;
|
|
2162
2389
|
st->alias_ptr = (char *) root->ptr;
|
|
2163
2390
|
} else if ( use_view_scratch ) {
|
|
2164
2391
|
st->root = NULL;
|
|
2165
|
-
st
|
|
2166
|
-
st->scratch_ptr = (char *) xmalloc(st->scratch_cap > 0
|
|
2167
|
-
? st->scratch_cap : 1);
|
|
2168
|
-
if ( src->elements > 0 ) {
|
|
2169
|
-
ca_copy_data(src, st->scratch_ptr);
|
|
2170
|
-
}
|
|
2392
|
+
ki_gather_view(st, src, flags, 1);
|
|
2171
2393
|
st->alias_mode = CA_ITER_ALIAS_NONE;
|
|
2172
2394
|
st->alias_ptr = st->scratch_ptr;
|
|
2173
2395
|
} else {
|
|
@@ -2176,6 +2398,17 @@ ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
|
2176
2398
|
st->alias_mode = CA_ITER_ALIAS_CONTIG;
|
|
2177
2399
|
st->alias_ptr = (char *) src->ptr;
|
|
2178
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
|
+
}
|
|
2179
2412
|
return CA_ITER_OK;
|
|
2180
2413
|
}
|
|
2181
2414
|
|
|
@@ -2271,6 +2504,55 @@ ca_iter_state_next_slab_strided_unprotected (ca_iter_state *st,
|
|
|
2271
2504
|
return 1;
|
|
2272
2505
|
}
|
|
2273
2506
|
|
|
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
|
+
|
|
2274
2556
|
static int
|
|
2275
2557
|
ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
2276
2558
|
char **out_ptr,
|
|
@@ -2370,7 +2652,11 @@ ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
|
2370
2652
|
}
|
|
2371
2653
|
|
|
2372
2654
|
if ( out_ptr ) *out_ptr = st->scratch_ptr;
|
|
2373
|
-
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
|
+
}
|
|
2374
2660
|
|
|
2375
2661
|
st->slabs_emitted += 1;
|
|
2376
2662
|
for ( int8_t m = st->outer_ndim - 1; m >= 0; m-- ) {
|
|
@@ -2406,11 +2692,15 @@ ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
|
2406
2692
|
mask_off += st->outer_idx[m] * st->stack_parent_mask_strides[parent_ax];
|
|
2407
2693
|
}
|
|
2408
2694
|
|
|
2409
|
-
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
|
+
}
|
|
2410
2699
|
if ( out_mask ) {
|
|
2411
|
-
*out_mask = st
|
|
2412
|
-
|
|
2413
|
-
|
|
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]);
|
|
2414
2704
|
}
|
|
2415
2705
|
|
|
2416
2706
|
st->slabs_emitted += 1;
|
|
@@ -2561,7 +2851,11 @@ ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
|
2561
2851
|
}
|
|
2562
2852
|
|
|
2563
2853
|
if ( out_ptr ) *out_ptr = st->scratch_ptr;
|
|
2564
|
-
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
|
+
}
|
|
2565
2859
|
|
|
2566
2860
|
st->slabs_emitted += 1;
|
|
2567
2861
|
/* Advance outer_idx row-major (innermost outer axis ticks first). */
|
|
@@ -2622,8 +2916,8 @@ ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
|
2622
2916
|
ca_size_t counts[CA_RANK_MAX];
|
|
2623
2917
|
|
|
2624
2918
|
if ( st->fiber_data_scratch_cap < need ) {
|
|
2625
|
-
if ( st->fiber_data_scratch )
|
|
2626
|
-
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);
|
|
2627
2921
|
st->fiber_data_scratch_cap = need;
|
|
2628
2922
|
}
|
|
2629
2923
|
|
|
@@ -2701,72 +2995,14 @@ ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
|
2701
2995
|
Capture last_data_off BEFORE the outer_idx advance below; sync_slab
|
|
2702
2996
|
consumes it for WRITE scatter. See header field doc + PROPOSAL
|
|
2703
2997
|
§4.3.2 hazard comment in sync_slab. */
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
st->last_data_off = data_off;
|
|
2713
|
-
|
|
2714
|
-
if ( data_step == (ca_size_t) bytes ) {
|
|
2715
|
-
/* Fast path: fiber is already contig (= innermost-axis or stride
|
|
2716
|
-
coincidentally == bytes). No gather needed. */
|
|
2717
|
-
yield_ptr = src_data;
|
|
2718
|
-
} else {
|
|
2719
|
-
/* Per-fiber gather via the typed-store inline helper
|
|
2720
|
-
(ca_iter_substrate.h). For bytes in {1,2,4,8} this uses a
|
|
2721
|
-
compiler-vectorize-friendly `*dp++ = v; sp += step` loop;
|
|
2722
|
-
other sizes fall back to per-element memcpy. Lazy-alloc
|
|
2723
|
-
scratch sized to max fiber bytes (slab_dims[0] constant per
|
|
2724
|
-
walk → single alloc in practice). */
|
|
2725
|
-
ca_size_t need = n * bytes;
|
|
2726
|
-
if ( st->fiber_data_scratch_cap < need ) {
|
|
2727
|
-
if ( st->fiber_data_scratch ) xfree(st->fiber_data_scratch);
|
|
2728
|
-
st->fiber_data_scratch = (char *) xmalloc(need);
|
|
2729
|
-
st->fiber_data_scratch_cap = need;
|
|
2730
|
-
}
|
|
2731
|
-
ca_stride_gather_run(st->fiber_data_scratch, src_data,
|
|
2732
|
-
bytes, n, data_step);
|
|
2733
|
-
yield_ptr = st->fiber_data_scratch;
|
|
2734
|
-
}
|
|
2735
|
-
} else {
|
|
2736
|
-
yield_ptr = st->alias_ptr + data_off;
|
|
2737
|
-
}
|
|
2738
|
-
|
|
2739
|
-
/* PROPOSAL_FIBER_DELIVERY F.1b: per-fiber contig mask delivery.
|
|
2740
|
-
Symmetric to F.1a data path above. When the source has a mask
|
|
2741
|
-
(= alias_mask != NULL) and the fiber's mask is not innermost-contig
|
|
2742
|
-
(= slab_mask_strides[0] != 1), gather it into fiber_mask_scratch
|
|
2743
|
-
so the author can write m[i] without stride math. Mask is
|
|
2744
|
-
read-only here (= L2 WRITE never propagates to mask state), so no
|
|
2745
|
-
scatter is needed in sync_slab. */
|
|
2746
|
-
boolean8_t *yield_mask;
|
|
2747
|
-
if ( (st->flags & CA_KERNEL_FIBER_CONTIG)
|
|
2748
|
-
&& st->naxes == 1 && st->slab_ndim == 1
|
|
2749
|
-
&& st->alias_mask != NULL ) {
|
|
2750
|
-
ca_size_t n = st->slab_dims[0];
|
|
2751
|
-
ca_size_t mask_step = st->slab_mask_strides[0];
|
|
2752
|
-
boolean8_t *src_mask = st->alias_mask + mask_off;
|
|
2753
|
-
|
|
2754
|
-
if ( mask_step == 1 ) {
|
|
2755
|
-
yield_mask = src_mask;
|
|
2756
|
-
} else {
|
|
2757
|
-
if ( st->fiber_mask_scratch_cap < (ca_size_t) n ) {
|
|
2758
|
-
if ( st->fiber_mask_scratch ) xfree(st->fiber_mask_scratch);
|
|
2759
|
-
st->fiber_mask_scratch = (boolean8_t *) xmalloc(n);
|
|
2760
|
-
st->fiber_mask_scratch_cap = n;
|
|
2761
|
-
}
|
|
2762
|
-
for ( ca_size_t i = 0; i < n; i++ ) {
|
|
2763
|
-
st->fiber_mask_scratch[i] = src_mask[i * mask_step];
|
|
2764
|
-
}
|
|
2765
|
-
yield_mask = st->fiber_mask_scratch;
|
|
2766
|
-
}
|
|
2767
|
-
} else {
|
|
2768
|
-
yield_mask = st->alias_mask ? st->alias_mask + mask_off : NULL;
|
|
2769
|
-
}
|
|
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]);
|
|
2770
3006
|
|
|
2771
3007
|
if ( out_ptr ) *out_ptr = yield_ptr;
|
|
2772
3008
|
if ( out_mask ) *out_mask = yield_mask;
|
|
@@ -2884,12 +3120,9 @@ ca_iter_state_sync_slab_unprotected (ca_iter_state *st)
|
|
|
2884
3120
|
below early-returns. */
|
|
2885
3121
|
}
|
|
2886
3122
|
|
|
2887
|
-
/* SRC_ATTACH path
|
|
2888
|
-
|
|
2889
|
-
which
|
|
2890
|
-
(cast back), CAByteSwap (swap back), CABitfield/CABitarray (bit
|
|
2891
|
-
pack back), CAReduce (broadcast across reduce window). Inherits
|
|
2892
|
-
transform-fused / partial materialise / etc. automatically.
|
|
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.
|
|
2893
3126
|
|
|
2894
3127
|
This has to stay below the two per-fiber blocks: consulting
|
|
2895
3128
|
src_kind first would push back the whole-view buffer while the
|
|
@@ -2897,9 +3130,7 @@ ca_iter_state_sync_slab_unprotected (ca_iter_state *st)
|
|
|
2897
3130
|
fiber_data_scratch, and would push back a NULL one for
|
|
2898
3131
|
PER_FIBER_FUSED, which owns no whole-view buffer at all. */
|
|
2899
3132
|
if ( st->src_kind == CA_ITER_SRC_ATTACH ) {
|
|
2900
|
-
|
|
2901
|
-
ca_xfer_all(st->src, st->scratch_ptr, CA_XFER_PUT);
|
|
2902
|
-
}
|
|
3133
|
+
ki_scratch_push_changed(st);
|
|
2903
3134
|
st->write_dirty = 0;
|
|
2904
3135
|
return;
|
|
2905
3136
|
}
|
|
@@ -2918,11 +3149,10 @@ ca_iter_state_sync_slab_unprotected (ca_iter_state *st)
|
|
|
2918
3149
|
case CA_ITER_SRC_CASTRIDE:
|
|
2919
3150
|
/* Two producers of CAStride + scratch: L1 non-contig, and the L2
|
|
2920
3151
|
non-entity-root path (init_l2's use_view_scratch). Both gathered
|
|
2921
|
-
with ca_copy_data into a view row-major buffer
|
|
2922
|
-
back the
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
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);
|
|
2926
3156
|
break;
|
|
2927
3157
|
|
|
2928
3158
|
case CA_ITER_SRC_DESCRIPTOR: {
|
|
@@ -2955,12 +3185,17 @@ ca_iter_state_sync_slab_unprotected (ca_iter_state *st)
|
|
|
2955
3185
|
st->write_dirty = 0;
|
|
2956
3186
|
}
|
|
2957
3187
|
|
|
3188
|
+
static VALUE ca_iter_finish_sync (VALUE arg);
|
|
3189
|
+
|
|
2958
3190
|
void
|
|
2959
3191
|
ca_iter_state_finish (ca_iter_state *st)
|
|
2960
3192
|
{
|
|
2961
3193
|
if ( st == NULL || st->src == NULL ) {
|
|
2962
3194
|
return;
|
|
2963
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;
|
|
2964
3199
|
/* composed_strides is inline — no free needed. outer_idx is heap
|
|
2965
3200
|
for L2 multi-d sources (NULL on L1 paths and on L2 0/1-d). */
|
|
2966
3201
|
if ( st->outer_idx ) {
|
|
@@ -2977,7 +3212,7 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2977
3212
|
ca_detach.
|
|
2978
3213
|
- else (alias paths): src was attached at init, detach. */
|
|
2979
3214
|
if ( st->scratch_ptr ) {
|
|
2980
|
-
|
|
3215
|
+
ki_data_free(st->scratch_ptr, st->scratch_cap);
|
|
2981
3216
|
st->scratch_ptr = NULL;
|
|
2982
3217
|
st->scratch_cap = 0;
|
|
2983
3218
|
}
|
|
@@ -2987,7 +3222,7 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2987
3222
|
}
|
|
2988
3223
|
/* PROPOSAL_FIBER_DELIVERY F.1a/F.1b: per-fiber scratch lifecycle. */
|
|
2989
3224
|
if ( st->fiber_data_scratch ) {
|
|
2990
|
-
|
|
3225
|
+
ki_data_free(st->fiber_data_scratch, st->fiber_data_scratch_cap);
|
|
2991
3226
|
st->fiber_data_scratch = NULL;
|
|
2992
3227
|
st->fiber_data_scratch_cap = 0;
|
|
2993
3228
|
}
|
|
@@ -3009,24 +3244,34 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
3009
3244
|
}
|
|
3010
3245
|
/* pilot/castack-axis0-loop-interchange: free tile cache. */
|
|
3011
3246
|
if ( st->stack_tile_cache ) {
|
|
3012
|
-
|
|
3247
|
+
ki_data_free(st->stack_tile_cache, 0);
|
|
3013
3248
|
st->stack_tile_cache = NULL;
|
|
3014
3249
|
st->stack_tile_cap = 0;
|
|
3015
3250
|
st->stack_tile_pos = 0;
|
|
3016
3251
|
st->stack_tile_have = 0;
|
|
3017
3252
|
}
|
|
3018
3253
|
if ( st->stack_parent_mask_ptrs ) {
|
|
3019
|
-
CAStack *stack = (CAStack *) st->src;
|
|
3020
3254
|
for ( int32_t kk = 0; kk < st->stack_n_parents; kk++ ) {
|
|
3021
|
-
|
|
3255
|
+
if ( st->stack_parent_mask_ptrs[kk] ) {
|
|
3256
|
+
xfree(st->stack_parent_mask_ptrs[kk]);
|
|
3257
|
+
}
|
|
3022
3258
|
}
|
|
3023
3259
|
xfree(st->stack_parent_mask_ptrs);
|
|
3024
3260
|
st->stack_parent_mask_ptrs = NULL;
|
|
3025
3261
|
}
|
|
3026
3262
|
st->stack_n_parents = 0;
|
|
3027
3263
|
if ( st->root ) {
|
|
3028
|
-
|
|
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;
|
|
3029
3268
|
st->root = NULL;
|
|
3269
|
+
if ( st->flags & CA_KERNEL_WRITE ) {
|
|
3270
|
+
ca_sync_detach(root);
|
|
3271
|
+
}
|
|
3272
|
+
else {
|
|
3273
|
+
ca_detach(root);
|
|
3274
|
+
}
|
|
3030
3275
|
} else if ( st->alias_mode == CA_ITER_ALIAS_CONTIG
|
|
3031
3276
|
|| st->alias_mode == CA_ITER_ALIAS_STRIDED ) {
|
|
3032
3277
|
/* alias path (CONTIG/STRIDED for CAStride family): we attached
|
|
@@ -3036,10 +3281,35 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
3036
3281
|
NONE, scratch_ptr xfree'd above), so no src.detach needed. */
|
|
3037
3282
|
ca_detach(st->src);
|
|
3038
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
|
+
}
|
|
3039
3292
|
st->src = NULL;
|
|
3040
3293
|
st->alias_ptr = NULL;
|
|
3041
3294
|
}
|
|
3042
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
|
+
|
|
3043
3313
|
/* ---- Raise-safe entry points ----------------------------------------
|
|
3044
3314
|
*
|
|
3045
3315
|
* A walk reads its source, and a source that converts as it is read (a
|
|
@@ -3053,10 +3323,9 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
3053
3323
|
* and ca_iter_state_finish is idempotent (it clears st->src), so the
|
|
3054
3324
|
* caller's own finish after an ordinary walk stays correct.
|
|
3055
3325
|
*
|
|
3056
|
-
* Not covered: a kernel body that raises. It runs in the caller's
|
|
3326
|
+
* Not covered here: a kernel body that raises. It runs in the caller's
|
|
3057
3327
|
* frame, between two calls of these functions, where the engine has no
|
|
3058
|
-
* hold on it.
|
|
3059
|
-
* to watch.
|
|
3328
|
+
* hold on it. A body that can raise runs through ca_iter_ensure below.
|
|
3060
3329
|
*
|
|
3061
3330
|
* init runs protected always -- once per walk, next to a materialise.
|
|
3062
3331
|
* next_slab / sync_slab are called once per slab, in walks whose whole
|
|
@@ -3072,6 +3341,7 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
3072
3341
|
header. */
|
|
3073
3342
|
#define CA_ITER_FLAG_WALK_MAY_RAISE 0x80000000u
|
|
3074
3343
|
|
|
3344
|
+
|
|
3075
3345
|
typedef struct {
|
|
3076
3346
|
ca_iter_state *st;
|
|
3077
3347
|
CArray *src;
|
|
@@ -3105,13 +3375,20 @@ ca_iter_mark_walk_may_raise (ca_iter_state *st)
|
|
|
3105
3375
|
}
|
|
3106
3376
|
}
|
|
3107
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. */
|
|
3108
3381
|
static void
|
|
3109
3382
|
ca_iter_protect (ca_iter_state *st, VALUE (*body)(VALUE), VALUE arg)
|
|
3110
3383
|
{
|
|
3111
3384
|
int tag = 0;
|
|
3112
3385
|
rb_protect(body, arg, &tag);
|
|
3113
3386
|
if ( tag ) {
|
|
3387
|
+
ca_iter_state *pair = (ca_iter_state *) st->pair;
|
|
3114
3388
|
ca_iter_state_finish(st);
|
|
3389
|
+
if ( pair != NULL ) {
|
|
3390
|
+
ca_iter_state_finish(pair);
|
|
3391
|
+
}
|
|
3115
3392
|
rb_jump_tag(tag);
|
|
3116
3393
|
}
|
|
3117
3394
|
}
|
|
@@ -3181,6 +3458,9 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
3181
3458
|
ca_iter_call_t c;
|
|
3182
3459
|
c.st = st; c.src = src; c.policy = policy;
|
|
3183
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
|
+
}
|
|
3184
3464
|
ca_iter_protect(st, ca_iter_call_init_l1, (VALUE) &c);
|
|
3185
3465
|
if ( c.rc == CA_ITER_OK ) ca_iter_mark_walk_may_raise(st);
|
|
3186
3466
|
return c.rc;
|
|
@@ -3197,11 +3477,32 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
3197
3477
|
ca_iter_call_t c;
|
|
3198
3478
|
c.st = st; c.src = src; c.policy = policy;
|
|
3199
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
|
+
}
|
|
3200
3483
|
ca_iter_protect(st, ca_iter_call_init_l2, (VALUE) &c);
|
|
3201
3484
|
if ( c.rc == CA_ITER_OK ) ca_iter_mark_walk_may_raise(st);
|
|
3202
3485
|
return c.rc;
|
|
3203
3486
|
}
|
|
3204
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
|
+
|
|
3205
3506
|
int
|
|
3206
3507
|
ca_iter_state_next_slab (ca_iter_state *st,
|
|
3207
3508
|
char **out_ptr,
|
|
@@ -3210,12 +3511,13 @@ ca_iter_state_next_slab (ca_iter_state *st,
|
|
|
3210
3511
|
{
|
|
3211
3512
|
ca_iter_call_t c;
|
|
3212
3513
|
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3213
|
-
return
|
|
3514
|
+
return ca_iter_mark_dirty(st,
|
|
3515
|
+
ca_iter_state_next_slab_unprotected(st, out_ptr, out_mask, out_n));
|
|
3214
3516
|
}
|
|
3215
3517
|
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.out_n = out_n;
|
|
3216
3518
|
c.rc = 0;
|
|
3217
3519
|
ca_iter_protect(st, ca_iter_call_next_slab, (VALUE) &c);
|
|
3218
|
-
return c.rc;
|
|
3520
|
+
return ca_iter_mark_dirty(st, c.rc);
|
|
3219
3521
|
}
|
|
3220
3522
|
|
|
3221
3523
|
int
|
|
@@ -3227,13 +3529,14 @@ ca_iter_state_next_slab_strided (ca_iter_state *st,
|
|
|
3227
3529
|
{
|
|
3228
3530
|
ca_iter_call_t c;
|
|
3229
3531
|
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3230
|
-
return
|
|
3231
|
-
|
|
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));
|
|
3232
3535
|
}
|
|
3233
3536
|
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.out_n = out_n;
|
|
3234
3537
|
c.out_stride_bytes = out_stride_bytes; c.rc = 0;
|
|
3235
3538
|
ca_iter_protect(st, ca_iter_call_next_slab_strided, (VALUE) &c);
|
|
3236
|
-
return c.rc;
|
|
3539
|
+
return ca_iter_mark_dirty(st, c.rc);
|
|
3237
3540
|
}
|
|
3238
3541
|
|
|
3239
3542
|
int
|
|
@@ -3243,11 +3546,12 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
3243
3546
|
{
|
|
3244
3547
|
ca_iter_call_t c;
|
|
3245
3548
|
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3246
|
-
return
|
|
3549
|
+
return ca_iter_mark_dirty(st,
|
|
3550
|
+
ca_iter_state_next_slab_axes_unprotected(st, out_ptr, out_mask));
|
|
3247
3551
|
}
|
|
3248
3552
|
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.rc = 0;
|
|
3249
3553
|
ca_iter_protect(st, ca_iter_call_next_slab_axes, (VALUE) &c);
|
|
3250
|
-
return c.rc;
|
|
3554
|
+
return ca_iter_mark_dirty(st, c.rc);
|
|
3251
3555
|
}
|
|
3252
3556
|
|
|
3253
3557
|
void
|
|
@@ -3262,6 +3566,144 @@ ca_iter_state_sync_slab (ca_iter_state *st)
|
|
|
3262
3566
|
ca_iter_protect(st, ca_iter_call_sync_slab, (VALUE) &c);
|
|
3263
3567
|
}
|
|
3264
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
|
+
|
|
3265
3707
|
#ifdef CARRAY_DEV_BUILD
|
|
3266
3708
|
/* ============================================================
|
|
3267
3709
|
* smoke surface (dev-only, stripped in release)
|
|
@@ -4418,9 +4860,13 @@ rb_caf_slab_bench_sort_copy_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4418
4860
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, out);
|
|
4419
4861
|
slab_axes[0] = (int8_t) axis;
|
|
4420
4862
|
|
|
4863
|
+
if ( axis < 0 || axis >= src->ndim ) {
|
|
4864
|
+
rb_raise(rb_eArgError, "caf_slab_bench_sort_copy_f64: axis out of range");
|
|
4865
|
+
}
|
|
4421
4866
|
ca_size_t fiber_n = src->dim[axis];
|
|
4422
4867
|
ca_size_t bytes = sizeof(double);
|
|
4423
|
-
|
|
4868
|
+
volatile VALUE holder; /* the walk can raise while buf is held */
|
|
4869
|
+
char *buf = ALLOCV_N(char, holder, fiber_n * bytes);
|
|
4424
4870
|
|
|
4425
4871
|
CA_FOR_EACH_SLAB_INOUT(st_in, st_out, src, out,
|
|
4426
4872
|
slab_axes, 1,
|
|
@@ -4452,7 +4898,7 @@ rb_caf_slab_bench_sort_copy_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4452
4898
|
}
|
|
4453
4899
|
}
|
|
4454
4900
|
}
|
|
4455
|
-
|
|
4901
|
+
ALLOCV_END(holder);
|
|
4456
4902
|
return vout;
|
|
4457
4903
|
}
|
|
4458
4904
|
|
|
@@ -4502,7 +4948,8 @@ rb_caf_bench_per_fiber_xfer_sum_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4502
4948
|
}
|
|
4503
4949
|
|
|
4504
4950
|
/* Fiber-sized contig scratch. */
|
|
4505
|
-
|
|
4951
|
+
volatile VALUE holder;
|
|
4952
|
+
char *buf = ALLOCV_N(char, holder, fiber_n * src->bytes);
|
|
4506
4953
|
|
|
4507
4954
|
for ( ca_size_t f = 0; f < total_fibers; f++ ) {
|
|
4508
4955
|
/* Build region: counts = 1 on all non-axis, fiber_n on axis;
|
|
@@ -4530,7 +4977,7 @@ rb_caf_bench_per_fiber_xfer_sum_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4530
4977
|
}
|
|
4531
4978
|
}
|
|
4532
4979
|
|
|
4533
|
-
|
|
4980
|
+
ALLOCV_END(holder);
|
|
4534
4981
|
return rb_float_new(total);
|
|
4535
4982
|
}
|
|
4536
4983
|
|
|
@@ -4539,6 +4986,8 @@ rb_caf_bench_per_fiber_xfer_sum_f64 (VALUE klass, VALUE vsrc, VALUE vaxis)
|
|
|
4539
4986
|
void
|
|
4540
4987
|
Init_ca_kernel_iterator (void)
|
|
4541
4988
|
{
|
|
4989
|
+
ki_kept_key = rb_ractor_local_storage_ptr_newkey(&ki_kept_type);
|
|
4990
|
+
|
|
4542
4991
|
#ifdef CARRAY_DEV_BUILD
|
|
4543
4992
|
/* ==== smoke surface registrations (dev-only, stripped in release) ====
|
|
4544
4993
|
* See PROPOSAL_SMOKE_DEV_BUILD_GATE.md. All `t1_smoke_*`, `caf_smoke_*`,
|