opencl_ruby_ffi 1.2.2 → 1.3.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.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/lib/opencl_ruby_ffi.rb +2 -0
- data/lib/opencl_ruby_ffi/Buffer.rb +18 -13
- data/lib/opencl_ruby_ffi/CommandQueue.rb +301 -302
- data/lib/opencl_ruby_ffi/Context.rb +158 -158
- data/lib/opencl_ruby_ffi/Device.rb +270 -224
- data/lib/opencl_ruby_ffi/Event.rb +40 -36
- data/lib/opencl_ruby_ffi/Image.rb +34 -57
- data/lib/opencl_ruby_ffi/Kernel.rb +251 -191
- data/lib/opencl_ruby_ffi/Mem.rb +49 -70
- data/lib/opencl_ruby_ffi/Pipe.rb +3 -14
- data/lib/opencl_ruby_ffi/Platform.rb +46 -48
- data/lib/opencl_ruby_ffi/Program.rb +131 -124
- data/lib/opencl_ruby_ffi/Sampler.rb +6 -24
- data/lib/opencl_ruby_ffi/amd/device_attribute_query.rb +100 -0
- data/lib/opencl_ruby_ffi/egl.rb +2 -0
- data/lib/opencl_ruby_ffi/ext.rb +11 -0
- data/lib/opencl_ruby_ffi/ext/device_fission.rb +264 -0
- data/lib/opencl_ruby_ffi/gl_ext.rb +2 -0
- data/lib/opencl_ruby_ffi/khr/d3d10_sharing.rb +120 -0
- data/lib/opencl_ruby_ffi/khr/d3d11_sharing.rb +120 -0
- data/lib/opencl_ruby_ffi/khr/dx9_media_sharing.rb +113 -0
- data/lib/opencl_ruby_ffi/khr/egl_event.rb +15 -0
- data/lib/opencl_ruby_ffi/khr/egl_image.rb +58 -0
- data/lib/opencl_ruby_ffi/khr/fp16.rb +23 -0
- data/lib/opencl_ruby_ffi/khr/fp64.rb +23 -0
- data/lib/opencl_ruby_ffi/khr/gl_event.rb +38 -0
- data/lib/opencl_ruby_ffi/khr/gl_sharing.rb +79 -0
- data/lib/opencl_ruby_ffi/khr/icd.rb +30 -0
- data/lib/opencl_ruby_ffi/khr/initalize_memory.rb +19 -0
- data/lib/opencl_ruby_ffi/khr/priority_hints.rb +48 -0
- data/lib/opencl_ruby_ffi/khr/spir.rb +45 -0
- data/lib/opencl_ruby_ffi/khr/sub_groups.rb +49 -0
- data/lib/opencl_ruby_ffi/khr/terminate_context.rb +46 -0
- data/lib/opencl_ruby_ffi/khr/throttle_hints.rb +47 -0
- data/lib/opencl_ruby_ffi/nv/device_attribute_query.rb +50 -0
- data/lib/opencl_ruby_ffi/opencl_ruby_ffi_base.rb +40 -13
- data/lib/opencl_ruby_ffi/opencl_ruby_ffi_base_gen.rb +214 -2114
- data/lib/opencl_ruby_ffi/opencl_types.rb +15 -3
- data/opencl_ruby_ffi.gemspec +4 -4
- data/templates_custom/default/module/setup.rb +9 -0
- metadata +29 -6
- data/lib/opencl_ruby_ffi/GLExt.rb +0 -58
- data/lib/opencl_ruby_ffi/Stream.rb +0 -127
@@ -58,24 +58,37 @@ module OpenCL
|
|
58
58
|
#Maps the cl_context object of OpenCL
|
59
59
|
class Context
|
60
60
|
include InnerInterface
|
61
|
-
|
62
|
-
class << self
|
63
|
-
include InnerGenerator
|
64
|
-
end
|
61
|
+
extend InnerGenerator
|
65
62
|
|
66
63
|
def inspect
|
67
64
|
return "#<#{self.class.name}: #{self.devices}>"
|
68
65
|
end
|
69
66
|
|
70
|
-
|
71
|
-
|
72
|
-
# Returns the
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
get_info("Context", :cl_uint, "reference_count")
|
68
|
+
|
69
|
+
# Returns the number of devices associated to the Context
|
70
|
+
def num_devices
|
71
|
+
d_n = 0
|
72
|
+
ptr = MemoryPointer::new( :size_t )
|
73
|
+
error = OpenCL.clGetContextInfo(self, DEVICES, 0, nil, ptr)
|
74
|
+
error_check(error)
|
75
|
+
d_n = ptr.read_size_t / Platform.size
|
76
|
+
return d_n
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns an Array of Device associated to the Context
|
80
|
+
def devices
|
81
|
+
n = self.num_devices
|
82
|
+
ptr2 = MemoryPointer::new( Device, n )
|
83
|
+
error = OpenCL.clGetContextInfo(self, DEVICES, Device.size*n, ptr2, nil)
|
84
|
+
error_check(error)
|
85
|
+
return ptr2.get_array_of_pointer(0, n).collect { |device_ptr|
|
86
|
+
Device::new(device_ptr)
|
87
|
+
}
|
88
|
+
end
|
76
89
|
|
77
90
|
##
|
78
|
-
#
|
91
|
+
# @!method properties
|
79
92
|
# the Array of :cl_context_properties used to create the Context
|
80
93
|
def properties
|
81
94
|
ptr1 = MemoryPointer::new( :size_t, 1)
|
@@ -108,33 +121,6 @@ module OpenCL
|
|
108
121
|
self.devices.first.platform
|
109
122
|
end
|
110
123
|
|
111
|
-
# Returns the number of devices associated to the Context
|
112
|
-
def num_devices
|
113
|
-
d_n = 0
|
114
|
-
ptr = MemoryPointer::new( :size_t )
|
115
|
-
error = OpenCL.clGetContextInfo(self, DEVICES, 0, nil, ptr)
|
116
|
-
error_check(error)
|
117
|
-
d_n = ptr.read_size_t / Platform.size
|
118
|
-
# else
|
119
|
-
# ptr = MemoryPointer::new( :cl_uint )
|
120
|
-
# error = OpenCL.clGetContextInfo(self, OpenCL::Context::NUM_DEVICES, ptr.size, ptr, nil)
|
121
|
-
# OpenCL.error_check(error)
|
122
|
-
# d_n = ptr.read_cl_uint
|
123
|
-
# end
|
124
|
-
return d_n
|
125
|
-
end
|
126
|
-
|
127
|
-
# Returns an Array of Device associated to the Context
|
128
|
-
def devices
|
129
|
-
n = self.num_devices
|
130
|
-
ptr2 = MemoryPointer::new( Device, n )
|
131
|
-
error = OpenCL.clGetContextInfo(self, DEVICES, Device.size*n, ptr2, nil)
|
132
|
-
error_check(error)
|
133
|
-
return ptr2.get_array_of_pointer(0, n).collect { |device_ptr|
|
134
|
-
Device::new(device_ptr)
|
135
|
-
}
|
136
|
-
end
|
137
|
-
|
138
124
|
# Returns an Array of ImageFormat that are supported for a given image type in the Context
|
139
125
|
#
|
140
126
|
# ==== Attributes
|
@@ -214,27 +200,10 @@ module OpenCL
|
|
214
200
|
# ==== Options
|
215
201
|
#
|
216
202
|
# * +:flags+ - a single or an Array of :cl_mem_flags specifying the flags to be used when creating the Image
|
217
|
-
def
|
218
|
-
return OpenCL.
|
203
|
+
def create_from_gl_renderbuffer( renderbuffer, options = {} )
|
204
|
+
return OpenCL.create_from_gl_renderbuffer( self, renderbuffer, options )
|
219
205
|
end
|
220
|
-
alias :
|
221
|
-
|
222
|
-
# Creates an Image in the Context from an OpenGL texture
|
223
|
-
#
|
224
|
-
# ==== Attributes
|
225
|
-
#
|
226
|
-
# * +texture_target+ - a :GLenum defining the image type of texture
|
227
|
-
# * +texture+ - a :GLuint specifying the name of the texture
|
228
|
-
# * +options+ - a hash containing named options
|
229
|
-
#
|
230
|
-
# ==== Options
|
231
|
-
#
|
232
|
-
# * +:miplevel+ - a :GLint specifying the mipmap level to be used (default 0)
|
233
|
-
# * +:flags+ - a single or an Array of :cl_mem_flags specifying the flags to be used when creating the Image
|
234
|
-
def create_from_gl_texture( texture_target, texture, options = {} )
|
235
|
-
return OpenCL.create_from_gl_texture( self, texture_target, texture, options )
|
236
|
-
end
|
237
|
-
alias :create_from_GL_texture :create_from_gl_texture
|
206
|
+
alias :create_from_GL_renderbuffer :create_from_gl_renderbuffer
|
238
207
|
|
239
208
|
# Creates an Image in the Context from an OpenGL 2D texture
|
240
209
|
#
|
@@ -270,21 +239,6 @@ module OpenCL
|
|
270
239
|
end
|
271
240
|
alias :create_from_GL_texture_3D :create_from_gl_texture_3d
|
272
241
|
|
273
|
-
# Creates an Image in the Context
|
274
|
-
#
|
275
|
-
# ==== Attributes
|
276
|
-
#
|
277
|
-
# * +format+ - an ImageFormat
|
278
|
-
# * +options+ - an ImageDesc
|
279
|
-
#
|
280
|
-
# ==== Options
|
281
|
-
#
|
282
|
-
# * +:flags+ - a single or an Array of :cl_mem_flags specifying the flags to be used when creating the Buffer
|
283
|
-
# * +:host_ptr+ - if provided, the Pointer (or convertible to Pointer using to_ptr) to the memory area to use
|
284
|
-
def create_image( format, desc, options = {} )
|
285
|
-
return OpenCL.create_image( self, format, desc, options )
|
286
|
-
end
|
287
|
-
|
288
242
|
# Creates a 1D Image in the Context
|
289
243
|
#
|
290
244
|
# ==== Attributes
|
@@ -336,39 +290,6 @@ module OpenCL
|
|
336
290
|
end
|
337
291
|
alias :create_image_3D :create_image_3d
|
338
292
|
|
339
|
-
# # Creates an Event in the Context from a GL sync
|
340
|
-
# #
|
341
|
-
# # ==== Attributes
|
342
|
-
# #
|
343
|
-
# # * +sync+ - a :GLsync representing the name of the sync object
|
344
|
-
# def create_event_from_gl_sync_khr( sync )
|
345
|
-
# return OpenCL.create_event_from_gl_sync_khr( self, sync )
|
346
|
-
# end
|
347
|
-
# alias :create_event_from_GL_sync_KHR :create_event_from_gl_sync_khr
|
348
|
-
|
349
|
-
|
350
|
-
# Creates a user Event in the Context
|
351
|
-
def create_user_event
|
352
|
-
return OpenCL.create_user_event(self)
|
353
|
-
end
|
354
|
-
|
355
|
-
# Links a set of compiled programs for all device in the Context, or a subset of devices
|
356
|
-
#
|
357
|
-
# ==== Attributes
|
358
|
-
#
|
359
|
-
# * +input_programs+ - a single or an Array of Program
|
360
|
-
# * +options+ - a Hash containing named options
|
361
|
-
# * +block+ - if provided, a callback invoked when the Program is built. Signature of the callback is { |Program, Pointer to user_data| ... }
|
362
|
-
#
|
363
|
-
# ==== Options
|
364
|
-
#
|
365
|
-
# * +:device_list+ - an Array of Device to build the program for
|
366
|
-
# * +:options+ - a String containing the options to use for the build
|
367
|
-
# * +:user_data+ - a Pointer (or convertible to Pointer using to_ptr) to the memory area to pass to the callback
|
368
|
-
def link_program( input_programs, options = {}, &block)
|
369
|
-
return OpenCL.link_program(self, input_programs, options, &block)
|
370
|
-
end
|
371
|
-
|
372
293
|
# Creates a Program from binary
|
373
294
|
#
|
374
295
|
# ==== Attributes
|
@@ -379,16 +300,6 @@ module OpenCL
|
|
379
300
|
return OpenCL.create_program_with_binary(self, device_list, binaries)
|
380
301
|
end
|
381
302
|
|
382
|
-
# Creates a Program from a list of built in kernel names
|
383
|
-
#
|
384
|
-
# ==== Attributes
|
385
|
-
#
|
386
|
-
# * +device_list+ - an Array of Device to create the program for
|
387
|
-
# * +kernel_names+ - a single or an Array of String representing the kernel names
|
388
|
-
def create_program_with_built_in_kernels( device_list, kernel_names )
|
389
|
-
return OpenCL.create_program_with_built_in_kernels(self, device_list, kernel_names )
|
390
|
-
end
|
391
|
-
|
392
303
|
# Creates a Program from sources in the Context
|
393
304
|
#
|
394
305
|
# ==== Attributes
|
@@ -398,15 +309,6 @@ module OpenCL
|
|
398
309
|
return OpenCL.create_program_with_source(self, strings)
|
399
310
|
end
|
400
311
|
|
401
|
-
# Create a Program from an intermediate level representation in the Context
|
402
|
-
#
|
403
|
-
# ==== Attributes
|
404
|
-
#
|
405
|
-
# * +il+ - a binary string containing the intermediate level representation of the program
|
406
|
-
def create_program_with_il(il)
|
407
|
-
return OpenCL.create_program_with_il(self, il)
|
408
|
-
end
|
409
|
-
|
410
312
|
# Creates a Sampler in the Context
|
411
313
|
#
|
412
314
|
# ==== Options
|
@@ -421,47 +323,145 @@ module OpenCL
|
|
421
323
|
return OpenCL.create_sampler( self, options )
|
422
324
|
end
|
423
325
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
def create_pipe( pipe_packet_size, pipe_max_packets, opts = {} )
|
435
|
-
return OpenCL.create_pipe( self, pipe_packet_size, pipe_max_packets, opts )
|
326
|
+
module OpenCL11
|
327
|
+
extend InnerGenerator
|
328
|
+
|
329
|
+
get_info("Context", :cl_uint, "num_devices")
|
330
|
+
|
331
|
+
# Creates a user Event in the Context
|
332
|
+
def create_user_event
|
333
|
+
return OpenCL.create_user_event(self)
|
334
|
+
end
|
335
|
+
|
436
336
|
end
|
437
337
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
338
|
+
|
339
|
+
module OpenCL12
|
340
|
+
|
341
|
+
# Creates an Image in the Context from an OpenGL texture
|
342
|
+
#
|
343
|
+
# ==== Attributes
|
344
|
+
#
|
345
|
+
# * +texture_target+ - a :GLenum defining the image type of texture
|
346
|
+
# * +texture+ - a :GLuint specifying the name of the texture
|
347
|
+
# * +options+ - a hash containing named options
|
348
|
+
#
|
349
|
+
# ==== Options
|
350
|
+
#
|
351
|
+
# * +:miplevel+ - a :GLint specifying the mipmap level to be used (default 0)
|
352
|
+
# * +:flags+ - a single or an Array of :cl_mem_flags specifying the flags to be used when creating the Image
|
353
|
+
def create_from_gl_texture( texture_target, texture, options = {} )
|
354
|
+
return OpenCL.create_from_gl_texture( self, texture_target, texture, options )
|
355
|
+
end
|
356
|
+
alias :create_from_GL_texture :create_from_gl_texture
|
357
|
+
|
358
|
+
# Creates an Image in the Context
|
359
|
+
#
|
360
|
+
# ==== Attributes
|
361
|
+
#
|
362
|
+
# * +format+ - an ImageFormat
|
363
|
+
# * +options+ - an ImageDesc
|
364
|
+
#
|
365
|
+
# ==== Options
|
366
|
+
#
|
367
|
+
# * +:flags+ - a single or an Array of :cl_mem_flags specifying the flags to be used when creating the Buffer
|
368
|
+
# * +:host_ptr+ - if provided, the Pointer (or convertible to Pointer using to_ptr) to the memory area to use
|
369
|
+
def create_image( format, desc, options = {} )
|
370
|
+
return OpenCL.create_image( self, format, desc, options )
|
371
|
+
end
|
372
|
+
|
373
|
+
# Links a set of compiled programs for all device in the Context, or a subset of devices
|
374
|
+
#
|
375
|
+
# ==== Attributes
|
376
|
+
#
|
377
|
+
# * +input_programs+ - a single or an Array of Program
|
378
|
+
# * +options+ - a Hash containing named options
|
379
|
+
# * +block+ - if provided, a callback invoked when the Program is built. Signature of the callback is { |Program, Pointer to user_data| ... }
|
380
|
+
#
|
381
|
+
# ==== Options
|
382
|
+
#
|
383
|
+
# * +:device_list+ - an Array of Device to build the program for
|
384
|
+
# * +:options+ - a String containing the options to use for the build
|
385
|
+
# * +:user_data+ - a Pointer (or convertible to Pointer using to_ptr) to the memory area to pass to the callback
|
386
|
+
def link_program( input_programs, options = {}, &block)
|
387
|
+
return OpenCL.link_program(self, input_programs, options, &block)
|
388
|
+
end
|
389
|
+
|
390
|
+
# Creates a Program from a list of built in kernel names
|
391
|
+
#
|
392
|
+
# ==== Attributes
|
393
|
+
#
|
394
|
+
# * +device_list+ - an Array of Device to create the program for
|
395
|
+
# * +kernel_names+ - a single or an Array of String representing the kernel names
|
396
|
+
def create_program_with_built_in_kernels( device_list, kernel_names )
|
397
|
+
return OpenCL.create_program_with_built_in_kernels(self, device_list, kernel_names )
|
398
|
+
end
|
399
|
+
|
450
400
|
end
|
451
401
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
402
|
+
module OpenCL20
|
403
|
+
|
404
|
+
# Creates a Pipe in the Context
|
405
|
+
#
|
406
|
+
# ==== Attributes
|
407
|
+
#
|
408
|
+
# * +pipe_packet_size+ - size of a packet in the Pipe
|
409
|
+
# * +pipe_max_packets+ - size of the Pipe in packet
|
410
|
+
#
|
411
|
+
# ==== Options
|
412
|
+
#
|
413
|
+
# * +:flags+ - a single or an Array of :cl_mem_flags specifying the flags to be used when creating the Buffer
|
414
|
+
def create_pipe( pipe_packet_size, pipe_max_packets, opts = {} )
|
415
|
+
return OpenCL.create_pipe( self, pipe_packet_size, pipe_max_packets, opts )
|
416
|
+
end
|
417
|
+
|
418
|
+
# Creates an SVMPointer pointing to an SVM area of memory in the Context
|
419
|
+
#
|
420
|
+
# ==== Attributes
|
421
|
+
#
|
422
|
+
# * +size+ - the size of the mmemory area to allocate
|
423
|
+
# * +options+ - a hash containing named options
|
424
|
+
#
|
425
|
+
# ==== Options
|
426
|
+
#
|
427
|
+
# * +:alignment+ - imposes the minimum alignment in byte
|
428
|
+
def svm_alloc(size, options = {})
|
429
|
+
return OpenCL.svm_alloc( self, size, options)
|
430
|
+
end
|
431
|
+
|
432
|
+
# Frees an SVMPointer
|
433
|
+
#
|
434
|
+
# ==== Attributes
|
435
|
+
#
|
436
|
+
# * +svm_pointer+ - the SVMPointer to deallocate
|
437
|
+
def svm_free(svm_pointer)
|
438
|
+
return OpenCL.svm_free(self, svm_pointer)
|
439
|
+
end
|
440
|
+
|
459
441
|
end
|
460
442
|
|
461
|
-
|
462
|
-
|
443
|
+
module OpenCL21
|
444
|
+
|
445
|
+
# Create a Program from an intermediate level representation in the Context
|
446
|
+
#
|
447
|
+
# ==== Attributes
|
448
|
+
#
|
449
|
+
# * +il+ - a binary string containing the intermediate level representation of the program
|
450
|
+
def create_program_with_il(il)
|
451
|
+
return OpenCL.create_program_with_il(self, il)
|
452
|
+
end
|
453
|
+
|
454
|
+
def set_default_device_command_queue( device, command_queue )
|
455
|
+
return OpenCL.set_default_device_command_queue( self, device, command_queue )
|
456
|
+
end
|
457
|
+
|
463
458
|
end
|
464
459
|
|
460
|
+
register_extension( :v11, OpenCL11, "platform.version_number >= 1.1" )
|
461
|
+
register_extension( :v12, OpenCL12, "platform.version_number >= 1.2" )
|
462
|
+
register_extension( :v20, OpenCL20, "platform.version_number >= 2.0" )
|
463
|
+
register_extension( :v21, OpenCL21, "platform.version_number >= 2.1" )
|
464
|
+
|
465
465
|
end
|
466
466
|
|
467
467
|
end
|
@@ -26,7 +26,7 @@ module OpenCL
|
|
26
26
|
error = clCreateSubDevices( in_device, props, device_number, devices_ptr, nil )
|
27
27
|
error_check(error)
|
28
28
|
devices_ptr.get_array_of_pointer(0, device_number).collect { |device_ptr|
|
29
|
-
|
29
|
+
Device::new(device_ptr, false)
|
30
30
|
}
|
31
31
|
end
|
32
32
|
|
@@ -39,7 +39,7 @@ module OpenCL
|
|
39
39
|
return [ device_timestamp_p.read_cl_ulong, host_timestamp_p.read_cl_ulong ]
|
40
40
|
end
|
41
41
|
|
42
|
-
def self.
|
42
|
+
def self.get_host_timer( device )
|
43
43
|
error_check(INVALID_OPERATION) if device.platform.version_number < 2.1
|
44
44
|
host_timestamp_p = MemoryPointer::new( :cl_ulong )
|
45
45
|
error = clGetHostTimer( device, host_timestamp_p)
|
@@ -50,18 +50,18 @@ module OpenCL
|
|
50
50
|
# Maps the cl_device_id object of OpenCL
|
51
51
|
class Device
|
52
52
|
include InnerInterface
|
53
|
-
|
54
|
-
class << self
|
55
|
-
include InnerGenerator
|
56
|
-
end
|
53
|
+
extend InnerGenerator
|
57
54
|
|
58
55
|
def inspect
|
59
56
|
return "#<#{self.class.name}: #{name} (#{pointer.to_i})>"
|
60
57
|
end
|
61
58
|
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
get_info("Device", :cl_uint, "address_bits")
|
60
|
+
get_info("Device", :cl_bool, "available")
|
61
|
+
get_info("Device", :cl_bool, "compiler_available")
|
62
|
+
get_info("Device", :cl_bool, "endian_little")
|
63
|
+
get_info("Device", :cl_bool, "error_correction_support")
|
64
|
+
get_info("Device", :cl_device_exec_capabilities, "execution_capabilities")
|
65
65
|
|
66
66
|
# Returns an Array of String corresponding to the Device extensions
|
67
67
|
def extensions
|
@@ -75,49 +75,58 @@ module OpenCL
|
|
75
75
|
return ext_string.split(" ")
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
get_info("Device", :cl_ulong, "global_mem_cache_size")
|
79
|
+
get_info("Device", :cl_device_mem_cache_type, "global_mem_cache_type")
|
80
|
+
get_info("Device", :cl_uint, "global_mem_cacheline_size")
|
81
|
+
get_info("Device", :cl_ulong, "global_mem_size")
|
82
|
+
get_info("Device", :cl_bool, "image_support")
|
83
|
+
get_info("Device", :size_t, "image2d_max_height")
|
84
|
+
get_info("Device", :size_t, "image2d_max_width")
|
85
|
+
get_info("Device", :size_t, "image3d_max_depth")
|
86
|
+
get_info("Device", :size_t, "image3d_max_height")
|
87
|
+
get_info("Device", :size_t, "image3d_max_width")
|
88
|
+
get_info("Device", :cl_ulong, "local_mem_size")
|
89
|
+
get_info("Device", :cl_device_local_mem_type, "local_mem_type")
|
90
|
+
get_info("Device", :cl_uint, "max_clock_frequency")
|
91
|
+
get_info("Device", :cl_uint, "max_compute_units")
|
92
|
+
get_info("Device", :cl_uint, "max_constant_args")
|
93
|
+
get_info("Device", :cl_ulong, "max_constant_buffer_size")
|
94
|
+
get_info("Device", :cl_ulong, "max_mem_alloc_size")
|
95
|
+
get_info("Device", :size_t, "max_parameter_size")
|
96
|
+
get_info("Device", :cl_uint, "max_read_image_args")
|
97
|
+
get_info("Device", :cl_uint, "max_samplers")
|
98
|
+
get_info("Device", :size_t, "max_work_group_size")
|
99
|
+
get_info("Device", :cl_uint, "max_work_item_dimensions")
|
100
|
+
get_info_array("Device", :size_t, "max_work_item_sizes")
|
101
|
+
get_info("Device", :cl_uint, "max_write_image_args")
|
102
|
+
get_info("Device", :cl_uint, "mem_base_addr_align")
|
103
|
+
get_info("Device", :cl_uint, "min_data_type_align_size")
|
104
|
+
get_info("Device", :string, "name")
|
105
|
+
|
106
|
+
alias to_s name
|
89
107
|
|
90
|
-
#
|
91
|
-
def
|
92
|
-
|
93
|
-
error = OpenCL.clGetDeviceInfo(
|
94
|
-
error_check(error)
|
95
|
-
vers = MemoryPointer::new( spir_versions_size.read_size_t )
|
96
|
-
error = OpenCL.clGetDeviceInfo( self, SPIR_VERSIONS, spir_versions_size.read_size_t, vers, nil)
|
108
|
+
# Returns the Platform the Device belongs to
|
109
|
+
def platform
|
110
|
+
ptr = MemoryPointer::new( OpenCL::Platform )
|
111
|
+
error = OpenCL.clGetDeviceInfo(self, PLATFORM, OpenCL::Platform.size, ptr, nil)
|
97
112
|
error_check(error)
|
98
|
-
|
99
|
-
return vers_string.split(" ")
|
100
|
-
end
|
101
|
-
|
102
|
-
def spir_versions_number
|
103
|
-
vers_strings = spir_versions
|
104
|
-
return vers_strings.collect { |s| s.scan(/(\d+\.\d+)/).first.first.to_f }
|
105
|
-
end
|
106
|
-
|
107
|
-
def il_version_number
|
108
|
-
return il_version.scan(/(\d+\.\d+)/).first.first.to_f
|
113
|
+
return OpenCL::Platform::new(ptr.read_pointer)
|
109
114
|
end
|
110
115
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
116
|
+
get_info("Device", :cl_uint, "preferred_vector_width_char")
|
117
|
+
get_info("Device", :cl_uint, "preferred_vector_width_short")
|
118
|
+
get_info("Device", :cl_uint, "preferred_vector_width_int")
|
119
|
+
get_info("Device", :cl_uint, "preferred_vector_width_long")
|
120
|
+
get_info("Device", :cl_uint, "preferred_vector_width_float")
|
121
|
+
get_info("Device", :cl_uint, "preferred_vector_width_double")
|
122
|
+
get_info("Device", :string, "profile")
|
123
|
+
get_info("Device", :size_t, "profiling_timer_resolution")
|
124
|
+
get_info("Device", :cl_command_queue_properties, "queue_properties")
|
125
|
+
get_info("Device", :cl_device_fp_config, "single_fp_config")
|
126
|
+
get_info("Device", :cl_device_type, "type")
|
127
|
+
get_info("Device", :string, "vendor")
|
128
|
+
get_info("Device", :cl_uint, "vendor_id")
|
129
|
+
get_info("Device", :string, "version")
|
121
130
|
|
122
131
|
# returs a floating point number corresponding to the OpenCL version of the Device
|
123
132
|
def version_number
|
@@ -126,203 +135,240 @@ module OpenCL
|
|
126
135
|
return n.first.first.to_f
|
127
136
|
end
|
128
137
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
138
|
+
get_info("Device", :string, "driver_version")
|
139
|
+
|
140
|
+
module OpenCL11
|
141
|
+
extend InnerGenerator
|
142
|
+
|
143
|
+
get_info("Device", :cl_bool, "host_unified_memory")
|
144
|
+
get_info("Device", :cl_uint, "native_vector_width_char")
|
145
|
+
get_info("Device", :cl_uint, "native_vector_width_short")
|
146
|
+
get_info("Device", :cl_uint, "native_vector_width_int")
|
147
|
+
get_info("Device", :cl_uint, "native_vector_width_long")
|
148
|
+
get_info("Device", :cl_uint, "native_vector_width_float")
|
149
|
+
get_info("Device", :cl_uint, "native_vector_width_double")
|
150
|
+
get_info("Device", :cl_uint, "native_vector_width_half")
|
151
|
+
get_info("Device", :string, "opencl_c_version")
|
152
|
+
|
153
|
+
# returs a floating point number corresponding to the OpenCL C version of the Device
|
154
|
+
def opencl_c_version_number
|
155
|
+
ver = self.opencl_c_version
|
156
|
+
n = ver.scan(/OpenCL C (\d+\.\d+)/)
|
157
|
+
return n.first.first.to_f
|
158
|
+
end
|
148
159
|
|
149
|
-
|
150
|
-
|
151
|
-
# Returns an ExecCpabilities representing the execution capabilities corresponding to the Device
|
152
|
-
eval get_info("Device", :cl_device_exec_capabilities, "EXECUTION_CAPABILITIES")
|
153
|
-
|
154
|
-
##
|
155
|
-
# :method: global_mem_cache_type()
|
156
|
-
# Returns a MemCacheType representing the type of the global cache memory on the Device
|
157
|
-
eval get_info("Device", :cl_device_mem_cache_type, "GLOBAL_MEM_CACHE_TYPE")
|
158
|
-
|
159
|
-
##
|
160
|
-
# :method: local_mem_type()
|
161
|
-
# Returns a LocalMemType rpresenting the type of the local memory on the Device
|
162
|
-
eval get_info("Device", :cl_device_local_mem_type, "LOCAL_MEM_TYPE")
|
163
|
-
|
164
|
-
##
|
165
|
-
# :method: queue_properties()
|
166
|
-
# Returns a CommandQueue::Properties representing the properties supported by a CommandQueue targetting the Device
|
167
|
-
eval get_info("Device", :cl_command_queue_properties, "QUEUE_PROPERTIES")
|
168
|
-
|
169
|
-
##
|
170
|
-
# :method: queue_on_device_properties()
|
171
|
-
# Returns a CommandQueue::Properties representing the properties supported by a CommandQueue on the Device
|
172
|
-
eval get_info("Device", :cl_command_queue_properties, "QUEUE_ON_DEVICE_PROPERTIES")
|
173
|
-
|
174
|
-
##
|
175
|
-
# :method: queue_on_host_properties()
|
176
|
-
# Returns a CommandQueue::Properties representing the properties supported by a CommandQueue targetting the Device
|
177
|
-
eval get_info("Device", :cl_command_queue_properties, "QUEUE_ON_HOST_PROPERTIES")
|
178
|
-
|
179
|
-
##
|
180
|
-
# :method: type()
|
181
|
-
# Returns a Device::Type representing the type of the Device
|
182
|
-
eval get_info("Device", :cl_device_type, "TYPE")
|
183
|
-
|
184
|
-
##
|
185
|
-
# :method: partition_affinity_domain()
|
186
|
-
# Returns an AffinityDomain representing the list of supported affinity domains for partitioning the Device using OpenCL::Device::PARTITION_BY_AFFINITY_DOMAIN
|
187
|
-
eval get_info("Device", :cl_device_affinity_domain, "PARTITION_AFFINITY_DOMAIN")
|
188
|
-
|
189
|
-
##
|
190
|
-
# :method: max_work_item_sizes()
|
191
|
-
# Maximum number of work-items that can be specified in each dimension of the work-group to clEnqueueNDRangeKernel for the Device
|
192
|
-
eval get_info_array("Device", :size_t, "MAX_WORK_ITEM_SIZES")
|
193
|
-
|
194
|
-
##
|
195
|
-
# :method: partition_properties()
|
196
|
-
# Returns the list of partition types supported by the Device
|
197
|
-
def partition_properties
|
198
|
-
ptr1 = MemoryPointer::new( :size_t, 1)
|
199
|
-
error = OpenCL.clGetDeviceInfo(self, PARTITION_PROPERTIES, 0, nil, ptr1)
|
200
|
-
error_check(error)
|
201
|
-
ptr2 = MemoryPointer::new( ptr1.read_size_t )
|
202
|
-
error = OpenCL.clGetDeviceInfo(self, PARTITION_PROPERTIES, ptr1.read_size_t, ptr2, nil)
|
203
|
-
error_check(error)
|
204
|
-
arr = ptr2.get_array_of_cl_device_partition_property(0, ptr1.read_size_t/ OpenCL.find_type(:cl_device_partition_property).size)
|
205
|
-
arr.reject! { |e| e.null? }
|
206
|
-
return arr.collect { |e| Partition::new(e.to_i) }
|
160
|
+
get_info("Device", :cl_uint, "preferred_vector_width_half")
|
161
|
+
|
207
162
|
end
|
208
163
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
164
|
+
module OpenCL12
|
165
|
+
extend InnerGenerator
|
166
|
+
|
167
|
+
# Returns an Array of String corresponding to the Device built in kernel names
|
168
|
+
def built_in_kernels
|
169
|
+
built_in_kernels_size = MemoryPointer::new( :size_t )
|
170
|
+
error = OpenCL.clGetDeviceInfo( self, BUILT_IN_KERNELS, 0, nil, built_in_kernels_size)
|
171
|
+
error_check(error)
|
172
|
+
ker = MemoryPointer::new( built_in_kernels_size.read_size_t )
|
173
|
+
error = OpenCL.clGetDeviceInfo( self, BUILT_IN_KERNELS, built_in_kernels_size.read_size_t, ker, nil)
|
174
|
+
error_check(error)
|
175
|
+
ker_string = ker.read_string
|
176
|
+
return ker_string.split(";")
|
177
|
+
end
|
213
178
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
179
|
+
get_info("Device", :size_t, "image_max_buffer_size")
|
180
|
+
get_info("Device", :size_t, "image_max_array_size")
|
181
|
+
get_info("Device", :cl_bool, "linker_available")
|
182
|
+
|
183
|
+
# Returns the parent Device if it exists
|
184
|
+
def parent_device
|
185
|
+
ptr = MemoryPointer::new( Device )
|
186
|
+
error = OpenCL.clGetDeviceInfo(self, PARENT_DEVICE, Device.size, ptr, nil)
|
187
|
+
error_check(error)
|
188
|
+
return nil if ptr.null?
|
189
|
+
return Device::new(ptr.read_pointer)
|
190
|
+
end
|
218
191
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
192
|
+
get_info("Device", :cl_uint, "partition_max_sub_devices")
|
193
|
+
|
194
|
+
##
|
195
|
+
# @!method partition_properties()
|
196
|
+
# Returns the list of partition types supported by the Device
|
197
|
+
def partition_properties
|
198
|
+
ptr1 = MemoryPointer::new( :size_t, 1)
|
199
|
+
error = OpenCL.clGetDeviceInfo(self, PARTITION_PROPERTIES, 0, nil, ptr1)
|
200
|
+
error_check(error)
|
201
|
+
ptr2 = MemoryPointer::new( ptr1.read_size_t )
|
202
|
+
error = OpenCL.clGetDeviceInfo(self, PARTITION_PROPERTIES, ptr1.read_size_t, ptr2, nil)
|
203
|
+
error_check(error)
|
204
|
+
arr = ptr2.get_array_of_cl_device_partition_property(0, ptr1.read_size_t/ OpenCL.find_type(:cl_device_partition_property).size)
|
205
|
+
arr.reject! { |e| e.null? }
|
206
|
+
return arr.collect { |e| Partition::new(e.to_i) }
|
207
|
+
end
|
208
|
+
|
209
|
+
get_info("Device", :cl_device_affinity_domain, "partition_affinity_domain")
|
210
|
+
|
211
|
+
##
|
212
|
+
# @!method partition_type()
|
213
|
+
# Returns a list of :cl_device_partition_property used to create the Device
|
214
|
+
def partition_type
|
215
|
+
ptr1 = MemoryPointer::new( :size_t, 1)
|
216
|
+
error = OpenCL.clGetDeviceInfo(self, PARTITION_TYPE, 0, nil, ptr1)
|
217
|
+
error_check(error)
|
218
|
+
ptr2 = MemoryPointer::new( ptr1.read_size_t )
|
219
|
+
error = OpenCL.clGetDeviceInfo(self, PARTITION_TYPE, ptr1.read_size_t, ptr2, nil)
|
220
|
+
error_check(error)
|
221
|
+
arr = ptr2.get_array_of_cl_device_partition_property(0, ptr1.read_size_t/ OpenCL.find_type(:cl_device_partition_property).size)
|
222
|
+
return [] if arr.length == 0
|
223
|
+
ptype = arr.first.to_i
|
231
224
|
arr_2 = []
|
232
|
-
arr_2.push(Partition::new(
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
i
|
238
|
-
|
225
|
+
arr_2.push( Partition::new(ptype) )
|
226
|
+
return arr_2 if arr.length == 1
|
227
|
+
case ptype
|
228
|
+
when Partition::BY_NAMES_EXT
|
229
|
+
i = 1
|
230
|
+
while arr[i].to_i - (0x1 << Pointer.size * 8) != Partition::BY_NAMES_LIST_END_EXT do
|
231
|
+
arr_2.push( arr[i].to_i )
|
232
|
+
i += 1
|
233
|
+
return arr_2 if arr.length <= i
|
234
|
+
end
|
235
|
+
arr_2.push( Partition::new(Partition::BY_NAMES_LIST_END_EXT) )
|
236
|
+
arr_2.push( 0 )
|
237
|
+
when Partition::EQUALLY
|
238
|
+
arr_2.push(arr[1].to_i)
|
239
|
+
arr_2.push( 0 )
|
240
|
+
when Partition::BY_COUNTS
|
241
|
+
i = 1
|
242
|
+
while arr[i].to_i != Partition::BY_COUNTS_LIST_END do
|
243
|
+
arr_2.push( arr[i].to_i )
|
244
|
+
i += 1
|
245
|
+
return arr_2 if arr.length <= i
|
246
|
+
end
|
247
|
+
arr_2.push( Partition::new(Partition::BY_COUNTS_LIST_END) )
|
248
|
+
arr_2.push( 0 )
|
239
249
|
end
|
240
|
-
arr_2[i] = Partition::new(Partition::BY_NAMES_LIST_END_EXT)
|
241
|
-
arr_2[i+1] = 0
|
242
250
|
return arr_2
|
243
|
-
else
|
244
|
-
return arr.collect { |e| Partition::new(e.to_i) }
|
245
251
|
end
|
246
|
-
end
|
247
|
-
#eval get_info_array("Device", :cl_device_partition_property, "PARTITION_TYPE")
|
248
252
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
253
|
+
get_info("Device", :size_t, "printf_buffer_size")
|
254
|
+
get_info("Device", :cl_bool, "preferred_interop_user_sync")
|
255
|
+
get_info("Device", :cl_uint, "reference_count")
|
256
|
+
#undef_method :min_data_type_align_size
|
257
|
+
|
258
|
+
# Partitions the Device in serveral sub-devices
|
259
|
+
#
|
260
|
+
# ==== Attributes
|
261
|
+
#
|
262
|
+
# * +properties+ - an Array of :cl_device_partition_property
|
263
|
+
#
|
264
|
+
# ==== Returns
|
265
|
+
#
|
266
|
+
# an Array of Device
|
267
|
+
def create_sub_devices( properties )
|
268
|
+
return OpenCL.create_sub_devices( self, properties )
|
269
|
+
end
|
256
270
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
271
|
+
# Partitions the Device in serveral sub-devices by affinity domain
|
272
|
+
#
|
273
|
+
# ==== Attributes
|
274
|
+
#
|
275
|
+
# * +affinity_domain+ - the :cl_device_partition_property specifying the target affinity domain
|
276
|
+
#
|
277
|
+
# ==== Returns
|
278
|
+
#
|
279
|
+
# an Array of Device
|
280
|
+
def partition_by_affinity_domain( affinity_domain = AFFINITY_DOMAIN_NEXT_PARTITIONABLE )
|
281
|
+
return OpenCL.create_sub_devices( self, [ PARTITION_BY_AFFINITY_DOMAIN, affinity_domain ] )
|
282
|
+
end
|
265
283
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
284
|
+
# Partitions the Device in serveral sub-devices containing compute_unit_number compute units
|
285
|
+
#
|
286
|
+
# ==== Attributes
|
287
|
+
#
|
288
|
+
# * +compute_unit_number+ - the number of compute units in each sub-device
|
289
|
+
#
|
290
|
+
# ==== Returns
|
291
|
+
#
|
292
|
+
# an Array of Device
|
293
|
+
def partition_equally( compute_unit_number = 1 )
|
294
|
+
return OpenCL.create_sub_devices( self, [ PARTITION_EQUALLY, compute_unit_number ] )
|
295
|
+
end
|
278
296
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
297
|
+
# Partitions the Device in serveral sub-devices each containing a specific number of compute units
|
298
|
+
#
|
299
|
+
# ==== Attributes
|
300
|
+
#
|
301
|
+
# * +compute_unit_count_list+ - an Array of compute unit counts
|
302
|
+
#
|
303
|
+
# ==== Returns
|
304
|
+
#
|
305
|
+
# an Array of Device
|
306
|
+
def partition_by_counts( *compute_unit_count_list )
|
307
|
+
compute_unit_count_list = [1] if compute_unit_count_list == []
|
308
|
+
compute_unit_count_list.flatten!
|
309
|
+
return OpenCL.create_sub_devices( self, [ PARTITION_BY_COUNTS] + compute_unit_count_list + [ PARTITION_BY_COUNTS_LIST_END ] )
|
310
|
+
end
|
291
311
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
#
|
298
|
-
# ==== Returns
|
299
|
-
#
|
300
|
-
# an Array of Device
|
301
|
-
def partition_equally( compute_unit_number = 1 )
|
302
|
-
return OpenCL.create_sub_devices( self, [ PARTITION_EQUALLY, compute_unit_number ] )
|
303
|
-
end
|
312
|
+
def partition_by_names_intel( *compute_unit_name_list )
|
313
|
+
compute_unit_name_list = [0] if compute_unit_name_list == []
|
314
|
+
compute_unit_name_list.flatten!
|
315
|
+
return OpenCL.create_sub_devices( self, [ Partition::BY_NAMES_INTEL ] + compute_unit_name_list + [ Partition::BY_NAMES_LIST_END_INTEL ] )
|
316
|
+
end
|
304
317
|
|
305
|
-
# Partitions the Device in serveral sub-devices each containing a specific number of compute units
|
306
|
-
#
|
307
|
-
# ==== Attributes
|
308
|
-
#
|
309
|
-
# * +compute_unit_number_list+ - an Array of compute unit number
|
310
|
-
#
|
311
|
-
# ==== Returns
|
312
|
-
#
|
313
|
-
# an Array of Device
|
314
|
-
def partition_by_count( compute_unit_number_list = [1] )
|
315
|
-
return OpenCL.create_sub_devices( self, [ PARTITION_BY_COUNTS] + compute_unit_number_list + [ PARTITION_BY_COUNTS_LIST_END ] )
|
316
318
|
end
|
317
319
|
|
318
|
-
|
319
|
-
|
320
|
+
|
321
|
+
module OpenCL20
|
322
|
+
extend InnerGenerator
|
323
|
+
|
324
|
+
get_info("Device", :size_t, "global_variable_preferred_total_size")
|
325
|
+
get_info("Device", :cl_uint, "image_base_address_alignment")
|
326
|
+
get_info("Device", :cl_uint, "image_pitch_alignment")
|
327
|
+
get_info("Device", :cl_uint, "max_on_device_events")
|
328
|
+
get_info("Device", :cl_uint, "max_on_device_queues")
|
329
|
+
get_info("Device", :cl_uint, "max_pipe_args")
|
330
|
+
get_info("Device", :cl_uint, "max_read_image_args")
|
331
|
+
get_info("Device", :cl_uint, "max_read_write_image_args")
|
332
|
+
get_info("Device", :cl_uint, "pipe_max_active_reservations")
|
333
|
+
get_info("Device", :cl_uint, "pipe_max_packet_size")
|
334
|
+
get_info("Device", :cl_uint, "preferred_global_atomic_alignment")
|
335
|
+
get_info("Device", :cl_uint, "preferred_local_atomic_alignment")
|
336
|
+
get_info("Device", :cl_uint, "preferred_platform_atomic_alignment")
|
337
|
+
get_info("Device", :cl_uint, "queue_on_device_max_size")
|
338
|
+
get_info("Device", :cl_uint, "queue_on_device_preferred_size")
|
339
|
+
get_info("Device", :cl_command_queue_properties, "queue_on_device_properties")
|
340
|
+
get_info("Device", :cl_command_queue_properties, "queue_on_host_properties")
|
341
|
+
get_info_array("Device", :cl_device_svm_capabilities, "svm_capabilities")
|
342
|
+
|
320
343
|
end
|
321
344
|
|
322
|
-
|
323
|
-
|
345
|
+
module OpenCL21
|
346
|
+
extend InnerGenerator
|
347
|
+
|
348
|
+
get_info("Device", :string, "il_version")
|
349
|
+
|
350
|
+
def il_version_number
|
351
|
+
return il_version.scan(/(\d+\.\d+)/).first.first.to_f
|
352
|
+
end
|
353
|
+
|
354
|
+
get_info_array("Device", :cl_uint, "max_num_sub_groups")
|
355
|
+
get_info_array("Device", :cl_bool, "subgroup_independent_forward_progress")
|
356
|
+
|
357
|
+
def get_device_and_host_timer
|
358
|
+
return OpenCL.get_device_and_host_timer( self )
|
359
|
+
end
|
360
|
+
|
361
|
+
def get_host_timer
|
362
|
+
return OpenCL.get_host_timer( self )
|
363
|
+
end
|
364
|
+
|
324
365
|
end
|
325
366
|
|
367
|
+
register_extension( :v11, OpenCL11, "platform.version_number >= 1.1" )
|
368
|
+
register_extension( :v12, OpenCL12, "platform.version_number >= 1.2" )
|
369
|
+
register_extension( :v20, OpenCL20, "platform.version_number >= 2.0" )
|
370
|
+
register_extension( :v21, OpenCL21, "platform.version_number >= 2.1" )
|
371
|
+
|
326
372
|
end
|
327
373
|
|
328
374
|
end
|