carray-jit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/CHANGELOG.md +84 -0
  4. data/LICENSE +21 -0
  5. data/README.md +88 -0
  6. data/bin/carray-jit +194 -0
  7. data/carray-jit.gemspec +41 -0
  8. data/docs/00_Introduction.md +40 -0
  9. data/docs/01_GettingStarted.md +80 -0
  10. data/docs/02_KernelShapes.md +397 -0
  11. data/docs/03_SupportedFeatures.md +595 -0
  12. data/docs/04_Compiling.md +234 -0
  13. data/docs/05_DesignNotes.md +136 -0
  14. data/docs/06_Cheatsheet.md +177 -0
  15. data/examples/README.md +56 -0
  16. data/examples/applications/game_of_life.rb +161 -0
  17. data/examples/applications/heat_equation.rb +117 -0
  18. data/examples/applications/kepler.rb +178 -0
  19. data/examples/applications/mandelbrot.rb +151 -0
  20. data/examples/applications/moving_average.rb +124 -0
  21. data/examples/applications/partial_sums.rb +141 -0
  22. data/examples/applications/point_cloud.rb +110 -0
  23. data/examples/applications/quicksort.rb +118 -0
  24. data/examples/applications/recursion.rb +121 -0
  25. data/examples/applications/relaxation.rb +115 -0
  26. data/examples/applications/sensor_gaps.rb +118 -0
  27. data/examples/applications/sieve.rb +95 -0
  28. data/examples/applications/sobel_edges.rb +80 -0
  29. data/examples/features/01_element_wise.rb +69 -0
  30. data/examples/features/02_stencil.rb +40 -0
  31. data/examples/features/03_recurrence.rb +50 -0
  32. data/examples/features/04_thomas.rb +81 -0
  33. data/examples/features/05_reduction.rb +90 -0
  34. data/examples/features/06_jit_contract.rb +58 -0
  35. data/examples/features/07_masks.rb +55 -0
  36. data/examples/features/08_views.rb +46 -0
  37. data/examples/features/09_inspecting.rb +55 -0
  38. data/examples/features/10_complex.rb +107 -0
  39. data/examples/features/11_c_functions.rb +260 -0
  40. data/examples/features/12_sweep.rb +139 -0
  41. data/examples/features/13_cscalar.rb +80 -0
  42. data/examples/features/14_stencil_window.rb +106 -0
  43. data/examples/features/15_loops.rb +148 -0
  44. data/examples/features/16_raising.rb +69 -0
  45. data/ext/carray_jit_access/carray_jit_access.c +460 -0
  46. data/ext/carray_jit_access/extconf.rb +8 -0
  47. data/lib/carray/jit/analyzer.rb +1847 -0
  48. data/lib/carray/jit/block_reader.rb +139 -0
  49. data/lib/carray/jit/c_function.rb +777 -0
  50. data/lib/carray/jit/c_generator.rb +2305 -0
  51. data/lib/carray/jit/compiler.rb +468 -0
  52. data/lib/carray/jit/errors.rb +37 -0
  53. data/lib/carray/jit/expression.rb +202 -0
  54. data/lib/carray/jit/kernel.rb +509 -0
  55. data/lib/carray/jit/node.rb +573 -0
  56. data/lib/carray/jit/sweep.rb +97 -0
  57. data/lib/carray/jit/type_assignment.rb +811 -0
  58. data/lib/carray/jit/version.rb +5 -0
  59. data/lib/carray/jit.rb +1210 -0
  60. metadata +139 -0
@@ -0,0 +1,460 @@
1
+ #include <ruby.h>
2
+ #include "carray.h"
3
+
4
+ /*
5
+ * Address bases for JIT kernels.
6
+ *
7
+ * A generated kernel addresses cells itself -- it reads a[i-1] and writes
8
+ * a[i] -- so what it needs from CArray is not element delivery but an
9
+ * addressing basis: a pointer, a byte offset, and one byte stride per axis.
10
+ * That is why this does not sit on the kernel iterator (per-cell/per-slab
11
+ * delivery, and no N-ary form) or on the sweep ELEMENT family (which
12
+ * flattens the array and cannot recover the axis structure a stencil needs).
13
+ *
14
+ * Arrays are classified in the order the public predicates suggest:
15
+ *
16
+ * 1. ca_is_entity -> the buffer is already the basis
17
+ * 2. ca_is_stride_family -> ca_stride_compose_to_root folds the whole
18
+ * view chain into root + base + strides, so a
19
+ * transpose or a column slice is addressed in
20
+ * place, with no gather and no scatter
21
+ * 3. otherwise -> ca_xfer_stride moves only the box the kernel
22
+ * actually touches -- the loop range grown by
23
+ * how far the kernel reaches, per array and per
24
+ * axis -- into a packed buffer, and writes that
25
+ * box back
26
+ *
27
+ * Tier 3 deliberately never calls ca_attach on the view. A whole-view
28
+ * materialise costs the same whether the kernel touches ten cells or ten
29
+ * million: measured on a four-million-element gather view, ca_attach was
30
+ * 2.7 ms regardless, while the region transfer was 0.001 ms for a hundred
31
+ * cells and 2.3 ms for a million. A cost that does not scale with the work
32
+ * is a cost the caller cannot reason about, and hiding one behind a JIT
33
+ * would make its promise meaningless. What tier 3 does cost is proportional
34
+ * to what the kernel asked to touch.
35
+ */
36
+
37
+ #define TIER_ENTITY 1
38
+ #define TIER_STRIDE 2
39
+ #define TIER_ATTACH 3
40
+
41
+ /* Slot layout: slot i is array i, slot count + i is that array's mask.
42
+ A mask is a CArray of the same shape as its parent and, for a view, the
43
+ same kind of view -- a CABlock's mask is a CABlockMask -- so it is opened
44
+ by exactly the same tier logic as the data. */
45
+ typedef struct {
46
+ int count;
47
+ int slots;
48
+ VALUE arrays;
49
+ CArray **carrays;
50
+ CArray **roots;
51
+ int *tier;
52
+ int *writable;
53
+ int *attached_root;
54
+ char **region; /* tier 3 packed buffer, NULL otherwise */
55
+ ca_size_t *region_start; /* count * CA_RANK_MAX */
56
+ ca_size_t *region_count;
57
+ VALUE bases;
58
+ VALUE box_starts; /* per array, per axis; nil for "all of it" */
59
+ VALUE box_counts;
60
+ } open_state;
61
+
62
+ /* The view's own row-major byte layout, which is the address space
63
+ ca_xfer_stride describes a region in. */
64
+ static void
65
+ native_steps (CArray *ca, ca_size_t *steps)
66
+ {
67
+ ca_size_t step = ca->bytes;
68
+ int8_t k;
69
+ for ( k = ca->ndim - 1; k >= 0; k-- ) {
70
+ steps[k] = step;
71
+ step *= ca->dim[k];
72
+ }
73
+ }
74
+
75
+ /* Checks one array's box description. Run for every array, whatever tier it
76
+ lands in, so that the same call is refused the same way regardless of what
77
+ the array turns out to be -- and because this is a C extension, where a
78
+ wrong type has to be a message and not a crash. */
79
+ static void
80
+ verify_box (VALUE box_starts, VALUE box_counts, int index, CArray *ca)
81
+ {
82
+ VALUE starts, counts;
83
+ if ( NIL_P(box_starts) ) return;
84
+ starts = rb_ary_entry(box_starts, index);
85
+ counts = rb_ary_entry(box_counts, index);
86
+ if ( NIL_P(starts) && NIL_P(counts) ) return;
87
+ Check_Type(starts, T_ARRAY);
88
+ Check_Type(counts, T_ARRAY);
89
+ if ( RARRAY_LEN(starts) != ca->ndim || RARRAY_LEN(counts) != ca->ndim ) {
90
+ rb_raise(rb_eArgError,
91
+ "a region is described by one start and one count per axis; "
92
+ "this array has %d", (int) ca->ndim);
93
+ }
94
+ }
95
+
96
+ /* Reads one array's box out of the Ruby-side description, defaulting to the
97
+ whole array. Its shape was checked by verify_box. */
98
+ static void
99
+ read_box (open_state *state, int index, CArray *ca,
100
+ ca_size_t *starts, ca_size_t *counts)
101
+ {
102
+ VALUE per_array_start = Qnil, per_array_count = Qnil;
103
+ int8_t k;
104
+
105
+ if ( ! NIL_P(state->box_starts) ) {
106
+ per_array_start = rb_ary_entry(state->box_starts, index);
107
+ per_array_count = rb_ary_entry(state->box_counts, index);
108
+ }
109
+
110
+ for ( k = 0; k < ca->ndim; k++ ) {
111
+ if ( NIL_P(per_array_start) ) {
112
+ starts[k] = 0;
113
+ counts[k] = ca->dim[k];
114
+ } else {
115
+ starts[k] = NUM2LL(rb_ary_entry(per_array_start, k));
116
+ counts[k] = NUM2LL(rb_ary_entry(per_array_count, k));
117
+ }
118
+ if ( starts[k] < 0 || counts[k] < 0 || starts[k] + counts[k] > ca->dim[k] ) {
119
+ rb_raise(rb_eArgError,
120
+ "the requested region falls outside the array on axis %d", (int) k);
121
+ }
122
+ }
123
+ }
124
+
125
+ static void
126
+ row_major_strides (CArray *ca, ca_size_t *strides)
127
+ {
128
+ ca_size_t step = ca->bytes;
129
+ int8_t k;
130
+ for ( k = ca->ndim - 1; k >= 0; k-- ) {
131
+ strides[k] = step;
132
+ step *= ca->dim[k];
133
+ }
134
+ }
135
+
136
+ static VALUE
137
+ size_array (ca_size_t *values, int8_t count)
138
+ {
139
+ VALUE list = rb_ary_new_capa(count);
140
+ int8_t k;
141
+ for ( k = 0; k < count; k++ ) {
142
+ rb_ary_push(list, LL2NUM((long long) values[k]));
143
+ }
144
+ return list;
145
+ }
146
+
147
+ /* Refuses what a generated kernel cannot express, rather than letting it
148
+ produce quietly wrong numbers. */
149
+ static void
150
+ verify_usable (VALUE object, CArray *ca, int writable)
151
+ {
152
+ if ( ca->data_type == CA_OBJECT ) {
153
+ rb_raise(rb_eArgError, "object arrays hold Ruby values, not numbers");
154
+ }
155
+ if ( writable && ca_is_readonly(ca) ) {
156
+ rb_raise(rb_eRuntimeError, "%"PRIsVALUE" is read-only",
157
+ rb_obj_class(object));
158
+ }
159
+ }
160
+
161
+ /* The stride tier addresses the fold's root directly, which is only sound
162
+ when that root owns its memory. ca_stride_compose_to_root stops at the
163
+ first thing it cannot fold through, and that need not be an entity: a
164
+ CARefer over a gather view (`whole[whole >= 0].reshape(4, 4)`) folds one
165
+ step and lands on the CASelect. Attaching a root like that materialises a
166
+ temporary, and detaching it throws the kernel's writes away -- silently.
167
+ So a fold that does not reach an entity is not the stride tier; the box
168
+ transfer handles it, and moves only the cells the kernel asked for. */
169
+ static int
170
+ folds_to_an_entity (CArray *ca)
171
+ {
172
+ CArray *root;
173
+ ca_size_t strides[CA_RANK_MAX];
174
+ ca_size_t base = 0;
175
+ ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
176
+ return ca_is_entity(root);
177
+ }
178
+
179
+ static int
180
+ tier_for (CArray *ca)
181
+ {
182
+ if ( ca_is_entity(ca) ) return TIER_ENTITY;
183
+ if ( ca_is_stride_family(ca) && folds_to_an_entity(ca) ) return TIER_STRIDE;
184
+ return TIER_ATTACH;
185
+ }
186
+
187
+ static VALUE
188
+ basis_for (open_state *state, int index)
189
+ {
190
+ CArray *ca = state->carrays[index];
191
+ ca_size_t strides[CA_RANK_MAX];
192
+ ca_size_t base = 0;
193
+ char *pointer;
194
+ VALUE result;
195
+
196
+ switch ( state->tier[index] ) {
197
+ case TIER_ENTITY: {
198
+ CArray *root = ca;
199
+ ca_attach(root);
200
+ state->roots[index] = root;
201
+ state->attached_root[index] = 1;
202
+ row_major_strides(ca, strides);
203
+ pointer = ca->ptr;
204
+ break;
205
+ }
206
+
207
+ case TIER_STRIDE: {
208
+ CArray *root;
209
+ ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
210
+ /* A view that reinterprets the element size -- refer(CA_INT32, ...) over
211
+ a float64 array -- gets a mask of its own shape, but one mask cell of
212
+ it covers a fraction of a parent cell, so writing cell i's mask also
213
+ marks its neighbour. A per-cell kernel writes cells independently and
214
+ cannot express that. */
215
+ if ( ca->mask && ca->bytes != root->bytes ) {
216
+ rb_raise(rb_eArgError,
217
+ "%"PRIsVALUE" reinterprets the element size and carries a mask; "
218
+ "its mask cells do not map one to one onto the parent's",
219
+ rb_obj_class(rb_ary_entry(state->arrays, index)));
220
+ }
221
+ ca_attach(root);
222
+ state->roots[index] = root;
223
+ state->attached_root[index] = 1;
224
+ pointer = root->ptr + base;
225
+ break;
226
+ }
227
+
228
+ default: {
229
+ /* Only the requested box crosses, never the whole view. */
230
+ ca_size_t starts[CA_RANK_MAX], counts[CA_RANK_MAX], steps[CA_RANK_MAX];
231
+ ca_size_t elements = 1, shift = 0, step;
232
+ int8_t k;
233
+ char *buffer;
234
+
235
+ native_steps(ca, steps);
236
+ read_box(state, index, ca, starts, counts);
237
+ for ( k = 0; k < ca->ndim; k++ ) elements *= counts[k];
238
+
239
+ /* ca_xfer_stride packs the box row-major, so the buffer's strides come
240
+ from the box's own extents, not the view's. */
241
+ step = ca->bytes;
242
+ for ( k = ca->ndim - 1; k >= 0; k-- ) {
243
+ strides[k] = step;
244
+ step *= counts[k];
245
+ }
246
+
247
+ buffer = ALLOC_N(char, (elements > 0 ? elements : 1) * ca->bytes);
248
+ if ( elements > 0 ) {
249
+ ca_xfer_stride(ca, starts, counts, steps, buffer, CA_XFER_GET);
250
+ }
251
+
252
+ state->region[index] = buffer;
253
+ for ( k = 0; k < ca->ndim; k++ ) {
254
+ state->region_start[index * CA_RANK_MAX + k] = starts[k];
255
+ state->region_count[index * CA_RANK_MAX + k] = counts[k];
256
+ shift += starts[k] * strides[k];
257
+ }
258
+ /* Shifted so that the box's first cell lands on buffer[0], the way a
259
+ view's base_offset shifts its parent's pointer. */
260
+ pointer = buffer - shift;
261
+ break;
262
+ }
263
+ }
264
+
265
+ result = rb_hash_new();
266
+ rb_hash_aset(result, ID2SYM(rb_intern("tier")), INT2NUM(state->tier[index]));
267
+ rb_hash_aset(result, ID2SYM(rb_intern("pointer")),
268
+ ULL2NUM((unsigned long long)(uintptr_t) pointer));
269
+ rb_hash_aset(result, ID2SYM(rb_intern("strides")), size_array(strides, ca->ndim));
270
+ rb_hash_aset(result, ID2SYM(rb_intern("dim")), size_array(ca->dim, ca->ndim));
271
+ rb_hash_aset(result, ID2SYM(rb_intern("bytes")), LL2NUM((long long) ca->bytes));
272
+ rb_hash_aset(result, ID2SYM(rb_intern("data_type")), INT2NUM(ca->data_type));
273
+ rb_hash_aset(result, ID2SYM(rb_intern("writable")),
274
+ state->writable[index] ? Qtrue : Qfalse);
275
+ return result;
276
+ }
277
+
278
+ /* Each array's basis, with its mask's basis folded in under :mask_pointer
279
+ and :mask_strides (nil when the array carries no mask). */
280
+ static VALUE
281
+ open_body (VALUE argument);
282
+
283
+ static VALUE
284
+ open_body (VALUE argument)
285
+ {
286
+ open_state *state = (open_state *) argument;
287
+ int i;
288
+ for ( i = 0; i < state->count; i++ ) {
289
+ VALUE basis = basis_for(state, i);
290
+ if ( state->carrays[state->count + i] ) {
291
+ VALUE mask = basis_for(state, state->count + i);
292
+ rb_hash_aset(basis, ID2SYM(rb_intern("mask_pointer")),
293
+ rb_hash_aref(mask, ID2SYM(rb_intern("pointer"))));
294
+ rb_hash_aset(basis, ID2SYM(rb_intern("mask_strides")),
295
+ rb_hash_aref(mask, ID2SYM(rb_intern("strides"))));
296
+ } else {
297
+ rb_hash_aset(basis, ID2SYM(rb_intern("mask_pointer")), Qnil);
298
+ rb_hash_aset(basis, ID2SYM(rb_intern("mask_strides")), Qnil);
299
+ }
300
+ rb_ary_push(state->bases, basis);
301
+ }
302
+ return rb_yield(state->bases);
303
+ }
304
+
305
+ /* Closes in reverse order, and runs whether or not the kernel raised. */
306
+ static VALUE
307
+ open_ensure (VALUE argument)
308
+ {
309
+ open_state *state = (open_state *) argument;
310
+ int i;
311
+ for ( i = state->slots - 1; i >= 0; i-- ) {
312
+ CArray *ca = state->carrays[i];
313
+ if ( ca == NULL ) continue;
314
+ /* A tier-1 or tier-2 basis addresses the root's own memory, so a write is
315
+ already where it belongs. Only a region buffer has to be sent back. */
316
+ if ( state->region[i] ) {
317
+ ca_size_t elements = 1;
318
+ int8_t k;
319
+ for ( k = 0; k < ca->ndim; k++ ) {
320
+ elements *= state->region_count[i * CA_RANK_MAX + k];
321
+ }
322
+ if ( state->writable[i] && elements > 0 ) {
323
+ ca_size_t steps[CA_RANK_MAX];
324
+ native_steps(ca, steps);
325
+ ca_xfer_stride(ca, &state->region_start[i * CA_RANK_MAX],
326
+ &state->region_count[i * CA_RANK_MAX],
327
+ steps, state->region[i], CA_XFER_PUT);
328
+ }
329
+ xfree(state->region[i]);
330
+ }
331
+ if ( state->attached_root[i] ) {
332
+ ca_detach(state->roots[i]);
333
+ }
334
+ }
335
+ xfree(state->carrays);
336
+ xfree(state->roots);
337
+ xfree(state->tier);
338
+ xfree(state->writable);
339
+ xfree(state->attached_root);
340
+ xfree(state->region);
341
+ xfree(state->region_start);
342
+ xfree(state->region_count);
343
+ return Qnil;
344
+ }
345
+
346
+ /*
347
+ * Opens every array, yields one basis hash per array, and closes them all
348
+ * on the way out -- including when the block raises.
349
+ */
350
+ static VALUE
351
+ access_open (int argc, VALUE *argv, VALUE module)
352
+ {
353
+ VALUE arrays, writable_flags, box_start, box_count;
354
+ open_state state;
355
+ int i;
356
+
357
+ rb_scan_args(argc, argv, "22", &arrays, &writable_flags, &box_start, &box_count);
358
+ Check_Type(arrays, T_ARRAY);
359
+ Check_Type(writable_flags, T_ARRAY);
360
+ if ( NIL_P(box_start) != NIL_P(box_count) ) {
361
+ rb_raise(rb_eArgError, "a region needs both starts and counts");
362
+ }
363
+ if ( ! NIL_P(box_start) ) {
364
+ Check_Type(box_start, T_ARRAY);
365
+ Check_Type(box_count, T_ARRAY);
366
+ if ( RARRAY_LEN(box_start) != RARRAY_LEN(arrays) ||
367
+ RARRAY_LEN(box_count) != RARRAY_LEN(arrays) ) {
368
+ rb_raise(rb_eArgError, "one region per array is required");
369
+ }
370
+ }
371
+ if ( RARRAY_LEN(arrays) != RARRAY_LEN(writable_flags) ) {
372
+ rb_raise(rb_eArgError, "one writable flag per array is required");
373
+ }
374
+
375
+ state.count = (int) RARRAY_LEN(arrays);
376
+ state.slots = state.count * 2;
377
+ state.arrays = arrays;
378
+ state.bases = rb_ary_new_capa(state.count);
379
+ state.carrays = ALLOC_N(CArray *, state.slots + 1);
380
+ state.roots = ALLOC_N(CArray *, state.slots + 1);
381
+ state.tier = ALLOC_N(int, state.slots + 1);
382
+ state.writable = ALLOC_N(int, state.slots + 1);
383
+ state.attached_root = ALLOC_N(int, state.slots + 1);
384
+ state.region = ALLOC_N(char *, state.slots + 1);
385
+ state.region_start = ALLOC_N(ca_size_t, (state.slots + 1) * CA_RANK_MAX);
386
+ state.region_count = ALLOC_N(ca_size_t, (state.slots + 1) * CA_RANK_MAX);
387
+ state.box_starts = box_start;
388
+ state.box_counts = box_count;
389
+
390
+ for ( i = 0; i < state.slots; i++ ) {
391
+ state.carrays[i] = NULL;
392
+ state.roots[i] = NULL;
393
+ state.writable[i] = 0;
394
+ state.attached_root[i] = 0;
395
+ state.region[i] = NULL;
396
+ memset(&state.region_start[i * CA_RANK_MAX], 0,
397
+ sizeof(ca_size_t) * CA_RANK_MAX);
398
+ memset(&state.region_count[i * CA_RANK_MAX], 0,
399
+ sizeof(ca_size_t) * CA_RANK_MAX);
400
+ }
401
+
402
+ for ( i = 0; i < state.count; i++ ) {
403
+ VALUE object = rb_ary_entry(arrays, i);
404
+ CArray *ca;
405
+ GetCArray(object, ca);
406
+ state.carrays[i] = ca;
407
+ state.writable[i] = RTEST(rb_ary_entry(writable_flags, i));
408
+ verify_usable(object, ca, state.writable[i]);
409
+ verify_box(box_start, box_count, i, ca);
410
+ state.tier[i] = tier_for(ca);
411
+
412
+ if ( ca->mask ) {
413
+ CArray *mask = ca->mask;
414
+ state.carrays[state.count + i] = mask;
415
+ state.writable[state.count + i] = state.writable[i];
416
+ state.tier[state.count + i] = tier_for(mask);
417
+ }
418
+ }
419
+
420
+ return rb_ensure(open_body, (VALUE) &state, open_ensure, (VALUE) &state);
421
+ }
422
+
423
+ /* Reports how an array would be opened, without opening it. */
424
+ static VALUE
425
+ access_classify (VALUE module, VALUE object)
426
+ {
427
+ CArray *ca;
428
+ VALUE result;
429
+ int tier;
430
+
431
+ GetCArray(object, ca);
432
+ tier = tier_for(ca);
433
+
434
+ result = rb_hash_new();
435
+ rb_hash_aset(result, ID2SYM(rb_intern("tier")), INT2NUM(tier));
436
+ rb_hash_aset(result, ID2SYM(rb_intern("entity")), ca_is_entity(ca) ? Qtrue : Qfalse);
437
+ rb_hash_aset(result, ID2SYM(rb_intern("stride_family")),
438
+ ca_is_stride_family(ca) ? Qtrue : Qfalse);
439
+ rb_hash_aset(result, ID2SYM(rb_intern("read_only")), ca_is_readonly(ca) ? Qtrue : Qfalse);
440
+ rb_hash_aset(result, ID2SYM(rb_intern("masked")), ca_has_mask(ca) ? Qtrue : Qfalse);
441
+ rb_hash_aset(result, ID2SYM(rb_intern("dim")), size_array(ca->dim, ca->ndim));
442
+ rb_hash_aset(result, ID2SYM(rb_intern("bytes")), LL2NUM((long long) ca->bytes));
443
+ rb_hash_aset(result, ID2SYM(rb_intern("data_type")), INT2NUM(ca->data_type));
444
+ return result;
445
+ }
446
+
447
+ void
448
+ Init_access (void)
449
+ {
450
+ VALUE cCArray = rb_const_get(rb_cObject, rb_intern("CArray"));
451
+ VALUE mJIT = rb_define_module_under(cCArray, "JIT");
452
+ VALUE mAccess = rb_define_module_under(mJIT, "Access");
453
+
454
+ rb_define_singleton_method(mAccess, "open", access_open, -1);
455
+ rb_define_singleton_method(mAccess, "classify", access_classify, 1);
456
+
457
+ rb_define_const(mAccess, "TIER_ENTITY", INT2NUM(TIER_ENTITY));
458
+ rb_define_const(mAccess, "TIER_STRIDE", INT2NUM(TIER_STRIDE));
459
+ rb_define_const(mAccess, "TIER_ATTACH", INT2NUM(TIER_ATTACH));
460
+ }
@@ -0,0 +1,8 @@
1
+ require "mkmf"
2
+ require "carray/mkmf"
3
+
4
+ # Only the public carray.h surface is used: the query predicates, the
5
+ # CAStride compose-fold, and the attach lifecycle.
6
+ if have_carray()
7
+ create_makefile("carray/jit/access")
8
+ end