opencl_ruby_ffi 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|