onnxruntime 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a31036492f6ad4f0ab17a2534a69f17ca05058267447089868f2ac5bf2c5e79
4
- data.tar.gz: 6cd8be229992a0ea4c9fdb8529a229e31a777321e0971f0123bc2680ca828be3
3
+ metadata.gz: dc2115e3b32ec7d1d0ab2da64edfb5bf2ebf24ecc6ad705d4a53ae4793e60412
4
+ data.tar.gz: 5e53efd5de12ed5ac06a7e4472c8ee043ffbbba9c82b5f49e340f6a70a4dfcdf
5
5
  SHA512:
6
- metadata.gz: 9bb61d56c9c4ddb17e0e085381226ab0c91e72de592deb6519bf6840ffb1a00eaa0fb9382eb0cba1d563165fb9d0528034da1f2ea9b6b3cb76b780813750ad21
7
- data.tar.gz: b94b0b2772728ead241a0d16c3ca2db099cbf7ab6f3994384e3107f69d9aa2cdaa31ed4ba08bd4d3d9fae2eef0b13ea84aa70823be0ff2d24b921e8fb390246b
6
+ metadata.gz: 93f83646d23298213b971ea7462ce4e5cc970c49d7572b646a6f8003b05689a5a232a3acc05b9cacfbabf65534c046d687eecc80fbf5583b2691391d30b54872
7
+ data.tar.gz: fc0349312d70944a2169302e8b9f1f70f255e29b60c523f0ba1a688ac162cc230636f9ef333d6ac032d855d9387d88234181a69edade6407bde027050972a2da
@@ -1,3 +1,29 @@
1
+ ## 0.5.0 (2020-10-01)
2
+
3
+ - Updated ONNX Runtime to 1.5.1
4
+ - OpenMP is now required on Mac
5
+ - Fixed `mul_1.onnx` example
6
+
7
+ ## 0.4.0 (2020-07-20)
8
+
9
+ - Updated ONNX Runtime to 1.4.0
10
+ - Added `providers` method
11
+ - Fixed errors on Windows
12
+
13
+ ## 0.3.3 (2020-06-17)
14
+
15
+ - Fixed segmentation fault on exit on Linux
16
+
17
+ ## 0.3.2 (2020-06-16)
18
+
19
+ - Fixed error with FFI 1.13.0+
20
+ - Added friendly graph optimization levels
21
+
22
+ ## 0.3.1 (2020-05-18)
23
+
24
+ - Updated ONNX Runtime to 1.3.0
25
+ - Added `custom_metadata_map` to model metadata
26
+
1
27
  ## 0.3.0 (2020-03-11)
2
28
 
3
29
  - Updated ONNX Runtime to 1.2.0
@@ -1,23 +1,22 @@
1
- Copyright (c) 2019-2020 Andrew Kane
2
- Datasets Copyright (c) Microsoft Corporation
3
-
4
1
  MIT License
5
2
 
6
- Permission is hereby granted, free of charge, to any person obtaining
7
- a copy of this software and associated documentation files (the
8
- "Software"), to deal in the Software without restriction, including
9
- without limitation the rights to use, copy, modify, merge, publish,
10
- distribute, sublicense, and/or sell copies of the Software, and to
11
- permit persons to whom the Software is furnished to do so, subject to
12
- the following conditions:
3
+ Copyright (c) 2018 Microsoft Corporation
4
+ Copyright (c) 2019-2020 Andrew Kane
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
13
12
 
14
- The above copyright notice and this permission notice shall be
15
- included in all copies or substantial portions of the Software.
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
16
15
 
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
data/README.md CHANGED
@@ -14,6 +14,12 @@ Add this line to your application’s Gemfile:
14
14
  gem 'onnxruntime'
15
15
  ```
16
16
 
17
+ On Mac, also install OpenMP:
18
+
19
+ ```sh
20
+ brew install libomp
21
+ ```
22
+
17
23
  ## Getting Started
18
24
 
19
25
  Load a model and make predictions
@@ -63,8 +69,8 @@ OnnxRuntime::Model.new(path_or_bytes, {
63
69
  enable_cpu_mem_arena: true,
64
70
  enable_mem_pattern: true,
65
71
  enable_profiling: false,
66
- execution_mode: :sequential,
67
- graph_optimization_level: nil,
72
+ execution_mode: :sequential, # :sequential or :parallel
73
+ graph_optimization_level: nil, # :none, :basic, :extended, or :all
68
74
  inter_op_num_threads: nil,
69
75
  intra_op_num_threads: nil,
70
76
  log_severity_level: 2,
@@ -19,7 +19,7 @@ module OnnxRuntime
19
19
  self.ffi_lib = [vendor_lib]
20
20
 
21
21
  def self.lib_version
22
- FFI.OrtGetApiBase[:GetVersionString].call
22
+ FFI.OrtGetApiBase[:GetVersionString].call.read_string
23
23
  end
24
24
 
25
25
  # friendlier error message
@@ -3,10 +3,13 @@ module OnnxRuntime
3
3
  extend ::FFI::Library
4
4
 
5
5
  begin
6
- ffi_lib Array(OnnxRuntime.ffi_lib)
6
+ ffi_lib OnnxRuntime.ffi_lib
7
7
  rescue LoadError => e
8
- raise e if ENV["ONNXRUNTIME_DEBUG"]
9
- raise LoadError, "Could not find ONNX Runtime"
8
+ if e.message.include?("Library not loaded: /usr/local/opt/libomp/lib/libomp.dylib") && e.message.include?("Reason: image not found")
9
+ raise LoadError, "OpenMP not found. Run `brew install libomp`"
10
+ else
11
+ raise e
12
+ end
10
13
  end
11
14
 
12
15
  # https://github.com/microsoft/onnxruntime/blob/master/include/onnxruntime/core/session/onnxruntime_c_api.h
@@ -20,19 +23,19 @@ module OnnxRuntime
20
23
  layout \
21
24
  :CreateStatus, callback(%i[int string], :pointer),
22
25
  :GetErrorCode, callback(%i[pointer], :pointer),
23
- :GetErrorMessage, callback(%i[pointer], :string),
26
+ :GetErrorMessage, callback(%i[pointer], :pointer),
24
27
  :CreateEnv, callback(%i[int string pointer], :pointer),
25
28
  :CreateEnvWithCustomLogger, callback(%i[], :pointer),
26
29
  :EnableTelemetryEvents, callback(%i[pointer], :pointer),
27
30
  :DisableTelemetryEvents, callback(%i[pointer], :pointer),
28
- :CreateSession, callback(%i[pointer string pointer pointer], :pointer),
31
+ :CreateSession, callback(%i[pointer pointer pointer pointer], :pointer),
29
32
  :CreateSessionFromArray, callback(%i[pointer pointer size_t pointer pointer], :pointer),
30
33
  :Run, callback(%i[pointer pointer pointer pointer size_t pointer size_t pointer], :pointer),
31
34
  :CreateSessionOptions, callback(%i[pointer], :pointer),
32
- :SetOptimizedModelFilePath, callback(%i[pointer string], :pointer),
35
+ :SetOptimizedModelFilePath, callback(%i[pointer pointer], :pointer),
33
36
  :CloneSessionOptions, callback(%i[], :pointer),
34
37
  :SetSessionExecutionMode, callback(%i[], :pointer),
35
- :EnableProfiling, callback(%i[pointer string], :pointer),
38
+ :EnableProfiling, callback(%i[pointer pointer], :pointer),
36
39
  :DisableProfiling, callback(%i[pointer], :pointer),
37
40
  :EnableMemPattern, callback(%i[pointer], :pointer),
38
41
  :DisableMemPattern, callback(%i[pointer], :pointer),
@@ -136,7 +139,15 @@ module OnnxRuntime
136
139
  :ModelMetadataGetDescription, callback(%i[pointer pointer pointer], :pointer),
137
140
  :ModelMetadataLookupCustomMetadataMap, callback(%i[pointer pointer pointer pointer], :pointer),
138
141
  :ModelMetadataGetVersion, callback(%i[pointer pointer], :pointer),
139
- :ReleaseModelMetadata, callback(%i[pointer], :void)
142
+ :ReleaseModelMetadata, callback(%i[pointer], :void),
143
+ :CreateEnvWithGlobalThreadPools, callback(%i[], :pointer),
144
+ :DisablePerSessionThreads, callback(%i[], :pointer),
145
+ :CreateThreadingOptions, callback(%i[], :pointer),
146
+ :ReleaseThreadingOptions, callback(%i[], :pointer),
147
+ :ModelMetadataGetCustomMetadataMapKeys, callback(%i[pointer pointer pointer pointer], :pointer),
148
+ :AddFreeDimensionOverrideByName, callback(%i[], :pointer),
149
+ :GetAvailableProviders, callback(%i[pointer pointer], :pointer),
150
+ :ReleaseAvailableProviders, callback(%i[pointer int], :pointer)
140
151
  end
141
152
 
142
153
  class ApiBase < ::FFI::Struct
@@ -144,9 +155,17 @@ module OnnxRuntime
144
155
  # to prevent "unable to resolve type" error on Ubuntu
145
156
  layout \
146
157
  :GetApi, callback(%i[uint32], Api.by_ref),
147
- :GetVersionString, callback(%i[], :string)
158
+ :GetVersionString, callback(%i[], :pointer)
148
159
  end
149
160
 
150
161
  attach_function :OrtGetApiBase, %i[], ApiBase.by_ref
162
+
163
+ if Gem.win_platform?
164
+ class Libc
165
+ extend ::FFI::Library
166
+ ffi_lib ::FFI::Library::LIBC
167
+ attach_function :mbstowcs, %i[pointer string size_t], :size_t
168
+ end
169
+ end
151
170
  end
152
171
  end
@@ -8,26 +8,25 @@ module OnnxRuntime
8
8
  check_status api[:CreateSessionOptions].call(session_options)
9
9
  check_status api[:EnableCpuMemArena].call(session_options.read_pointer) if enable_cpu_mem_arena
10
10
  check_status api[:EnableMemPattern].call(session_options.read_pointer) if enable_mem_pattern
11
- check_status api[:EnableProfiling].call(session_options.read_pointer, "onnxruntime_profile_") if enable_profiling
11
+ check_status api[:EnableProfiling].call(session_options.read_pointer, ort_string("onnxruntime_profile_")) if enable_profiling
12
12
  if execution_mode
13
- mode =
14
- case execution_mode
15
- when :sequential
16
- 0
17
- when :parallel
18
- 1
19
- else
20
- raise ArgumentError, "Invalid execution mode"
21
- end
13
+ execution_modes = {sequential: 0, parallel: 1}
14
+ mode = execution_modes[execution_mode]
15
+ raise ArgumentError, "Invalid execution mode" unless mode
22
16
  check_status api[:SetSessionExecutionMode].call(session_options.read_pointer, mode)
23
17
  end
24
- check_status api[:SetSessionGraphOptimizationLevel].call(session_options.read_pointer, graph_optimization_level) if graph_optimization_level
18
+ if graph_optimization_level
19
+ optimization_levels = {none: 0, basic: 1, extended: 2, all: 99}
20
+ level = optimization_levels[graph_optimization_level]
21
+ raise ArgumentError, "Invalid graph optimization level" unless level
22
+ check_status api[:SetSessionGraphOptimizationLevel].call(session_options.read_pointer, level)
23
+ end
25
24
  check_status api[:SetInterOpNumThreads].call(session_options.read_pointer, inter_op_num_threads) if inter_op_num_threads
26
25
  check_status api[:SetIntraOpNumThreads].call(session_options.read_pointer, intra_op_num_threads) if intra_op_num_threads
27
26
  check_status api[:SetSessionLogSeverityLevel].call(session_options.read_pointer, log_severity_level) if log_severity_level
28
27
  check_status api[:SetSessionLogVerbosityLevel].call(session_options.read_pointer, log_verbosity_level) if log_verbosity_level
29
28
  check_status api[:SetSessionLogId].call(session_options.read_pointer, logid) if logid
30
- check_status api[:SetOptimizedModelFilePath].call(session_options.read_pointer, optimized_model_filepath) if optimized_model_filepath
29
+ check_status api[:SetOptimizedModelFilePath].call(session_options.read_pointer, ort_string(optimized_model_filepath)) if optimized_model_filepath
31
30
 
32
31
  # session
33
32
  @session = ::FFI::MemoryPointer.new(:pointer)
@@ -40,17 +39,12 @@ module OnnxRuntime
40
39
  path_or_bytes.encoding == Encoding::BINARY
41
40
  end
42
41
 
43
- # fix for Windows "File doesn't exist"
44
- if Gem.win_platform? && !from_memory
45
- path_or_bytes = File.binread(path_or_bytes)
46
- from_memory = true
47
- end
48
-
49
42
  if from_memory
50
43
  check_status api[:CreateSessionFromArray].call(env.read_pointer, path_or_bytes, path_or_bytes.bytesize, session_options.read_pointer, @session)
51
44
  else
52
- check_status api[:CreateSession].call(env.read_pointer, path_or_bytes, session_options.read_pointer, @session)
45
+ check_status api[:CreateSession].call(env.read_pointer, ort_string(path_or_bytes), session_options.read_pointer, @session)
53
46
  end
47
+ ObjectSpace.define_finalizer(self, self.class.finalize(@session))
54
48
 
55
49
  # input info
56
50
  allocator = ::FFI::MemoryPointer.new(:pointer)
@@ -63,7 +57,7 @@ module OnnxRuntime
63
57
  # input
64
58
  num_input_nodes = ::FFI::MemoryPointer.new(:size_t)
65
59
  check_status api[:SessionGetInputCount].call(read_pointer, num_input_nodes)
66
- read_size_t(num_input_nodes).times do |i|
60
+ num_input_nodes.read(:size_t).times do |i|
67
61
  name_ptr = ::FFI::MemoryPointer.new(:string)
68
62
  check_status api[:SessionGetInputName].call(read_pointer, i, @allocator.read_pointer, name_ptr)
69
63
  typeinfo = ::FFI::MemoryPointer.new(:pointer)
@@ -74,13 +68,15 @@ module OnnxRuntime
74
68
  # output
75
69
  num_output_nodes = ::FFI::MemoryPointer.new(:size_t)
76
70
  check_status api[:SessionGetOutputCount].call(read_pointer, num_output_nodes)
77
- read_size_t(num_output_nodes).times do |i|
71
+ num_output_nodes.read(:size_t).times do |i|
78
72
  name_ptr = ::FFI::MemoryPointer.new(:string)
79
73
  check_status api[:SessionGetOutputName].call(read_pointer, i, allocator.read_pointer, name_ptr)
80
74
  typeinfo = ::FFI::MemoryPointer.new(:pointer)
81
75
  check_status api[:SessionGetOutputTypeInfo].call(read_pointer, i, typeinfo)
82
76
  @outputs << {name: name_ptr.read_pointer.read_string}.merge(node_info(typeinfo))
83
77
  end
78
+ ensure
79
+ # release :SessionOptions, session_options
84
80
  end
85
81
 
86
82
  # TODO support logid
@@ -106,9 +102,18 @@ module OnnxRuntime
106
102
  output_names.size.times.map do |i|
107
103
  create_from_onnx_value(output_tensor[i].read_pointer)
108
104
  end
105
+ ensure
106
+ release :RunOptions, run_options
107
+ if input_tensor
108
+ input_feed.size.times do |i|
109
+ release :Value, input_tensor[i]
110
+ end
111
+ end
109
112
  end
110
113
 
111
114
  def modelmeta
115
+ keys = ::FFI::MemoryPointer.new(:pointer)
116
+ num_keys = ::FFI::MemoryPointer.new(:int64_t)
112
117
  description = ::FFI::MemoryPointer.new(:string)
113
118
  domain = ::FFI::MemoryPointer.new(:string)
114
119
  graph_name = ::FFI::MemoryPointer.new(:string)
@@ -117,36 +122,61 @@ module OnnxRuntime
117
122
 
118
123
  metadata = ::FFI::MemoryPointer.new(:pointer)
119
124
  check_status api[:SessionGetModelMetadata].call(read_pointer, metadata)
125
+
126
+ custom_metadata_map = {}
127
+ check_status api[:ModelMetadataGetCustomMetadataMapKeys].call(metadata.read_pointer, @allocator.read_pointer, keys, num_keys)
128
+ num_keys.read(:int64_t).times do |i|
129
+ key = keys.read_pointer[i * ::FFI::Pointer.size].read_pointer.read_string
130
+ value = ::FFI::MemoryPointer.new(:string)
131
+ check_status api[:ModelMetadataLookupCustomMetadataMap].call(metadata.read_pointer, @allocator.read_pointer, key, value)
132
+ custom_metadata_map[key] = value.read_pointer.read_string
133
+ end
134
+
120
135
  check_status api[:ModelMetadataGetDescription].call(metadata.read_pointer, @allocator.read_pointer, description)
121
136
  check_status api[:ModelMetadataGetDomain].call(metadata.read_pointer, @allocator.read_pointer, domain)
122
137
  check_status api[:ModelMetadataGetGraphName].call(metadata.read_pointer, @allocator.read_pointer, graph_name)
123
138
  check_status api[:ModelMetadataGetProducerName].call(metadata.read_pointer, @allocator.read_pointer, producer_name)
124
139
  check_status api[:ModelMetadataGetVersion].call(metadata.read_pointer, version)
125
- api[:ReleaseModelMetadata].call(metadata.read_pointer)
126
-
127
- # TODO add custom_metadata_map
128
- # need a way to get keys
129
140
 
130
141
  {
142
+ custom_metadata_map: custom_metadata_map,
131
143
  description: description.read_pointer.read_string,
132
144
  domain: domain.read_pointer.read_string,
133
145
  graph_name: graph_name.read_pointer.read_string,
134
146
  producer_name: producer_name.read_pointer.read_string,
135
147
  version: version.read(:int64_t)
136
148
  }
149
+ ensure
150
+ release :ModelMetadata, metadata
137
151
  end
138
152
 
153
+ # return value has double underscore like Python
139
154
  def end_profiling
140
155
  out = ::FFI::MemoryPointer.new(:string)
141
156
  check_status api[:SessionEndProfiling].call(read_pointer, @allocator.read_pointer, out)
142
157
  out.read_pointer.read_string
143
158
  end
144
159
 
160
+ # no way to set providers with C API yet
161
+ # so we can return all available providers
162
+ def providers
163
+ out_ptr = ::FFI::MemoryPointer.new(:pointer)
164
+ length_ptr = ::FFI::MemoryPointer.new(:int)
165
+ check_status api[:GetAvailableProviders].call(out_ptr, length_ptr)
166
+ length = length_ptr.read_int
167
+ providers = []
168
+ length.times do |i|
169
+ providers << out_ptr.read_pointer[i * ::FFI::Pointer.size].read_pointer.read_string
170
+ end
171
+ api[:ReleaseAvailableProviders].call(out_ptr.read_pointer, length)
172
+ providers
173
+ end
174
+
145
175
  private
146
176
 
147
177
  def create_input_tensor(input_feed)
148
178
  allocator_info = ::FFI::MemoryPointer.new(:pointer)
149
- check_status = api[:CreateCpuMemoryInfo].call(1, 0, allocator_info)
179
+ check_status api[:CreateCpuMemoryInfo].call(1, 0, allocator_info)
150
180
  input_tensor = ::FFI::MemoryPointer.new(:pointer, input_feed.size)
151
181
 
152
182
  input_feed.each_with_index do |(input_name, input), idx|
@@ -164,7 +194,7 @@ module OnnxRuntime
164
194
 
165
195
  # TODO support more types
166
196
  inp = @inputs.find { |i| i[:name] == input_name.to_s }
167
- raise "Unknown input: #{input_name}" unless inp
197
+ raise Error, "Unknown input: #{input_name}" unless inp
168
198
 
169
199
  input_node_dims = ::FFI::MemoryPointer.new(:int64, shape.size)
170
200
  input_node_dims.write_array_of_int64(shape)
@@ -206,7 +236,7 @@ module OnnxRuntime
206
236
 
207
237
  def create_from_onnx_value(out_ptr)
208
238
  out_type = ::FFI::MemoryPointer.new(:int)
209
- check_status = api[:GetValueType].call(out_ptr, out_type)
239
+ check_status api[:GetValueType].call(out_ptr, out_type)
210
240
  type = FFI::OnnxType[out_type.read_int]
211
241
 
212
242
  case type
@@ -221,7 +251,9 @@ module OnnxRuntime
221
251
 
222
252
  out_size = ::FFI::MemoryPointer.new(:size_t)
223
253
  output_tensor_size = api[:GetTensorShapeElementCount].call(typeinfo.read_pointer, out_size)
224
- output_tensor_size = read_size_t(out_size)
254
+ output_tensor_size = out_size.read(:size_t)
255
+
256
+ release :TensorTypeAndShapeInfo, typeinfo
225
257
 
226
258
  # TODO support more types
227
259
  type = FFI::TensorElementDataType[type]
@@ -240,7 +272,7 @@ module OnnxRuntime
240
272
  out = ::FFI::MemoryPointer.new(:size_t)
241
273
  check_status api[:GetValueCount].call(out_ptr, out)
242
274
 
243
- read_size_t(out).times.map do |i|
275
+ out.read(:size_t).times.map do |i|
244
276
  seq = ::FFI::MemoryPointer.new(:pointer)
245
277
  check_status api[:GetValue].call(out_ptr, i, @allocator.read_pointer, seq)
246
278
  create_from_onnx_value(seq.read_pointer)
@@ -255,6 +287,7 @@ module OnnxRuntime
255
287
  check_status api[:GetValue].call(out_ptr, 1, @allocator.read_pointer, map_values)
256
288
  check_status api[:GetTensorTypeAndShape].call(map_keys.read_pointer, type_shape)
257
289
  check_status api[:GetTensorElementType].call(type_shape.read_pointer, elem_type)
290
+ release :TensorTypeAndShapeInfo, type_shape
258
291
 
259
292
  # TODO support more types
260
293
  elem_type = FFI::TensorElementDataType[elem_type.read_int]
@@ -281,9 +314,9 @@ module OnnxRuntime
281
314
 
282
315
  def check_status(status)
283
316
  unless status.null?
284
- message = api[:GetErrorMessage].call(status)
317
+ message = api[:GetErrorMessage].call(status).read_string
285
318
  api[:ReleaseStatus].call(status)
286
- raise OnnxRuntime::Error, message
319
+ raise Error, message
287
320
  end
288
321
  end
289
322
 
@@ -295,6 +328,7 @@ module OnnxRuntime
295
328
  case type
296
329
  when :tensor
297
330
  tensor_info = ::FFI::MemoryPointer.new(:pointer)
331
+ # don't free tensor_info
298
332
  check_status api[:CastTypeInfoToTensorInfo].call(typeinfo.read_pointer, tensor_info)
299
333
 
300
334
  type, shape = tensor_type_and_shape(tensor_info)
@@ -335,7 +369,7 @@ module OnnxRuntime
335
369
  unsupported_type("ONNX", type)
336
370
  end
337
371
  ensure
338
- api[:ReleaseTypeInfo].call(typeinfo.read_pointer)
372
+ release :TypeInfo, typeinfo
339
373
  end
340
374
 
341
375
  def tensor_type_and_shape(tensor_info)
@@ -344,7 +378,7 @@ module OnnxRuntime
344
378
 
345
379
  num_dims_ptr = ::FFI::MemoryPointer.new(:size_t)
346
380
  check_status api[:GetDimensionsCount].call(tensor_info.read_pointer, num_dims_ptr)
347
- num_dims = read_size_t(num_dims_ptr)
381
+ num_dims = num_dims_ptr.read(:size_t)
348
382
 
349
383
  node_dims = ::FFI::MemoryPointer.new(:int64, num_dims)
350
384
  check_status api[:GetDimensions].call(tensor_info.read_pointer, node_dims, num_dims)
@@ -353,20 +387,43 @@ module OnnxRuntime
353
387
  end
354
388
 
355
389
  def unsupported_type(name, type)
356
- raise "Unsupported #{name} type: #{type}"
390
+ raise Error, "Unsupported #{name} type: #{type}"
357
391
  end
358
392
 
359
- # read(:size_t) not supported in FFI JRuby
360
- def read_size_t(ptr)
361
- if RUBY_PLATFORM == "java"
362
- ptr.read_long
363
- else
364
- ptr.read(:size_t)
365
- end
393
+ def api
394
+ self.class.api
366
395
  end
367
396
 
368
- def api
369
- @api ||= FFI.OrtGetApiBase[:GetApi].call(1)
397
+ def release(*args)
398
+ self.class.release(*args)
399
+ end
400
+
401
+ def self.api
402
+ @api ||= FFI.OrtGetApiBase[:GetApi].call(4)
403
+ end
404
+
405
+ def self.release(type, pointer)
406
+ api[:"Release#{type}"].call(pointer.read_pointer) if pointer && !pointer.null?
407
+ end
408
+
409
+ def self.finalize(session)
410
+ # must use proc instead of stabby lambda
411
+ proc { release :Session, session }
412
+ end
413
+
414
+ # wide string on Windows
415
+ # char string on Linux
416
+ # see ORTCHAR_T in onnxruntime_c_api.h
417
+ def ort_string(str)
418
+ if Gem.win_platform?
419
+ max = str.size + 1 # for null byte
420
+ dest = ::FFI::MemoryPointer.new(:wchar_t, max)
421
+ ret = FFI::Libc.mbstowcs(dest, str, max)
422
+ raise Error, "Expected mbstowcs to return #{str.size}, got #{ret}" if ret != str.size
423
+ dest
424
+ else
425
+ str
426
+ end
370
427
  end
371
428
 
372
429
  def env
@@ -375,7 +432,7 @@ module OnnxRuntime
375
432
  @@env ||= begin
376
433
  env = ::FFI::MemoryPointer.new(:pointer)
377
434
  check_status api[:CreateEnv].call(3, "Default", env)
378
- at_exit { api[:ReleaseEnv].call(env.read_pointer) }
435
+ at_exit { release :Env, env }
379
436
  # disable telemetry
380
437
  # https://github.com/microsoft/onnxruntime/blob/master/docs/Privacy.md
381
438
  check_status api[:DisableTelemetryEvents].call(env)