carray 3.0.3 → 3.0.4
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 +264 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +1 -6
- data/ext/ca_axis_group.c +27 -27
- data/ext/ca_binop_dispatch.c +1 -29
- data/ext/ca_binop_dispatch.h +0 -1
- data/ext/ca_categorical_iterator.c +205 -134
- data/ext/ca_compare.c +7 -18
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1234 -1994
- data/ext/ca_kernel_iterator.h +391 -437
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +96 -39
- data/ext/ca_obj_bincmp.c +24 -21
- data/ext/ca_obj_binop.c +15 -26
- data/ext/ca_obj_bitarray.c +3 -2
- data/ext/ca_obj_bitfield.c +5 -6
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +5 -6
- data/ext/ca_obj_const_string.c +173 -19
- data/ext/ca_obj_face.c +238 -57
- data/ext/ca_obj_face.h +19 -0
- data/ext/ca_obj_fake.c +15 -29
- data/ext/ca_obj_farray.c +6 -3
- data/ext/ca_obj_field.c +17 -5
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +406 -132
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +67 -57
- data/ext/ca_obj_object.c +157 -51
- data/ext/ca_obj_record.c +12 -7
- data/ext/ca_obj_reduce.c +13 -8
- data/ext/ca_obj_refer.c +25 -27
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +6 -5
- data/ext/ca_obj_select.c +14 -9
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +11 -1
- data/ext/ca_obj_stack.c +179 -34
- data/ext/ca_obj_stride.c +162 -115
- data/ext/ca_obj_string.c +71 -4
- data/ext/ca_obj_tile.c +6 -5
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +5 -3
- data/ext/ca_obj_triop.c +23 -32
- data/ext/ca_obj_window.c +190 -26
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +181 -75
- data/ext/carray_access.c +184 -96
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +89 -6
- data/ext/carray_bincount.c +10 -8
- data/ext/carray_broadcast.c +13 -8
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +108 -0
- data/ext/carray_cast.c +142 -24
- data/ext/carray_cast_func.rb +46 -6
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +16 -7
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +147 -55
- data/ext/carray_count.c +50 -20
- data/ext/carray_element.c +76 -33
- data/ext/carray_factorize.c +118 -64
- data/ext/carray_generate.c +191 -50
- data/ext/carray_histogram.c +62 -17
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +336 -29
- data/ext/carray_kernels_bincmp.c +4453 -0
- data/ext/carray_kernels_binop.c +11368 -0
- data/ext/carray_kernels_init.c +1734 -0
- data/ext/carray_kernels_moncmp.c +2104 -0
- data/ext/carray_kernels_monop.c +18369 -0
- data/ext/carray_kernels_reduce_aggregate.c +23818 -0
- data/ext/carray_kernels_reduce_boolean.c +406 -0
- data/ext/carray_kernels_reduce_cumulative.c +10086 -0
- data/ext/carray_kernels_reduce_extreme.c +17634 -0
- data/ext/carray_kernels_reduce_variance.c +3849 -0
- data/ext/carray_kernels_scan.c +4302 -0
- data/ext/carray_kernels_search.c +33829 -0
- data/ext/carray_kernels_sort.c +10906 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +292 -72
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +124 -47
- data/ext/carray_order.c +384 -76
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +67 -13
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +63 -38
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +91 -28
- data/ext/carray_sort.c +35 -35
- data/ext/carray_struct.c +19 -18
- data/ext/carray_test.c +26 -5
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +246 -45
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +198 -240
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +126 -22
- data/lib/carray/autoload_carray.rb +8 -31
- data/lib/carray/autoload_method_extension.rb +14 -5
- data/lib/carray/axis_group.rb +255 -106
- data/lib/carray/basics.rb +78 -10
- data/lib/carray/bincount_nd.rb +12 -2
- data/lib/carray/block_iterator.rb +126 -23
- data/lib/carray/boolean_reduce.rb +17 -17
- data/lib/carray/categorical.rb +165 -43
- data/lib/carray/categorical_iterator.rb +130 -27
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +14 -5
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/convert.rb +69 -0
- data/lib/carray/frame/csv_parser.rb +111 -17
- data/lib/carray/frame/describe.rb +3 -2
- data/lib/carray/frame/frame.rb +246 -21
- data/lib/carray/frame/group.rb +510 -95
- data/lib/carray/frame/io.rb +115 -28
- data/lib/carray/frame/join.rb +312 -51
- data/lib/carray/frame/records.rb +83 -7
- data/lib/carray/frame/reshape.rb +42 -35
- data/lib/carray/frame/sort.rb +7 -19
- data/lib/carray/frame/verbs.rb +188 -48
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +11 -4
- data/lib/carray/fusion.rb +40 -16
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +31 -8
- data/lib/carray/iterator.rb +85 -7
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +182 -183
- data/lib/carray/mask_gap_fill.rb +63 -57
- data/lib/carray/meld_reduce.rb +12 -14
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +16 -0
- data/lib/carray/methods/bit_string.rb +1 -1
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +3 -1
- data/lib/carray/methods/gather_nd.rb +14 -5
- data/lib/carray/methods/insert_block.rb +2 -2
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +53 -36
- data/lib/carray/methods/join.rb +1 -6
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +47 -51
- data/lib/carray/methods/mode.rb +1 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/resize.rb +3 -3
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +3 -3
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +53 -8
- data/lib/carray/segment_iterator.rb +313 -82
- data/lib/carray/serialize.rb +24 -10
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +8 -1
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +19 -8
- data/lib/carray/time.rb +726 -104
- data/lib/carray/window_iterator.rb +122 -16
- data/lib/carray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +4 -0
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +2 -1
- data/yard-stubs/ca_obj_roll.rb +2 -2
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_cast.rb +10 -0
- data/yard-stubs/carray_conversion.rb +2 -1
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +26 -2
- data/yard-stubs/carray_math.rb +27 -1
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +29 -18
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +14 -9
- data/yard-stubs/carray_slab.rb +9 -2
- data/yard-stubs/carray_sort.rb +6 -5
- data/yard-stubs/carray_test.rb +5 -3
- metadata +25 -3
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_lazy.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* ---------------------------------------------------------------------------
|
|
2
2
|
|
|
3
|
-
CALazyMarker view + the
|
|
3
|
+
CALazyMarker view + the lazy arena.
|
|
4
4
|
|
|
5
5
|
CALazyMarker is a zero-cost marker that holds a CArray entity and
|
|
6
6
|
causes `.sqrt` / `.sin` / etc. on it to build a lazy CAMonOp tree
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
is a pure pass-through: every CArray operation delegates to the
|
|
12
12
|
parent. Detection happens via ca_is_lazy_view().
|
|
13
13
|
|
|
14
|
-
ca_lazy_arena is the
|
|
14
|
+
ca_lazy_arena is the per-Ractor slot-pool arena that CAMonOp / CABinOp
|
|
15
15
|
/ CAMonCmp / CABinCmp use for scratch during to_ca; slot buffers
|
|
16
16
|
stay alive across calls to amortise mmap into steady-state reuse.
|
|
17
17
|
|
|
@@ -80,10 +80,6 @@ ca_lazy_marker_setup (CALazyMarker *ca, CArray *parent)
|
|
|
80
80
|
|
|
81
81
|
memcpy(ca->dim, parent->dim, parent->ndim * sizeof(ca_size_t));
|
|
82
82
|
|
|
83
|
-
if ( ca_has_mask(parent) ) {
|
|
84
|
-
ca_create_mask(ca);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
83
|
if ( ca_is_scalar(parent) ) {
|
|
88
84
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
89
85
|
}
|
|
@@ -105,8 +101,10 @@ ca_lazy_marker_setup (CALazyMarker *ca, CArray *parent)
|
|
|
105
101
|
CALazyMarker *
|
|
106
102
|
ca_lazy_marker_new (CArray *parent)
|
|
107
103
|
{
|
|
104
|
+
/* check: the setup checks nothing */
|
|
108
105
|
CALazyMarker *ca = ALLOC(CALazyMarker);
|
|
109
106
|
ca_lazy_marker_setup(ca, parent);
|
|
107
|
+
ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
|
|
110
108
|
return ca;
|
|
111
109
|
}
|
|
112
110
|
|
|
@@ -360,7 +358,6 @@ ca_gc_local (void)
|
|
|
360
358
|
return g;
|
|
361
359
|
}
|
|
362
360
|
|
|
363
|
-
static void ca_lazy_arena_mark_object_slots (void);
|
|
364
361
|
|
|
365
362
|
/* Returns the depth to hand back to ca_gc_hold_pop_to, so nested holds
|
|
366
363
|
unwind in order. Pushing is best-effort at the ceiling: a chain
|
|
@@ -437,32 +434,6 @@ ca_gc_release_buffer (void *ptr)
|
|
|
437
434
|
}
|
|
438
435
|
}
|
|
439
436
|
|
|
440
|
-
static VALUE ca_gc_guard = Qnil;
|
|
441
|
-
|
|
442
|
-
/* The wrapped pointer must be non-NULL: Ruby's GC skips the mark
|
|
443
|
-
function of a TypedData whose data pointer is NULL. */
|
|
444
|
-
static int ca_gc_guard_body = 0;
|
|
445
|
-
|
|
446
|
-
/* The arena's object slots. The holds are marked per Ractor above. */
|
|
447
|
-
static void
|
|
448
|
-
ca_gc_guard_mark (void *ptr)
|
|
449
|
-
{
|
|
450
|
-
(void) ptr;
|
|
451
|
-
ca_lazy_arena_mark_object_slots();
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
static void
|
|
455
|
-
ca_gc_guard_free (void *ptr)
|
|
456
|
-
{
|
|
457
|
-
(void) ptr;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
static const rb_data_type_t ca_gc_guard_data_type = {
|
|
461
|
-
"carray_object_gc_guard",
|
|
462
|
-
{ ca_gc_guard_mark, ca_gc_guard_free, NULL, },
|
|
463
|
-
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
464
|
-
};
|
|
465
|
-
|
|
466
437
|
/* ------------------------------------------------------------------- */
|
|
467
438
|
/* ca_lazy_arena */
|
|
468
439
|
/* ------------------------------------------------------------------- */
|
|
@@ -485,12 +456,13 @@ static const rb_data_type_t ca_gc_guard_data_type = {
|
|
|
485
456
|
as the largest request it has served (e.g. N=1M f64, depth-8 chain =
|
|
486
457
|
8 × 8MB = 64MB kept resident). A request no free slot can hold grows
|
|
487
458
|
a free slot; a new slot opens only while every warm one is in use.
|
|
488
|
-
|
|
459
|
+
Past 256 MB the idle slots are given back at the next top-level entry
|
|
460
|
+
(ca_lazy_arena_trim). When all 32 are in use the acquire raises: this signals a programming
|
|
489
461
|
error or a pathological chain rather than a graceful fallback.
|
|
490
462
|
|
|
491
|
-
|
|
492
|
-
is not a goal (see
|
|
493
|
-
|
|
463
|
+
One arena per Ractor (see ca_lazy_arena_get). Within a Ractor it is
|
|
464
|
+
not guarded: thread-safety across concurrent access is not a goal (see
|
|
465
|
+
guides/devel/04_attach_lifecycle.md). */
|
|
494
466
|
|
|
495
467
|
#define CA_LAZY_ARENA_SLOTS 32
|
|
496
468
|
|
|
@@ -509,29 +481,109 @@ typedef struct ca_lazy_arena {
|
|
|
509
481
|
ca_size_t debug_reuse_count; /* test: how many acquire = reuse */
|
|
510
482
|
} ca_lazy_arena_t;
|
|
511
483
|
|
|
512
|
-
|
|
484
|
+
/* One arena per Ractor: the slots are handed out by pointer and toggled
|
|
485
|
+
without a lock, so two Ractors sharing them would hand the same buffer
|
|
486
|
+
to both. The storage marks the object slots in use and frees the
|
|
487
|
+
buffers when the Ractor ends. */
|
|
488
|
+
static rb_ractor_local_key_t ca_lazy_arena_key;
|
|
489
|
+
|
|
490
|
+
static void ca_lazy_arena_mark_object_slots (ca_lazy_arena_t *arena);
|
|
491
|
+
|
|
492
|
+
static void
|
|
493
|
+
ca_lazy_arena_mark (void *ptr)
|
|
494
|
+
{
|
|
495
|
+
if ( ptr ) ca_lazy_arena_mark_object_slots((ca_lazy_arena_t *) ptr);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
static void
|
|
499
|
+
ca_lazy_arena_free (void *ptr)
|
|
500
|
+
{
|
|
501
|
+
ca_lazy_arena_t *arena = (ca_lazy_arena_t *) ptr;
|
|
502
|
+
int i;
|
|
503
|
+
if ( arena == NULL ) return;
|
|
504
|
+
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
505
|
+
if ( arena->slots[i].ptr ) ruby_xfree(arena->slots[i].ptr);
|
|
506
|
+
}
|
|
507
|
+
ruby_xfree(arena);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
static const struct rb_ractor_local_storage_type ca_lazy_arena_type = {
|
|
511
|
+
ca_lazy_arena_mark, ca_lazy_arena_free
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
static ca_lazy_arena_t *
|
|
515
|
+
ca_lazy_arena_get (void)
|
|
516
|
+
{
|
|
517
|
+
ca_lazy_arena_t *arena =
|
|
518
|
+
(ca_lazy_arena_t *) rb_ractor_local_storage_ptr(ca_lazy_arena_key);
|
|
519
|
+
if ( arena == NULL ) {
|
|
520
|
+
arena = ZALLOC(ca_lazy_arena_t);
|
|
521
|
+
rb_ractor_local_storage_ptr_set(ca_lazy_arena_key, arena);
|
|
522
|
+
}
|
|
523
|
+
return arena;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* Above this the arena returns memory: the idle slots are freed, the
|
|
527
|
+
smallest first, until what it holds is under the limit. The largest
|
|
528
|
+
slot is always kept, so a workload that repeats one request keeps its
|
|
529
|
+
warm buffer however large it is. */
|
|
530
|
+
#define CA_LAZY_ARENA_KEEP_BYTES ((ca_size_t) 256 << 20)
|
|
531
|
+
|
|
532
|
+
static void
|
|
533
|
+
ca_lazy_arena_trim (ca_lazy_arena_t *arena)
|
|
534
|
+
{
|
|
535
|
+
ca_size_t total = 0;
|
|
536
|
+
int i, largest = -1;
|
|
537
|
+
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
538
|
+
if ( arena->slots[i].ptr == NULL ) continue;
|
|
539
|
+
total += arena->slots[i].bytes;
|
|
540
|
+
if ( largest < 0 || arena->slots[i].bytes > arena->slots[largest].bytes ) {
|
|
541
|
+
largest = i;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
while ( total > CA_LAZY_ARENA_KEEP_BYTES ) {
|
|
545
|
+
int smallest = -1;
|
|
546
|
+
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
547
|
+
ca_lazy_arena_slot_t *s = &arena->slots[i];
|
|
548
|
+
if ( s->ptr == NULL || s->in_use || i == largest ) continue;
|
|
549
|
+
if ( smallest < 0 || s->bytes < arena->slots[smallest].bytes ) {
|
|
550
|
+
smallest = i;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if ( smallest < 0 ) break;
|
|
554
|
+
total -= arena->slots[smallest].bytes;
|
|
555
|
+
xfree(arena->slots[smallest].ptr);
|
|
556
|
+
arena->slots[smallest].ptr = NULL;
|
|
557
|
+
arena->slots[smallest].bytes = 0;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
513
560
|
|
|
514
561
|
void
|
|
515
562
|
ca_lazy_arena_enter (void)
|
|
516
563
|
{
|
|
517
|
-
|
|
564
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
565
|
+
if ( arena->depth == 0 ) {
|
|
566
|
+
/* Only a slot no one holds is freed: a lazy view's attach takes
|
|
567
|
+
scratch outside any enter / exit bracket. */
|
|
568
|
+
ca_lazy_arena_trim(arena);
|
|
518
569
|
/* Top-level reset to recover from a prior exception that left
|
|
519
570
|
slots in_use without a matching release. Safe because
|
|
520
571
|
depth==0 means no nested caller is mid-acquire. */
|
|
521
572
|
int i;
|
|
522
573
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
523
|
-
|
|
524
|
-
|
|
574
|
+
arena->slots[i].in_use = 0;
|
|
575
|
+
arena->slots[i].object_elements = 0;
|
|
525
576
|
}
|
|
526
577
|
}
|
|
527
|
-
|
|
578
|
+
arena->depth++;
|
|
528
579
|
}
|
|
529
580
|
|
|
530
581
|
void
|
|
531
582
|
ca_lazy_arena_exit (void)
|
|
532
583
|
{
|
|
533
|
-
|
|
534
|
-
|
|
584
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
585
|
+
if ( arena->depth > 0 ) {
|
|
586
|
+
arena->depth--;
|
|
535
587
|
}
|
|
536
588
|
/* Keep all slot buffers, and leave in_use and the object tags alone.
|
|
537
589
|
A scratch can be acquired outside any enter/exit bracket -- a lazy
|
|
@@ -599,12 +651,13 @@ ca_lazy_arena_release_held (VALUE arg)
|
|
|
599
651
|
void *
|
|
600
652
|
ca_lazy_arena_acquire (ca_size_t bytes)
|
|
601
653
|
{
|
|
654
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
602
655
|
int i, best, empty;
|
|
603
656
|
ca_size_t best_bytes;
|
|
604
657
|
|
|
605
658
|
if ( bytes <= 0 ) bytes = 1;
|
|
606
659
|
|
|
607
|
-
|
|
660
|
+
arena->debug_acquire_count++;
|
|
608
661
|
|
|
609
662
|
/* Pass 1: best-fit among unused warm slots (smallest >= bytes).
|
|
610
663
|
CAREFUL: ca_size_t is signed int64_t, so the "no match yet"
|
|
@@ -613,7 +666,7 @@ ca_lazy_arena_acquire (ca_size_t bytes)
|
|
|
613
666
|
best = -1;
|
|
614
667
|
best_bytes = CA_LENGTH_MAX;
|
|
615
668
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
616
|
-
ca_lazy_arena_slot_t *s = &
|
|
669
|
+
ca_lazy_arena_slot_t *s = &arena->slots[i];
|
|
617
670
|
if ( s->in_use ) continue;
|
|
618
671
|
if ( s->ptr == NULL ) continue;
|
|
619
672
|
if ( s->bytes < bytes ) continue;
|
|
@@ -623,10 +676,10 @@ ca_lazy_arena_acquire (ca_size_t bytes)
|
|
|
623
676
|
}
|
|
624
677
|
}
|
|
625
678
|
if ( best >= 0 ) {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
return
|
|
679
|
+
arena->slots[best].in_use = 1;
|
|
680
|
+
arena->slots[best].object_elements = 0;
|
|
681
|
+
arena->debug_reuse_count++;
|
|
682
|
+
return arena->slots[best].ptr;
|
|
630
683
|
}
|
|
631
684
|
|
|
632
685
|
|
|
@@ -642,7 +695,7 @@ ca_lazy_arena_acquire (ca_size_t bytes)
|
|
|
642
695
|
best = -1;
|
|
643
696
|
best_bytes = -1;
|
|
644
697
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
645
|
-
ca_lazy_arena_slot_t *s = &
|
|
698
|
+
ca_lazy_arena_slot_t *s = &arena->slots[i];
|
|
646
699
|
if ( s->in_use || s->ptr == NULL ) continue;
|
|
647
700
|
if ( s->bytes > best_bytes ) {
|
|
648
701
|
best = i;
|
|
@@ -650,34 +703,34 @@ ca_lazy_arena_acquire (ca_size_t bytes)
|
|
|
650
703
|
}
|
|
651
704
|
}
|
|
652
705
|
if ( best >= 0 ) {
|
|
653
|
-
ca_lazy_arena_slot_t *s = &
|
|
706
|
+
ca_lazy_arena_slot_t *s = &arena->slots[best];
|
|
654
707
|
void *old = s->ptr;
|
|
655
708
|
s->ptr = NULL;
|
|
656
709
|
s->bytes = 0;
|
|
657
710
|
xfree(old);
|
|
658
|
-
s->ptr = xmalloc(bytes);
|
|
711
|
+
s->ptr = xmalloc(bytes); /* cells: ca_lazy_arena_acquire_object clears object slots */
|
|
659
712
|
s->bytes = bytes;
|
|
660
713
|
s->in_use = 1;
|
|
661
714
|
s->object_elements = 0;
|
|
662
|
-
|
|
715
|
+
arena->debug_xmalloc_count++;
|
|
663
716
|
return s->ptr;
|
|
664
717
|
}
|
|
665
718
|
|
|
666
719
|
/* Pass 3: every warm slot is in use. Open an empty one. */
|
|
667
720
|
empty = -1;
|
|
668
721
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
669
|
-
if (
|
|
722
|
+
if ( arena->slots[i].ptr == NULL ) {
|
|
670
723
|
empty = i;
|
|
671
724
|
break;
|
|
672
725
|
}
|
|
673
726
|
}
|
|
674
727
|
if ( empty >= 0 ) {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return
|
|
728
|
+
arena->slots[empty].ptr = xmalloc(bytes); /* cells: ca_lazy_arena_acquire_object clears object slots */
|
|
729
|
+
arena->slots[empty].bytes = bytes;
|
|
730
|
+
arena->slots[empty].in_use = 1;
|
|
731
|
+
arena->slots[empty].object_elements = 0;
|
|
732
|
+
arena->debug_xmalloc_count++;
|
|
733
|
+
return arena->slots[empty].ptr;
|
|
681
734
|
}
|
|
682
735
|
|
|
683
736
|
/* Pass 4: all CA_LAZY_ARENA_SLOTS in use simultaneously. This is
|
|
@@ -692,12 +745,13 @@ ca_lazy_arena_acquire (ca_size_t bytes)
|
|
|
692
745
|
void
|
|
693
746
|
ca_lazy_arena_release (void *ptr)
|
|
694
747
|
{
|
|
748
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
695
749
|
int i;
|
|
696
750
|
if ( ptr == NULL ) return;
|
|
697
751
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
698
|
-
if (
|
|
699
|
-
|
|
700
|
-
|
|
752
|
+
if ( arena->slots[i].ptr == ptr ) {
|
|
753
|
+
arena->slots[i].in_use = 0;
|
|
754
|
+
arena->slots[i].object_elements = 0;
|
|
701
755
|
return;
|
|
702
756
|
}
|
|
703
757
|
}
|
|
@@ -716,21 +770,18 @@ ca_lazy_arena_release (void *ptr)
|
|
|
716
770
|
void *
|
|
717
771
|
ca_lazy_arena_acquire_object (ca_size_t n_elements)
|
|
718
772
|
{
|
|
773
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
719
774
|
void *ptr;
|
|
720
775
|
int i;
|
|
721
776
|
|
|
722
777
|
if ( n_elements < 0 ) n_elements = 0;
|
|
723
778
|
ptr = ca_lazy_arena_acquire(n_elements * (ca_size_t) sizeof(VALUE));
|
|
724
779
|
|
|
725
|
-
|
|
726
|
-
VALUE *p = (VALUE *) ptr;
|
|
727
|
-
ca_size_t n = n_elements;
|
|
728
|
-
while ( n-- ) *p++ = Qnil;
|
|
729
|
-
}
|
|
780
|
+
ca_object_cells_clear(ptr, n_elements);
|
|
730
781
|
|
|
731
782
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
732
|
-
if (
|
|
733
|
-
|
|
783
|
+
if ( arena->slots[i].ptr == ptr ) {
|
|
784
|
+
arena->slots[i].object_elements = n_elements;
|
|
734
785
|
break;
|
|
735
786
|
}
|
|
736
787
|
}
|
|
@@ -738,11 +789,11 @@ ca_lazy_arena_acquire_object (ca_size_t n_elements)
|
|
|
738
789
|
}
|
|
739
790
|
|
|
740
791
|
static void
|
|
741
|
-
ca_lazy_arena_mark_object_slots (
|
|
792
|
+
ca_lazy_arena_mark_object_slots (ca_lazy_arena_t *arena)
|
|
742
793
|
{
|
|
743
794
|
int i;
|
|
744
795
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
745
|
-
ca_lazy_arena_slot_t *s = &
|
|
796
|
+
ca_lazy_arena_slot_t *s = &arena->slots[i];
|
|
746
797
|
ca_size_t n;
|
|
747
798
|
VALUE *p;
|
|
748
799
|
if ( ! s->in_use || s->object_elements <= 0 ) continue;
|
|
@@ -754,45 +805,52 @@ ca_lazy_arena_mark_object_slots (void)
|
|
|
754
805
|
|
|
755
806
|
/* Test instrumentation — exposed to Ruby for the arena smoke and
|
|
756
807
|
regression assertions. Not user-facing API. */
|
|
808
|
+
#ifdef CARRAY_DEV_BUILD
|
|
757
809
|
static VALUE
|
|
758
810
|
rb_ca_lazy_arena_s_reset_counters (VALUE klass)
|
|
759
811
|
{
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
812
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
813
|
+
arena->debug_acquire_count = 0;
|
|
814
|
+
arena->debug_xmalloc_count = 0;
|
|
815
|
+
arena->debug_reuse_count = 0;
|
|
763
816
|
return Qnil;
|
|
764
817
|
}
|
|
765
818
|
|
|
766
819
|
static VALUE
|
|
767
820
|
rb_ca_lazy_arena_s_acquire_count (VALUE klass)
|
|
768
821
|
{
|
|
769
|
-
|
|
822
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
823
|
+
return SIZE2NUM(arena->debug_acquire_count);
|
|
770
824
|
}
|
|
771
825
|
|
|
772
826
|
static VALUE
|
|
773
827
|
rb_ca_lazy_arena_s_xmalloc_count (VALUE klass)
|
|
774
828
|
{
|
|
775
|
-
|
|
829
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
830
|
+
return SIZE2NUM(arena->debug_xmalloc_count);
|
|
776
831
|
}
|
|
777
832
|
|
|
778
833
|
static VALUE
|
|
779
834
|
rb_ca_lazy_arena_s_reuse_count (VALUE klass)
|
|
780
835
|
{
|
|
781
|
-
|
|
836
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
837
|
+
return SIZE2NUM(arena->debug_reuse_count);
|
|
782
838
|
}
|
|
783
839
|
|
|
784
840
|
static VALUE
|
|
785
841
|
rb_ca_lazy_arena_s_depth (VALUE klass)
|
|
786
842
|
{
|
|
787
|
-
|
|
843
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
844
|
+
return INT2NUM(arena->depth);
|
|
788
845
|
}
|
|
789
846
|
|
|
790
847
|
static VALUE
|
|
791
848
|
rb_ca_lazy_arena_s_slot_in_use_count (VALUE klass)
|
|
792
849
|
{
|
|
850
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
793
851
|
int i, n = 0;
|
|
794
852
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
795
|
-
if (
|
|
853
|
+
if ( arena->slots[i].in_use ) n++;
|
|
796
854
|
}
|
|
797
855
|
return INT2NUM(n);
|
|
798
856
|
}
|
|
@@ -806,16 +864,18 @@ rb_ca_lazy_arena_s_slot_in_use_count (VALUE klass)
|
|
|
806
864
|
static VALUE
|
|
807
865
|
rb_ca_lazy_arena_s_slot_capacities (VALUE klass)
|
|
808
866
|
{
|
|
867
|
+
ca_lazy_arena_t *arena = ca_lazy_arena_get();
|
|
809
868
|
int i;
|
|
810
869
|
VALUE arr = rb_ary_new();
|
|
811
870
|
(void) klass;
|
|
812
871
|
for ( i = 0; i < CA_LAZY_ARENA_SLOTS; i++ ) {
|
|
813
|
-
if (
|
|
814
|
-
rb_ary_push(arr, SIZE2NUM(
|
|
872
|
+
if ( arena->slots[i].ptr != NULL ) {
|
|
873
|
+
rb_ary_push(arr, SIZE2NUM(arena->slots[i].bytes));
|
|
815
874
|
}
|
|
816
875
|
}
|
|
817
876
|
return arr;
|
|
818
877
|
}
|
|
878
|
+
#endif /* CARRAY_DEV_BUILD */
|
|
819
879
|
|
|
820
880
|
/* ------------------------------------------------------------------- */
|
|
821
881
|
|
|
@@ -835,6 +895,7 @@ rb_ca_lazy_marker_initialize_copy (VALUE self, VALUE other)
|
|
|
835
895
|
ca_check_uninitialized(ca);
|
|
836
896
|
TypedData_Get_Struct(other, CALazyMarker, &calazy_marker_data_type, cs);
|
|
837
897
|
ca_lazy_marker_setup(ca, cs->parent);
|
|
898
|
+
ca_view_inherit_mask((VALUE) ca);
|
|
838
899
|
return self;
|
|
839
900
|
}
|
|
840
901
|
|
|
@@ -857,16 +918,13 @@ Init_carray_lazy (void)
|
|
|
857
918
|
|
|
858
919
|
ca_gc_local_key = rb_ractor_local_storage_ptr_newkey(&ca_gc_local_type);
|
|
859
920
|
|
|
860
|
-
|
|
861
|
-
arena's CA_OBJECT slots reachable. */
|
|
862
|
-
ca_gc_guard = TypedData_Wrap_Struct(rb_cObject, &ca_gc_guard_data_type,
|
|
863
|
-
&ca_gc_guard_body);
|
|
864
|
-
rb_gc_register_mark_object(ca_gc_guard);
|
|
921
|
+
ca_lazy_arena_key = rb_ractor_local_storage_ptr_newkey(&ca_lazy_arena_type);
|
|
865
922
|
|
|
866
923
|
rb_define_alloc_func(rb_cCALazyMarker, rb_ca_lazy_marker_s_allocate);
|
|
867
924
|
rb_define_method(rb_cCALazyMarker, "initialize_copy",
|
|
868
925
|
rb_ca_lazy_marker_initialize_copy, 1);
|
|
869
926
|
|
|
927
|
+
#ifdef CARRAY_DEV_BUILD
|
|
870
928
|
/* Arena test instrumentation (not user-facing). Bound on CArray
|
|
871
929
|
for symmetry with CAMonOp / CABinOp counters, but the arena is
|
|
872
930
|
a singleton process-wide state. */
|
|
@@ -884,6 +942,7 @@ Init_carray_lazy (void)
|
|
|
884
942
|
rb_ca_lazy_arena_s_slot_in_use_count, 0);
|
|
885
943
|
rb_define_singleton_method(rb_cCArray, "__lazy_arena_slot_capacities__",
|
|
886
944
|
rb_ca_lazy_arena_s_slot_capacities, 0);
|
|
945
|
+
#endif
|
|
887
946
|
|
|
888
947
|
Init_ca_mask_of_operands();
|
|
889
948
|
}
|
|
@@ -1056,18 +1115,18 @@ ca_lazy_req_pull (void *operand, const ca_lazy_req_t *req, void *buf, int dir)
|
|
|
1056
1115
|
VALUE
|
|
1057
1116
|
ca_lazy_evaluated (VALUE self)
|
|
1058
1117
|
{
|
|
1059
|
-
|
|
1118
|
+
/* rb_intern caches each literal by itself; a shared guard over several
|
|
1119
|
+
IDs would let a second Ractor read one not yet set. */
|
|
1120
|
+
ID id_evaluator = rb_intern("@expression_evaluator");
|
|
1121
|
+
ID id_fusion = rb_intern("Fusion");
|
|
1122
|
+
ID id_evaluate = rb_intern("evaluate");
|
|
1060
1123
|
CArray *ca;
|
|
1061
|
-
if ( ! id_evaluator ) {
|
|
1062
|
-
id_evaluator = rb_intern("@expression_evaluator");
|
|
1063
|
-
id_fusion = rb_intern("Fusion");
|
|
1064
|
-
id_evaluate = rb_intern("evaluate");
|
|
1065
|
-
}
|
|
1066
1124
|
GetCArray(self, ca);
|
|
1067
1125
|
if ( ! ca_is_lazy_view(ca) ) {
|
|
1068
1126
|
return Qnil;
|
|
1069
1127
|
}
|
|
1070
|
-
|
|
1128
|
+
/* registered in the main Ractor, and asked only there */
|
|
1129
|
+
if ( ! ca_in_main_ractor() || ! RTEST(rb_attr_get(rb_cCArray, id_evaluator)) ) {
|
|
1071
1130
|
return Qnil;
|
|
1072
1131
|
}
|
|
1073
1132
|
return rb_funcall(rb_const_get(rb_cCArray, id_fusion), id_evaluate, 1, self);
|
|
@@ -1306,6 +1365,7 @@ NORETURN(static void ca_mask_of_operands_read_only (void));
|
|
|
1306
1365
|
static void
|
|
1307
1366
|
ca_mask_of_operands_read_only (void)
|
|
1308
1367
|
{
|
|
1368
|
+
/* read-only-check: says it is the mask, which no lazy node owns */
|
|
1309
1369
|
rb_raise(rb_eRuntimeError, "the mask of a lazy operation is read-only");
|
|
1310
1370
|
}
|
|
1311
1371
|
|
|
@@ -1359,8 +1419,8 @@ ca_mask_of_operands_func_xfer_all (void *ap, void *data, int dir)
|
|
|
1359
1419
|
static VALUE
|
|
1360
1420
|
ca_mask_of_operands_fill_buffer (VALUE arg)
|
|
1361
1421
|
{
|
|
1362
|
-
|
|
1363
|
-
ca_mask_of_operands_func_xfer_all(
|
|
1422
|
+
void **a = (void **) arg;
|
|
1423
|
+
ca_mask_of_operands_func_xfer_all(a[0], a[1], CA_XFER_GET);
|
|
1364
1424
|
return Qnil;
|
|
1365
1425
|
}
|
|
1366
1426
|
|
|
@@ -1370,21 +1430,19 @@ static void
|
|
|
1370
1430
|
ca_mask_of_operands_func_attach (void *ap)
|
|
1371
1431
|
{
|
|
1372
1432
|
CAMaskOfOperands *ca = (CAMaskOfOperands *) ap;
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
rb_jump_tag(tag);
|
|
1380
|
-
}
|
|
1433
|
+
char *buf = ca_alloc_cells((CArray *) ca);
|
|
1434
|
+
void *a[2];
|
|
1435
|
+
a[0] = ca;
|
|
1436
|
+
a[1] = buf;
|
|
1437
|
+
ca_fill_or_xfree(buf, ca_mask_of_operands_fill_buffer, (VALUE) a);
|
|
1438
|
+
ca->ptr = buf;
|
|
1381
1439
|
}
|
|
1382
1440
|
|
|
1383
1441
|
static void
|
|
1384
1442
|
ca_mask_of_operands_func_allocate (void *ap)
|
|
1385
1443
|
{
|
|
1386
1444
|
CAMaskOfOperands *ca = (CAMaskOfOperands *) ap;
|
|
1387
|
-
ca->ptr =
|
|
1445
|
+
ca->ptr = ca_alloc_cells((CArray *) ca);
|
|
1388
1446
|
memset(ca->ptr, 0, ca->elements);
|
|
1389
1447
|
}
|
|
1390
1448
|
|
|
@@ -1454,7 +1512,12 @@ Init_ca_mask_of_operands (void)
|
|
|
1454
1512
|
|
|
1455
1513
|
An operand can be given a mask later unless it is broadcast from one
|
|
1456
1514
|
cell (a scalar the expression made from a literal), a value array, or a
|
|
1457
|
-
read-only entity. The shared mask is read-only, as the operation is.
|
|
1515
|
+
read-only entity. The shared mask is read-only, as the operation is.
|
|
1516
|
+
|
|
1517
|
+
With no masked operand the mask is still made when asked for (a view
|
|
1518
|
+
over the operation that masks cells of its own, such as a shift with
|
|
1519
|
+
fill UNDEF, needs one to lie over): it reads all false until an
|
|
1520
|
+
operand is given a mask. */
|
|
1458
1521
|
CArray *
|
|
1459
1522
|
ca_lazy_operation_mask (CArray *operation, int mode)
|
|
1460
1523
|
{
|
|
@@ -1475,10 +1538,6 @@ ca_lazy_operation_mask (CArray *operation, int mode)
|
|
|
1475
1538
|
}
|
|
1476
1539
|
}
|
|
1477
1540
|
|
|
1478
|
-
if ( n_masked == 0 ) {
|
|
1479
|
-
return NULL;
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
1541
|
if ( mode == CA_LAZY_MASK_OR && n_masked == 1 && n_open == 0
|
|
1483
1542
|
&& masked->elements == operation->elements ) {
|
|
1484
1543
|
CArray *shared = (CArray *) ca_refer_new(masked->mask, CA_BOOLEAN,
|