ndav 0.0.5 → 0.0.6
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/README.md +10 -2
- data/ext/ndav.c +78 -64
- data/lib/ndav/memory_viewable.rb +51 -18
- data/ndav.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz: '
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0194ddf5f19c3e973cb1ef947c125b598295db76eeca5998776612a592c40067'
|
|
4
|
+
data.tar.gz: 59f077dfdf2cdb48c675cde2e9addd7094a01417210fe28f8d786b93213ff8f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0ff36126d7192ace3dba90a706ec0f45032c590dd5085c0ca1e4166c6a6708b518ad7077ef9af54a6def14911e3a62c3bbda0e0d904cea0dd51ab46a9fb25dd
|
|
7
|
+
data.tar.gz: 97026defa9b86987290f46a5f04ae0133ca280a87bea04989954fb49055ccc230a5f33d5ac90a8d68c046a05dcfaa97c46c7d6f93fda90f4234f7bf074ae1293
|
data/README.md
CHANGED
|
@@ -57,7 +57,9 @@ It might not be difficult, but a little bit cumbersome. Additionally, Red Arrow
|
|
|
57
57
|
USAGE
|
|
58
58
|
-----
|
|
59
59
|
|
|
60
|
-
`ndav` gem is just a base library. You need to install bridges as well.
|
|
60
|
+
`ndav` gem is just a base library. You need to install bridges as well.
|
|
61
|
+
|
|
62
|
+
Say, assume you want to make conversions between Numo::NArray each other.
|
|
61
63
|
|
|
62
64
|
require "numo/narray"
|
|
63
65
|
require "ndav"
|
|
@@ -106,6 +108,12 @@ On the other hand, it also exports MemoryView. You can pass NDAV arrays *directl
|
|
|
106
108
|
samples = waveform.to_ndav
|
|
107
109
|
whisper.full(params, samples)
|
|
108
110
|
|
|
111
|
+
Additinally, classes that `include` `NDAV::MemoryViewable`, including `Numo::NArray`, `OnnxRuntime::OrtValue` and `Torch::Tensor`, export MemoryViews:
|
|
112
|
+
|
|
113
|
+
memory_view = Fiddle::MemoryView.new(numo)
|
|
114
|
+
memory_view = Fiddle::MemoryView.new(ort_value)
|
|
115
|
+
memory_view = Fiddle::MemoryView.new(torch_tensor)
|
|
116
|
+
|
|
109
117
|
### Notice On Memory Sharing ###
|
|
110
118
|
|
|
111
119
|
Notice that NDAV is just a memory view and libraries share a memory address. If you change source data destructively, it affects converted data.
|
|
@@ -147,7 +155,7 @@ Refer to existing bridge implementations listed above to create your bridge.
|
|
|
147
155
|
|
|
148
156
|
The points are:
|
|
149
157
|
|
|
150
|
-
* Implement `FromNDAV#from_ndav`, `ToNDAV#to_ndav`, {NDAV.register register} them, and `NDAV.from_your_data` and `NDAV#to_your_data` are automatically derived
|
|
158
|
+
* Implement `FromNDAV#from_ndav`, `MemoryViewable#ndav_descriptor`, optionally `ToNDAV#to_ndav`, {NDAV.register register} them, and `NDAV.from_your_data` and `NDAV#to_your_data` are automatically derived and the array become to able to export a MemoryView
|
|
151
159
|
* When initializing NDAV object from your object, use `lifetime` keyword argument for {NDAV#initialize} effectively to prevent Ruby from GCing your object, which would lead to a dangling pointer
|
|
152
160
|
* When initializing your object from NDAV object, keep NDAV object alive to prevent Ruby from GCing NDAV object, which would lead to a dangling pointer, [ndav-numo-narray][], for instance, embeds the NDAV object in an instance variable
|
|
153
161
|
|
data/ext/ndav.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#include <ruby/memory_view.h>
|
|
3
3
|
|
|
4
4
|
static ID id_ndav_validated_descriptor;
|
|
5
|
-
static VALUE
|
|
5
|
+
static VALUE sym_addr;
|
|
6
6
|
static VALUE sym_shape;
|
|
7
7
|
static VALUE sym_strides;
|
|
8
8
|
static VALUE sym_format;
|
|
@@ -31,8 +31,25 @@ fill_size_array(VALUE src, ssize_t *dest, ssize_t size)
|
|
|
31
31
|
return true;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
static void
|
|
35
|
+
release_memview_common(rb_memory_view_t *view)
|
|
36
|
+
{
|
|
37
|
+
if (view->shape) {
|
|
38
|
+
free((void *)view->shape);
|
|
39
|
+
view->shape = NULL;
|
|
40
|
+
}
|
|
41
|
+
if (view->strides) {
|
|
42
|
+
free((void *)view->strides);
|
|
43
|
+
view->strides = NULL;
|
|
44
|
+
}
|
|
45
|
+
if (view->sub_offsets) {
|
|
46
|
+
free((void *)view->sub_offsets);
|
|
47
|
+
view->sub_offsets = NULL;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
34
51
|
static bool
|
|
35
|
-
|
|
52
|
+
ndav_memory_viewable_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
36
53
|
{
|
|
37
54
|
bool row_major_requested = (flags & RUBY_MEMORY_VIEW_ROW_MAJOR) == RUBY_MEMORY_VIEW_ROW_MAJOR;
|
|
38
55
|
bool column_major_requested = (flags & RUBY_MEMORY_VIEW_COLUMN_MAJOR) == RUBY_MEMORY_VIEW_COLUMN_MAJOR;
|
|
@@ -42,8 +59,8 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
|
42
59
|
rb_warn("descriptor not Hash");
|
|
43
60
|
return false;
|
|
44
61
|
}
|
|
45
|
-
bool row_major_contiguous = rb_hash_aref(desc, sym_row_major_contiguous_p);
|
|
46
|
-
bool column_major_contiguous = rb_hash_aref(desc, sym_column_major_contiguous_p);
|
|
62
|
+
bool row_major_contiguous = RTEST(rb_hash_aref(desc, sym_row_major_contiguous_p));
|
|
63
|
+
bool column_major_contiguous = RTEST(rb_hash_aref(desc, sym_column_major_contiguous_p));
|
|
47
64
|
if (row_major_requested && column_major_requested) { // row-major OR column-major requested
|
|
48
65
|
if (!row_major_contiguous && !column_major_contiguous) {
|
|
49
66
|
return false;
|
|
@@ -58,7 +75,7 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
|
58
75
|
return false;
|
|
59
76
|
}
|
|
60
77
|
bool writable_requested = (flags & RUBY_MEMORY_VIEW_WRITABLE) == RUBY_MEMORY_VIEW_WRITABLE;
|
|
61
|
-
// TODO: Handle flags
|
|
78
|
+
// TODO: Handle other flags
|
|
62
79
|
|
|
63
80
|
VALUE readonly_v = rb_hash_aref(desc, sym_readonly_p);
|
|
64
81
|
bool readonly = NIL_P(readonly_v) || RTEST(readonly_v);
|
|
@@ -66,120 +83,112 @@ ndav_get_memory_view(const VALUE ndav, rb_memory_view_t *view, int flags)
|
|
|
66
83
|
rb_warn("not writable");
|
|
67
84
|
return false;
|
|
68
85
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
VALUE
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
VALUE byte_size_v = rb_hash_aref(desc, sym_byte_size);
|
|
87
|
+
ssize_t byte_size = NUM2SSIZET(byte_size_v);
|
|
88
|
+
VALUE addr = rb_hash_aref(desc, sym_addr);
|
|
89
|
+
rb_memory_view_t tmp = {0};
|
|
90
|
+
if (!rb_memory_view_init_as_byte_array(&tmp, ndav, NUM2PTR(addr), byte_size, readonly)) {
|
|
91
|
+
rb_warn("failed to initialize");
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
tmp.readonly = readonly;
|
|
95
|
+
tmp.obj = ndav;
|
|
74
96
|
// TODO: Commonalize
|
|
75
97
|
// TODO: Consider:
|
|
76
98
|
// * Use TypedData?
|
|
77
99
|
// * If so, calling attr readers at Ruby layer has performance disadvantage.
|
|
78
100
|
// * Freezing instance vars in #initialize and then embed them to TypedData may be a solution
|
|
79
101
|
VALUE item_size = rb_hash_aref(desc, sym_item_size);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
view->byte_size = NUM2SSIZET(byte_size);
|
|
102
|
+
tmp.item_size = NUM2SSIZET(item_size);
|
|
103
|
+
tmp.byte_size = byte_size;
|
|
83
104
|
VALUE ndim = rb_hash_aref(desc, sym_ndim);
|
|
84
|
-
|
|
105
|
+
tmp.ndim = NUM2SSIZET(ndim);
|
|
85
106
|
VALUE format = rb_hash_aref(desc, sym_format);
|
|
86
|
-
|
|
107
|
+
tmp.format = StringValueCStr(format);
|
|
87
108
|
|
|
88
109
|
// TODO: Commonalize
|
|
89
110
|
VALUE shape = rb_hash_aref(desc, sym_shape);
|
|
90
111
|
if (!RB_TYPE_P(shape, T_ARRAY)) {
|
|
91
|
-
|
|
112
|
+
release_memview_common(&tmp);
|
|
113
|
+
rb_warn("shape is not an array");
|
|
92
114
|
return false;
|
|
93
115
|
}
|
|
94
|
-
ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) *
|
|
116
|
+
ssize_t *view_shape = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
|
|
95
117
|
if (!view_shape) {
|
|
118
|
+
release_memview_common(&tmp);
|
|
96
119
|
return false;
|
|
97
120
|
}
|
|
98
|
-
if (!fill_size_array(shape, view_shape,
|
|
99
|
-
free(
|
|
121
|
+
if (!fill_size_array(shape, view_shape, tmp.ndim)) {
|
|
122
|
+
free(view_shape);
|
|
123
|
+
release_memview_common(&tmp);
|
|
100
124
|
return false;
|
|
101
125
|
}
|
|
102
|
-
|
|
126
|
+
tmp.shape = view_shape;
|
|
103
127
|
|
|
104
128
|
VALUE strides = rb_hash_aref(desc, sym_strides);
|
|
105
129
|
if (!RB_TYPE_P(strides, T_ARRAY)) {
|
|
106
|
-
|
|
107
|
-
|
|
130
|
+
release_memview_common(&tmp);
|
|
131
|
+
rb_warn("strides is not an array");
|
|
108
132
|
return false;
|
|
109
133
|
}
|
|
110
|
-
ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) *
|
|
134
|
+
ssize_t *view_strides = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
|
|
111
135
|
if (!view_strides) {
|
|
112
|
-
|
|
136
|
+
release_memview_common(&tmp);
|
|
113
137
|
return false;
|
|
114
138
|
}
|
|
115
|
-
if (!fill_size_array(strides, view_strides,
|
|
116
|
-
free(
|
|
117
|
-
|
|
139
|
+
if (!fill_size_array(strides, view_strides, tmp.ndim)) {
|
|
140
|
+
free(view_strides);
|
|
141
|
+
release_memview_common(&tmp);
|
|
118
142
|
return false;
|
|
119
143
|
}
|
|
120
|
-
|
|
144
|
+
tmp.strides = view_strides;
|
|
121
145
|
|
|
122
146
|
VALUE sub_offsets = rb_hash_aref(desc, sym_sub_offsets);
|
|
123
147
|
if (NIL_P(sub_offsets)) {
|
|
124
148
|
if (indirect_requested) {
|
|
149
|
+
release_memview_common(&tmp);
|
|
125
150
|
rb_warn("indirect requested but sub_offsets is NULL");
|
|
126
|
-
free((void *)view->shape);
|
|
127
|
-
free((void *)view->strides);
|
|
128
151
|
return false;
|
|
129
152
|
}
|
|
130
|
-
|
|
153
|
+
tmp.sub_offsets = NULL;
|
|
131
154
|
} else if (!RB_TYPE_P(sub_offsets, T_ARRAY)) {
|
|
155
|
+
release_memview_common(&tmp);
|
|
132
156
|
rb_warn("sub_offsets is not an array");
|
|
133
|
-
free((void *)view->shape);
|
|
134
|
-
free((void *)view->strides);
|
|
135
157
|
return false;
|
|
136
158
|
} else {
|
|
137
|
-
ssize_t *view_sub_offsets = (ssize_t *)malloc(sizeof(ssize_t) *
|
|
159
|
+
ssize_t *view_sub_offsets = (ssize_t *)malloc(sizeof(ssize_t) * tmp.ndim);
|
|
138
160
|
if (!view_sub_offsets) {
|
|
139
|
-
|
|
140
|
-
free((void *)view->strides);
|
|
161
|
+
release_memview_common(&tmp);
|
|
141
162
|
return false;
|
|
142
163
|
}
|
|
143
|
-
if (!fill_size_array(sub_offsets, view_sub_offsets,
|
|
144
|
-
free(
|
|
145
|
-
|
|
146
|
-
free((void *)view_sub_offsets);
|
|
164
|
+
if (!fill_size_array(sub_offsets, view_sub_offsets, tmp.ndim)) {
|
|
165
|
+
free(view_sub_offsets);
|
|
166
|
+
release_memview_common(&tmp);
|
|
147
167
|
return false;
|
|
148
168
|
}
|
|
149
|
-
|
|
169
|
+
tmp.sub_offsets = view_sub_offsets;
|
|
150
170
|
}
|
|
151
171
|
|
|
152
172
|
private_data_t *private_data = malloc(sizeof(private_data_t));
|
|
153
173
|
if (!private_data) {
|
|
154
|
-
|
|
155
|
-
free((void *)view->strides);
|
|
156
|
-
free((void *)view->sub_offsets);
|
|
174
|
+
release_memview_common(&tmp);
|
|
157
175
|
rb_warn("failed to alloc private_data");
|
|
158
176
|
return false;
|
|
159
177
|
}
|
|
160
178
|
private_data->descriptor = Qnil;
|
|
161
179
|
rb_gc_register_address(&private_data->descriptor);
|
|
162
180
|
private_data->descriptor = desc;
|
|
163
|
-
|
|
181
|
+
tmp.private_data = private_data;
|
|
182
|
+
|
|
183
|
+
*view = tmp;
|
|
164
184
|
|
|
165
185
|
return true;
|
|
166
186
|
}
|
|
167
187
|
|
|
168
188
|
static bool
|
|
169
|
-
|
|
189
|
+
ndav_memory_viewable_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
170
190
|
{
|
|
171
|
-
|
|
172
|
-
free((void *)view->shape);
|
|
173
|
-
view->shape = NULL;
|
|
174
|
-
}
|
|
175
|
-
if (view->strides) {
|
|
176
|
-
free((void *)view->strides);
|
|
177
|
-
view->strides = NULL;
|
|
178
|
-
}
|
|
179
|
-
if (view->sub_offsets) {
|
|
180
|
-
free((void *)view->sub_offsets);
|
|
181
|
-
view->sub_offsets = NULL;
|
|
182
|
-
}
|
|
191
|
+
release_memview_common(view);
|
|
183
192
|
if (view->private_data) {
|
|
184
193
|
private_data_t *private_data = (private_data_t *)view->private_data;
|
|
185
194
|
rb_gc_unregister_address(&private_data->descriptor);
|
|
@@ -191,16 +200,21 @@ ndav_release_memory_view(const VALUE ndav, rb_memory_view_t *view)
|
|
|
191
200
|
}
|
|
192
201
|
|
|
193
202
|
static bool
|
|
194
|
-
|
|
203
|
+
ndav_memory_viewable_memory_view_available_p(const VALUE obj)
|
|
195
204
|
{
|
|
196
205
|
VALUE descriptor = rb_funcall(obj, id_ndav_validated_descriptor, 0);
|
|
197
|
-
|
|
206
|
+
if (RB_TYPE_P(descriptor, T_HASH)) {
|
|
207
|
+
return true;
|
|
208
|
+
} else {
|
|
209
|
+
rb_warn("descriptor not Hash");
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
198
212
|
}
|
|
199
213
|
|
|
200
214
|
const struct rb_memory_view_entry ndav_view_entry = {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
215
|
+
ndav_memory_viewable_get_memory_view,
|
|
216
|
+
ndav_memory_viewable_release_memory_view,
|
|
217
|
+
ndav_memory_viewable_memory_view_available_p
|
|
204
218
|
};
|
|
205
219
|
|
|
206
220
|
static VALUE
|
|
@@ -218,7 +232,7 @@ void
|
|
|
218
232
|
Init_ndav(void)
|
|
219
233
|
{
|
|
220
234
|
id_ndav_validated_descriptor = rb_intern("ndav_validated_descriptor");
|
|
221
|
-
|
|
235
|
+
sym_addr = ID2SYM(rb_intern("addr"));
|
|
222
236
|
sym_shape = ID2SYM(rb_intern("shape"));
|
|
223
237
|
sym_strides = ID2SYM(rb_intern("strides"));
|
|
224
238
|
sym_format = ID2SYM(rb_intern("format"));
|
data/lib/ndav/memory_viewable.rb
CHANGED
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
class NDAV
|
|
2
|
+
# +include+ this module and define +#ndav_descriptor+ method in your class,
|
|
3
|
+
# and then the class exports a MemoryView.
|
|
4
|
+
#
|
|
5
|
+
# +#ndav_descriptor+'s arguments are flags of MemoryView including
|
|
6
|
+
# +simple+, +writable+, +format+, +multi_dimensional+, +strides+, +row_major+, +column_major+, +any_contiguous+, +indirect+.
|
|
7
|
+
# For the meaning of them, see MemoryView document.
|
|
8
|
+
#
|
|
9
|
+
# It must return a Hash whose keys includes:
|
|
10
|
+
#
|
|
11
|
+
# * +:data+: Required. Binary +String+, pointer address +Integer+ or +Fiddle::Pointer+. This is passed to +Fiddle::Pointer.to_ptr+, so should be valid for the method.
|
|
12
|
+
# * +:shape+: Required. See MemoryView document.
|
|
13
|
+
# * +:strides+: Required. See MemoryView document.
|
|
14
|
+
# * +:format+: Required. See MemoryView document.
|
|
15
|
+
# * +:byte_size+: Required. See MemoryView document.
|
|
16
|
+
# * +:readonly?+: Required. See MemoryView document.
|
|
17
|
+
# * +:sub_offsets+: Optional. See MemoryView document.
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# class YourClass
|
|
21
|
+
# include NDAV::MemoryViewable
|
|
22
|
+
# # :
|
|
23
|
+
# def ndav_descriptor(
|
|
24
|
+
# simple: true,
|
|
25
|
+
# writable: false,
|
|
26
|
+
# format: false,
|
|
27
|
+
# multi_dimensional: false,
|
|
28
|
+
# strides: false,
|
|
29
|
+
# row_major: false,
|
|
30
|
+
# column_major: false,
|
|
31
|
+
# any_contiguous: false,
|
|
32
|
+
# indirect: false
|
|
33
|
+
# )
|
|
34
|
+
# {
|
|
35
|
+
# data:,
|
|
36
|
+
# shape:,
|
|
37
|
+
# strides:,
|
|
38
|
+
# format:,
|
|
39
|
+
# byte_size:,
|
|
40
|
+
# readonly?:,
|
|
41
|
+
# sub_offsets:
|
|
42
|
+
# }
|
|
43
|
+
# end
|
|
44
|
+
# # :
|
|
45
|
+
# end
|
|
2
46
|
module MemoryViewable
|
|
3
47
|
class << self
|
|
4
48
|
def included(base)
|
|
@@ -8,34 +52,23 @@ class NDAV
|
|
|
8
52
|
|
|
9
53
|
private
|
|
10
54
|
|
|
11
|
-
# Overwrite this method or define each ndav_xxx method
|
|
12
|
-
def ndav_descriptor(simple: true, writable: false, format: false, multi_dimensional: false, strides: false, row_major: false, column_major: false, any_contiguous: false, indirect: false)
|
|
13
|
-
{
|
|
14
|
-
data: ndav_data,
|
|
15
|
-
shape: ndav_shape,
|
|
16
|
-
strides: ndav_strides,
|
|
17
|
-
format: ndav_format,
|
|
18
|
-
byte_size: ndav_byte_size,
|
|
19
|
-
readonly?: ndav_readonly?,
|
|
20
|
-
sub_offsets: ndav_sub_offsets
|
|
21
|
-
}
|
|
22
|
-
end
|
|
23
|
-
|
|
24
55
|
def ndav_validated_descriptor(flags = ::NDAV::Flags::FLAGS[:simple])
|
|
25
56
|
desc = ndav_descriptor(**NDAV::Flags.decode(flags)).to_h
|
|
26
|
-
unless desc.kind_of? Hash
|
|
27
|
-
warn "descriptor not Hash"
|
|
28
|
-
return false
|
|
29
|
-
end
|
|
30
57
|
[:data, :shape, :strides, :format, :byte_size, :readonly?].each do |key|
|
|
31
58
|
unless desc.key? key
|
|
32
59
|
warn ":#{key} not in descriptor"
|
|
33
60
|
return false
|
|
34
61
|
end
|
|
35
62
|
end
|
|
63
|
+
item_size = NDAV::ITEM_SIZES[desc[:format]]
|
|
64
|
+
unless desc[:shape].reduce(item_size, :*) == desc[:byte_size]
|
|
65
|
+
warn "item size from format and shape not match byte_size"
|
|
66
|
+
return false
|
|
67
|
+
end
|
|
36
68
|
desc.merge(
|
|
69
|
+
addr: ::Fiddle::Pointer.to_ptr(desc[:data]).to_i,
|
|
37
70
|
ndim: desc[:shape].length,
|
|
38
|
-
item_size
|
|
71
|
+
item_size:,
|
|
39
72
|
row_major_contiguous?: ::NDAV.row_major_contiguous?(**desc),
|
|
40
73
|
column_major_contiguous?: ::NDAV.column_major_contiguous?(**desc)
|
|
41
74
|
)
|
data/ndav.gemspec
CHANGED