BOAST 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/BOAST.gemspec +4 -3
- data/lib/BOAST.rb +1 -0
- data/lib/BOAST/Language/Arithmetic.rb +5 -1
- data/lib/BOAST/Language/BOAST_OpenCL.rb +6 -6
- data/lib/BOAST/Language/Case.rb +11 -11
- data/lib/BOAST/Language/Comment.rb +2 -2
- data/lib/BOAST/Language/Config.rb +5 -5
- data/lib/BOAST/Language/DataTypes.rb +31 -29
- data/lib/BOAST/Language/Expression.rb +16 -16
- data/lib/BOAST/Language/For.rb +6 -6
- data/lib/BOAST/Language/FuncCall.rb +7 -7
- data/lib/BOAST/Language/HighLevelOperators.rb +6 -6
- data/lib/BOAST/Language/If.rb +7 -7
- data/lib/BOAST/Language/Index.rb +31 -31
- data/lib/BOAST/Language/Intrinsics.rb +27 -27
- data/lib/BOAST/Language/OpenMP.rb +19 -19
- data/lib/BOAST/Language/Operators.rb +62 -50
- data/lib/BOAST/Language/Pragma.rb +4 -4
- data/lib/BOAST/Language/Procedure.rb +47 -47
- data/lib/BOAST/Language/Slice.rb +14 -14
- data/lib/BOAST/Language/State.rb +1 -1
- data/lib/BOAST/Language/Transitions.rb +1 -1
- data/lib/BOAST/Language/Variable.rb +83 -90
- data/lib/BOAST/Language/While.rb +4 -4
- data/lib/BOAST/Optimization/Optimization.rb +61 -37
- data/lib/BOAST/Runtime/AffinityProbe.rb +99 -15
- data/lib/BOAST/Runtime/CRuntime.rb +18 -6
- data/lib/BOAST/Runtime/CUDARuntime.rb +11 -7
- data/lib/BOAST/Runtime/CoExecute.rb +77 -0
- data/lib/BOAST/Runtime/CompiledRuntime.rb +274 -110
- data/lib/BOAST/Runtime/Compilers.rb +15 -15
- data/lib/BOAST/Runtime/Config.rb +3 -0
- data/lib/BOAST/Runtime/EnergyProbe.rb +86 -71
- data/lib/BOAST/Runtime/FFIRuntime.rb +1 -1
- data/lib/BOAST/Runtime/FORTRANRuntime.rb +15 -5
- data/lib/BOAST/Runtime/MPPARuntime.rb +30 -19
- data/lib/BOAST/Runtime/OpenCLRuntime.rb +2 -2
- data/lib/BOAST/Runtime/Probe.rb +122 -41
- metadata +29 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c229720903f977f8eecf78d3d66dd4471d8a8f28
|
4
|
+
data.tar.gz: ece1f7a741ecd2025e65df571ed374931f79fd2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac2212627bbf0ff41330224ddade322cf51e73ac55c888d42fb5795985632db72759030f2f464edbc5f209fe408a1f5d2d22729bf8920d83e86fd450a2dcbf7b
|
7
|
+
data.tar.gz: f3af938b84253de6905d7984dc8d8954d5a58ca0337dda7c766fe2fa5f29b14025a6dd34425dfaa81a713f1e456a96034a5b39f881a952e97962cd24a23e415a
|
data/BOAST.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'BOAST'
|
3
|
-
s.version = "2.0
|
3
|
+
s.version = "2.1.0"
|
4
4
|
s.author = "Brice Videau"
|
5
5
|
s.email = "brice.videau@imag.fr"
|
6
6
|
s.homepage = "https://github.com/Nanosim-LIG/boast"
|
@@ -9,13 +9,14 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.files = Dir['BOAST.gemspec', 'LICENSE', 'README.md', 'lib/**/*']
|
10
10
|
s.has_rdoc = false
|
11
11
|
s.license = 'BSD-2-Clause'
|
12
|
-
s.required_ruby_version = '>=
|
12
|
+
s.required_ruby_version = '>= 2.0.0'
|
13
13
|
s.add_dependency 'narray', '~> 0.6.0', '>=0.6.0.8'
|
14
14
|
s.add_dependency 'narray_ffi', '~> 1.2', '>=1.2.0'
|
15
15
|
s.add_dependency 'opencl_ruby_ffi', '~> 1.3', '>=1.3.2'
|
16
16
|
s.add_dependency 'systemu', '~> 2', '>=2.2.0'
|
17
17
|
s.add_dependency 'os', '~> 0.9', '>=0.9.6'
|
18
|
-
s.add_dependency 'PAPI', '~> 0', '>=0.
|
18
|
+
s.add_dependency 'PAPI', '~> 1.0', '>=1.0.0'
|
19
|
+
s.add_dependency 'hwloc', '~> 0.3', '>=0.3.0'
|
19
20
|
s.add_dependency 'ffi', '~> 1.9', '>=1.9.3'
|
20
21
|
s.add_dependency 'rgl', '~> 0.5', '>=0.5.1'
|
21
22
|
s.add_dependency 'rake', '>=0.9'
|
data/lib/BOAST.rb
CHANGED
@@ -44,6 +44,7 @@ require 'BOAST/Runtime/FORTRANRuntime.rb'
|
|
44
44
|
require 'BOAST/Runtime/FFIRuntime.rb'
|
45
45
|
require 'BOAST/Runtime/MPPARuntime.rb'
|
46
46
|
require 'BOAST/Runtime/CKernel.rb'
|
47
|
+
require 'BOAST/Runtime/CoExecute.rb'
|
47
48
|
require 'BOAST/Runtime/NonRegression.rb'
|
48
49
|
require 'BOAST/Runtime/RubyEnergyMonitor.rb'
|
49
50
|
require 'BOAST/Language/Parens.rb'
|
@@ -132,7 +132,7 @@ module BOAST
|
|
132
132
|
alias | or
|
133
133
|
|
134
134
|
def cast(type)
|
135
|
-
return type.copy("(#{type.type.decl} *)#{self}")
|
135
|
+
return type.copy("(#{type.type.decl}#{type.dimension? ? " *" : ""})#{self}")
|
136
136
|
end
|
137
137
|
|
138
138
|
def components( range )
|
@@ -151,5 +151,9 @@ module BOAST
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
+
def coerce(other)
|
155
|
+
return [other.to_var, self]
|
156
|
+
end
|
157
|
+
|
154
158
|
end
|
155
159
|
end
|
@@ -42,7 +42,7 @@ module BOAST
|
|
42
42
|
return FuncCall::new("get_global_size", dim, :return => Sizet)
|
43
43
|
elsif lang == CUDA then
|
44
44
|
d = OCL_CUDA_DIM_ASSOC[dim]
|
45
|
-
raise "Unsupported dimension!"
|
45
|
+
raise "Unsupported dimension!" unless d
|
46
46
|
return eval "CUDA_GRIDDIM.#{d}*CUDA_BLOCKDIM.#{d}"
|
47
47
|
else
|
48
48
|
raise "Unsupported language!"
|
@@ -54,7 +54,7 @@ module BOAST
|
|
54
54
|
return FuncCall::new("get_global_id",dim, :return => Sizet)
|
55
55
|
elsif lang == CUDA then
|
56
56
|
d = OCL_CUDA_DIM_ASSOC[dim]
|
57
|
-
raise "Unsupported dimension!"
|
57
|
+
raise "Unsupported dimension!" unless d
|
58
58
|
return eval "CUDA_THREADIDX.#{d}+CUDA_BLOCKIDX.#{d}*CUDA_BLOCKDIM.#{d}"
|
59
59
|
else
|
60
60
|
raise "Unsupported language!"
|
@@ -66,7 +66,7 @@ module BOAST
|
|
66
66
|
return FuncCall::new("get_local_size",dim, :return => Sizet)
|
67
67
|
elsif lang == CUDA then
|
68
68
|
d = OCL_CUDA_DIM_ASSOC[dim]
|
69
|
-
raise "Unsupported dimension!"
|
69
|
+
raise "Unsupported dimension!" unless d
|
70
70
|
return eval "CUDA_BLOCKDIM.#{d}"
|
71
71
|
else
|
72
72
|
raise "Unsupported language!"
|
@@ -78,7 +78,7 @@ module BOAST
|
|
78
78
|
return FuncCall::new("get_local_id",dim, :return => Sizet)
|
79
79
|
elsif lang == CUDA then
|
80
80
|
d = OCL_CUDA_DIM_ASSOC[dim]
|
81
|
-
raise "Unsupported dimension!"
|
81
|
+
raise "Unsupported dimension!" unless d
|
82
82
|
return eval "CUDA_THREADIDX.#{d}"
|
83
83
|
else
|
84
84
|
raise "Unsupported language!"
|
@@ -90,7 +90,7 @@ module BOAST
|
|
90
90
|
return FuncCall::new("get_num_groups",dim, :return => Sizet)
|
91
91
|
elsif lang == CUDA then
|
92
92
|
d = OCL_CUDA_DIM_ASSOC[dim]
|
93
|
-
raise "Unsupported dimension!"
|
93
|
+
raise "Unsupported dimension!" unless d
|
94
94
|
return eval "CUDA_GRIDDIM.#{d}"
|
95
95
|
else
|
96
96
|
raise "Unsupported language!"
|
@@ -102,7 +102,7 @@ module BOAST
|
|
102
102
|
return FuncCall::new("get_group_id",dim, :return => Sizet)
|
103
103
|
elsif lang == CUDA then
|
104
104
|
d = OCL_CUDA_DIM_ASSOC[dim]
|
105
|
-
raise "Unsupported dimension!"
|
105
|
+
raise "Unsupported dimension!" unless d
|
106
106
|
return eval "CUDA_BLOCKIDX.#{d}"
|
107
107
|
else
|
108
108
|
raise "Unsupported language!"
|
data/lib/BOAST/Language/Case.rb
CHANGED
@@ -35,17 +35,17 @@ module BOAST
|
|
35
35
|
def to_s
|
36
36
|
s = ""
|
37
37
|
if @constants then
|
38
|
-
s
|
38
|
+
s << case_string(@constants)
|
39
39
|
else
|
40
|
-
s
|
40
|
+
s << default_string
|
41
41
|
end
|
42
42
|
return s
|
43
43
|
end
|
44
44
|
|
45
45
|
def open
|
46
46
|
s = ""
|
47
|
-
s
|
48
|
-
s
|
47
|
+
s << indent
|
48
|
+
s << to_s
|
49
49
|
output.puts s
|
50
50
|
increment_indent_level
|
51
51
|
return self
|
@@ -54,8 +54,8 @@ module BOAST
|
|
54
54
|
def close
|
55
55
|
if @constants and break_string then
|
56
56
|
s = ""
|
57
|
-
s
|
58
|
-
s
|
57
|
+
s << indent
|
58
|
+
s << break_string
|
59
59
|
output.puts s
|
60
60
|
end
|
61
61
|
decrement_indent_level
|
@@ -117,14 +117,14 @@ module BOAST
|
|
117
117
|
|
118
118
|
def to_s
|
119
119
|
s = ""
|
120
|
-
s
|
120
|
+
s << switch_string(@expression)
|
121
121
|
return s
|
122
122
|
end
|
123
123
|
|
124
124
|
def open
|
125
125
|
s = ""
|
126
|
-
s
|
127
|
-
s
|
126
|
+
s << indent
|
127
|
+
s << to_s
|
128
128
|
output.puts s
|
129
129
|
increment_indent_level
|
130
130
|
return self
|
@@ -145,8 +145,8 @@ module BOAST
|
|
145
145
|
def close
|
146
146
|
decrement_indent_level
|
147
147
|
s = ""
|
148
|
-
s
|
149
|
-
s
|
148
|
+
s << indent
|
149
|
+
s << end_string
|
150
150
|
output.puts s
|
151
151
|
return self
|
152
152
|
end
|
@@ -26,13 +26,13 @@ module BOAST
|
|
26
26
|
|
27
27
|
def to_s_fortran
|
28
28
|
s = ""
|
29
|
-
@comment.each_line { |l| s
|
29
|
+
@comment.each_line { |l| s << "! #{l}" }
|
30
30
|
return s
|
31
31
|
end
|
32
32
|
|
33
33
|
def to_s_c
|
34
34
|
s = ""
|
35
|
-
@comment.each_line { |l| s
|
35
|
+
@comment.each_line { |l| s << "/* #{l.delete("\n")} */\n" }
|
36
36
|
return s
|
37
37
|
end
|
38
38
|
|
@@ -22,12 +22,12 @@ module BOAST
|
|
22
22
|
|
23
23
|
def assert_boast_config_dir
|
24
24
|
home_config_dir = ENV["XDG_CONFIG_HOME"]
|
25
|
-
home_config_dir = "#{Dir.home}/.config"
|
26
|
-
Dir.mkdir( home_config_dir )
|
27
|
-
return nil
|
25
|
+
home_config_dir = "#{Dir.home}/.config" unless home_config_dir
|
26
|
+
Dir.mkdir( home_config_dir ) unless File::exist?( home_config_dir )
|
27
|
+
return nil unless File::directory?(home_config_dir)
|
28
28
|
boast_config_dir = "#{home_config_dir}/BOAST"
|
29
|
-
Dir.mkdir( boast_config_dir )
|
30
|
-
return nil
|
29
|
+
Dir.mkdir( boast_config_dir ) unless File::exist?( boast_config_dir )
|
30
|
+
return nil unless File::directory?(boast_config_dir)
|
31
31
|
return boast_config_dir
|
32
32
|
end
|
33
33
|
|
@@ -44,7 +44,7 @@ module BOAST
|
|
44
44
|
|
45
45
|
def decl
|
46
46
|
return "integer(kind=#{get_default_int_size})" if lang == FORTRAN
|
47
|
-
|
47
|
+
unless @signed then
|
48
48
|
return "size_t" if [C, CL, CUDA].include?( lang )
|
49
49
|
else
|
50
50
|
return "ptrdiff_t" if [C, CL, CUDA].include?( lang )
|
@@ -56,7 +56,7 @@ module BOAST
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def signed?
|
59
|
-
return
|
59
|
+
return signed
|
60
60
|
end
|
61
61
|
|
62
62
|
def suffix
|
@@ -101,7 +101,7 @@ module BOAST
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def signed?
|
104
|
-
return
|
104
|
+
return signed
|
105
105
|
end
|
106
106
|
|
107
107
|
def to_hash
|
@@ -137,9 +137,9 @@ module BOAST
|
|
137
137
|
def suffix
|
138
138
|
s = ""
|
139
139
|
if [C, CL, CUDA].include?( lang ) then
|
140
|
-
s
|
140
|
+
s << "f" if @size == 4
|
141
141
|
elsif lang == FORTRAN then
|
142
|
-
s
|
142
|
+
s << "_wp" if @size == 8
|
143
143
|
end
|
144
144
|
return s
|
145
145
|
end
|
@@ -177,7 +177,7 @@ module BOAST
|
|
177
177
|
end
|
178
178
|
if hash[:vector_length] and hash[:vector_length] > 1 then
|
179
179
|
@vector_length = hash[:vector_length]
|
180
|
-
raise "Vectors need to have their element size specified!"
|
180
|
+
raise "Vectors need to have their element size specified!" unless @size
|
181
181
|
else
|
182
182
|
@vector_length = 1
|
183
183
|
end
|
@@ -197,7 +197,7 @@ module BOAST
|
|
197
197
|
end
|
198
198
|
|
199
199
|
def signed?
|
200
|
-
return
|
200
|
+
return @signed
|
201
201
|
end
|
202
202
|
|
203
203
|
def decl
|
@@ -208,7 +208,7 @@ module BOAST
|
|
208
208
|
if lang == C then
|
209
209
|
if @vector_length == 1 then
|
210
210
|
s = ""
|
211
|
-
s
|
211
|
+
s << "u" unless @signed
|
212
212
|
return s+"int#{8*@size}_t" if @size
|
213
213
|
return s+"int"
|
214
214
|
elsif @vector_length > 1 then
|
@@ -216,33 +216,35 @@ module BOAST
|
|
216
216
|
end
|
217
217
|
else
|
218
218
|
s =""
|
219
|
-
|
220
|
-
|
219
|
+
unless @signed then
|
220
|
+
s << "u"
|
221
|
+
s << "nsigned " if lang == CUDA and @vector_length == 1
|
222
|
+
end
|
221
223
|
case @size
|
222
224
|
when 1
|
223
|
-
s
|
225
|
+
s << "char"
|
224
226
|
when 2
|
225
|
-
s
|
227
|
+
s << "short"
|
226
228
|
when 4
|
227
|
-
s
|
229
|
+
s << "int"
|
228
230
|
when 8
|
229
231
|
if lang == CUDA
|
230
232
|
case @vector_length
|
231
233
|
when 1
|
232
|
-
s
|
234
|
+
s << "long long"
|
233
235
|
else
|
234
|
-
s
|
236
|
+
s << "longlong"
|
235
237
|
end
|
236
238
|
else
|
237
|
-
s
|
239
|
+
s << "long"
|
238
240
|
end
|
239
241
|
when nil
|
240
|
-
s
|
242
|
+
s << "int"
|
241
243
|
else
|
242
244
|
raise "Unsupported integer size!"
|
243
245
|
end
|
244
246
|
if @vector_length > 1 then
|
245
|
-
s
|
247
|
+
s << "#{@vector_length}"
|
246
248
|
end
|
247
249
|
return s
|
248
250
|
end
|
@@ -250,9 +252,9 @@ module BOAST
|
|
250
252
|
|
251
253
|
def decl_ffi
|
252
254
|
t = ""
|
253
|
-
t
|
254
|
-
t
|
255
|
-
t
|
255
|
+
t << "u" unless @signed
|
256
|
+
t << "int"
|
257
|
+
t << "#{@size*8}" if @size
|
256
258
|
return t.to_sym
|
257
259
|
end
|
258
260
|
|
@@ -307,7 +309,7 @@ module BOAST
|
|
307
309
|
|
308
310
|
def define_c
|
309
311
|
s = indent
|
310
|
-
s
|
312
|
+
s << decl_c + " {"
|
311
313
|
output.puts s
|
312
314
|
increment_indent_level
|
313
315
|
@members_array.each { |value|
|
@@ -315,15 +317,15 @@ module BOAST
|
|
315
317
|
}
|
316
318
|
decrement_indent_level
|
317
319
|
s = indent
|
318
|
-
s
|
319
|
-
s
|
320
|
+
s << "}"
|
321
|
+
s << finalize
|
320
322
|
output.print s
|
321
323
|
return self
|
322
324
|
end
|
323
325
|
|
324
326
|
def define_fortran
|
325
327
|
s = indent
|
326
|
-
s
|
328
|
+
s << "TYPE :: #{@name}\n"
|
327
329
|
output.puts s
|
328
330
|
increment_indent_level
|
329
331
|
@members_array.each { |value|
|
@@ -331,16 +333,16 @@ module BOAST
|
|
331
333
|
}
|
332
334
|
decrement_indent_level
|
333
335
|
s = indent
|
334
|
-
s
|
335
|
-
s
|
336
|
+
s << "END TYPE #{@name}"
|
337
|
+
s << finalize
|
336
338
|
output.print s
|
337
339
|
return self
|
338
340
|
end
|
339
341
|
|
340
342
|
def finalize
|
341
343
|
s = ""
|
342
|
-
s
|
343
|
-
s
|
344
|
+
s << ";" if [C, CL, CUDA].include?( lang )
|
345
|
+
s << "\n"
|
344
346
|
return s
|
345
347
|
end
|
346
348
|
|
@@ -21,7 +21,7 @@ module BOAST
|
|
21
21
|
|
22
22
|
def method_missing(m, *a, &b)
|
23
23
|
var = to_var
|
24
|
-
if var.type.
|
24
|
+
if var.type.kind_of?(CStruct) and var.type.members[m.to_s] then
|
25
25
|
return struct_reference(type.members[m.to_s])
|
26
26
|
elsif var.vector? and m.to_s[0] == 's' and lang != CUDA then
|
27
27
|
required_set = m.to_s[1..-1].chars.to_a
|
@@ -56,23 +56,23 @@ module BOAST
|
|
56
56
|
return oper.string(op1, op2, return_type) unless oper.kind_of?(String)
|
57
57
|
s = ""
|
58
58
|
if op1 then
|
59
|
-
s
|
60
|
-
s
|
61
|
-
s
|
62
|
-
end
|
63
|
-
s
|
64
|
-
s
|
65
|
-
s
|
59
|
+
s << "(" if (oper == "*" or oper == "/")
|
60
|
+
s << op1.to_s
|
61
|
+
s << ")" if (oper == "*" or oper == "/")
|
62
|
+
end
|
63
|
+
s << " " unless oper == "++" or oper == "."
|
64
|
+
s << oper unless ( oper == "&" and lang == FORTRAN )
|
65
|
+
s << " " unless oper == "." or oper == "&" or ( oper == "*" and op1.nil? )
|
66
66
|
if op2 then
|
67
|
-
s
|
68
|
-
s
|
69
|
-
s
|
67
|
+
s << "(" if (oper == "*" or oper == "/" or oper == "-")
|
68
|
+
s << op2.to_s
|
69
|
+
s << ")" if (oper == "*" or oper == "/" or oper == "-")
|
70
70
|
end
|
71
71
|
return s
|
72
72
|
end
|
73
73
|
|
74
74
|
private :to_s_base
|
75
|
-
|
75
|
+
|
76
76
|
def to_var
|
77
77
|
op1 = nil
|
78
78
|
op1 = @operand1.to_var if @operand1.respond_to?(:to_var)
|
@@ -93,7 +93,7 @@ module BOAST
|
|
93
93
|
return Variable::new(res_exp, get_default_type)
|
94
94
|
end
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
def to_s
|
98
98
|
op1 = nil
|
99
99
|
op1 = @operand1.to_var if @operand1.respond_to?(:to_var)
|
@@ -114,9 +114,9 @@ module BOAST
|
|
114
114
|
|
115
115
|
def pr
|
116
116
|
s=""
|
117
|
-
s
|
118
|
-
s
|
119
|
-
s
|
117
|
+
s << indent
|
118
|
+
s << to_s
|
119
|
+
s << ";" if [C, CL, CUDA].include?( lang )
|
120
120
|
output.puts s
|
121
121
|
return self
|
122
122
|
end
|
data/lib/BOAST/Language/For.rb
CHANGED
@@ -13,7 +13,7 @@ module BOAST
|
|
13
13
|
|
14
14
|
# returns the Boolean evaluation of the unroll attribute.
|
15
15
|
def unroll?
|
16
|
-
return
|
16
|
+
return @unroll
|
17
17
|
end
|
18
18
|
|
19
19
|
# Sets the unroll attribute to val.
|
@@ -132,7 +132,7 @@ module BOAST
|
|
132
132
|
else
|
133
133
|
step = @step.to_i
|
134
134
|
end
|
135
|
-
raise "Invalid bounds (not constants)!"
|
135
|
+
raise "Invalid bounds (not constants)!" unless ( first and last and step )
|
136
136
|
ensure
|
137
137
|
pop_env( :replace_constants )
|
138
138
|
end
|
@@ -159,8 +159,8 @@ module BOAST
|
|
159
159
|
def open
|
160
160
|
@openmp.open if @openmp
|
161
161
|
s=""
|
162
|
-
s
|
163
|
-
s
|
162
|
+
s << indent
|
163
|
+
s << to_s
|
164
164
|
output.puts s
|
165
165
|
increment_indent_level
|
166
166
|
return self
|
@@ -188,8 +188,8 @@ module BOAST
|
|
188
188
|
def close
|
189
189
|
decrement_indent_level
|
190
190
|
s = ""
|
191
|
-
s
|
192
|
-
s
|
191
|
+
s << indent
|
192
|
+
s << end_string
|
193
193
|
output.puts s
|
194
194
|
@openmp.close if @openmp
|
195
195
|
return self
|