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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/BOAST.gemspec +4 -3
  3. data/lib/BOAST.rb +1 -0
  4. data/lib/BOAST/Language/Arithmetic.rb +5 -1
  5. data/lib/BOAST/Language/BOAST_OpenCL.rb +6 -6
  6. data/lib/BOAST/Language/Case.rb +11 -11
  7. data/lib/BOAST/Language/Comment.rb +2 -2
  8. data/lib/BOAST/Language/Config.rb +5 -5
  9. data/lib/BOAST/Language/DataTypes.rb +31 -29
  10. data/lib/BOAST/Language/Expression.rb +16 -16
  11. data/lib/BOAST/Language/For.rb +6 -6
  12. data/lib/BOAST/Language/FuncCall.rb +7 -7
  13. data/lib/BOAST/Language/HighLevelOperators.rb +6 -6
  14. data/lib/BOAST/Language/If.rb +7 -7
  15. data/lib/BOAST/Language/Index.rb +31 -31
  16. data/lib/BOAST/Language/Intrinsics.rb +27 -27
  17. data/lib/BOAST/Language/OpenMP.rb +19 -19
  18. data/lib/BOAST/Language/Operators.rb +62 -50
  19. data/lib/BOAST/Language/Pragma.rb +4 -4
  20. data/lib/BOAST/Language/Procedure.rb +47 -47
  21. data/lib/BOAST/Language/Slice.rb +14 -14
  22. data/lib/BOAST/Language/State.rb +1 -1
  23. data/lib/BOAST/Language/Transitions.rb +1 -1
  24. data/lib/BOAST/Language/Variable.rb +83 -90
  25. data/lib/BOAST/Language/While.rb +4 -4
  26. data/lib/BOAST/Optimization/Optimization.rb +61 -37
  27. data/lib/BOAST/Runtime/AffinityProbe.rb +99 -15
  28. data/lib/BOAST/Runtime/CRuntime.rb +18 -6
  29. data/lib/BOAST/Runtime/CUDARuntime.rb +11 -7
  30. data/lib/BOAST/Runtime/CoExecute.rb +77 -0
  31. data/lib/BOAST/Runtime/CompiledRuntime.rb +274 -110
  32. data/lib/BOAST/Runtime/Compilers.rb +15 -15
  33. data/lib/BOAST/Runtime/Config.rb +3 -0
  34. data/lib/BOAST/Runtime/EnergyProbe.rb +86 -71
  35. data/lib/BOAST/Runtime/FFIRuntime.rb +1 -1
  36. data/lib/BOAST/Runtime/FORTRANRuntime.rb +15 -5
  37. data/lib/BOAST/Runtime/MPPARuntime.rb +30 -19
  38. data/lib/BOAST/Runtime/OpenCLRuntime.rb +2 -2
  39. data/lib/BOAST/Runtime/Probe.rb +122 -41
  40. metadata +29 -8
@@ -1,26 +1,75 @@
1
1
  module BOAST
2
2
 
3
3
  # @private
4
- module AffinityProbe
4
+ module HwlocProbe
5
5
  extend PrivateStateAccessor
6
6
 
7
+ class << self
8
+ attr_accessor :topology
9
+ end
10
+ @topology = nil
11
+
12
+ begin
13
+ require 'hwloc'
14
+ @topology = Hwloc::Topology::new
15
+ @topology.load
16
+ rescue LoadError => e
17
+ end
18
+
7
19
  module_function
8
20
 
9
21
  def cflags
10
- return "-D_GNU_SOURCE"
11
22
  end
12
23
 
13
24
  def header
14
- get_output.puts "#include <sched.h>"
15
25
  end
16
26
 
27
+ def preamble
28
+ end
29
+
30
+
17
31
  def decl
18
- get_output.puts " cpu_set_t _boast_affinity_mask_old;"
19
- get_output.puts " int _boast_affinity_set = 0;"
20
32
  end
21
33
 
22
34
  def configure
23
- get_output.print <<EOF
35
+ end
36
+
37
+ def start
38
+ end
39
+
40
+ def stop
41
+ end
42
+
43
+ def compute
44
+ end
45
+
46
+ def store
47
+ end
48
+
49
+ def is_available?
50
+ return !@topology.nil?
51
+ end
52
+
53
+ end
54
+
55
+ # @private
56
+ module PthreadAffinityProbe
57
+ extend PrivateStateAccessor
58
+
59
+ module_function
60
+
61
+ def cflags
62
+ return "-D_GNU_SOURCE"
63
+ end
64
+
65
+ def header
66
+ get_output.puts "#include <sched.h>"
67
+ end
68
+
69
+ def preamble
70
+ get_output.puts <<EOF
71
+ static int _boast_affinity_setup( VALUE _boast_rb_opts, cpu_set_t * _boast_affinity_mask_old );
72
+ static int _boast_affinity_setup( VALUE _boast_rb_opts, cpu_set_t * _boast_affinity_mask_old ) {
24
73
  if( _boast_rb_opts != Qnil ) {
25
74
  VALUE _boast_affinity_rb_ptr = Qnil;
26
75
 
@@ -31,18 +80,43 @@ module BOAST
31
80
  int _boast_affinity_counter;
32
81
  int _boast_affinity_cpu_number;
33
82
 
34
- if( TYPE(_boast_affinity_rb_ptr) != T_ARRAY )
83
+ if( TYPE(_boast_affinity_rb_ptr) != T_ARRAY ) {
35
84
  rb_raise(rb_eArgError, "Option :cpu_affinity should be an array!");
85
+ }
36
86
  CPU_ZERO(&_boast_affinity_mask);
37
87
  _boast_affinity_cpu_number = RARRAY_LEN(_boast_affinity_rb_ptr);
38
- for( _boast_affinity_counter = 0; _boast_affinity_counter < _boast_affinity_cpu_number; _boast_affinity_counter++ )
88
+ for( _boast_affinity_counter = 0; _boast_affinity_counter < _boast_affinity_cpu_number; _boast_affinity_counter++ ) {
39
89
  CPU_SET(FIX2INT(rb_ary_entry(_boast_affinity_rb_ptr,_boast_affinity_counter)), &_boast_affinity_mask);
40
- sched_getaffinity(getpid(), sizeof(_boast_affinity_mask_old), &_boast_affinity_mask_old);
41
- if( sched_setaffinity(getpid(), sizeof(_boast_affinity_mask), &_boast_affinity_mask) != 0)
90
+ }
91
+ pthread_getaffinity_np(pthread_self(), sizeof(*_boast_affinity_mask_old), _boast_affinity_mask_old);
92
+ if( pthread_setaffinity_np(pthread_self(), sizeof(_boast_affinity_mask), &_boast_affinity_mask) != 0) {
42
93
  rb_raise(rb_eArgError, "Invalid affinity list provided!");
43
- _boast_affinity_set = 1;
94
+ }
95
+ return 1;
44
96
  }
45
97
  }
98
+ return 0;
99
+ }
100
+
101
+ static int _boast_restore_affinity( int _boast_affinity_set, cpu_set_t * _boast_affinity_mask_old );
102
+ static int _boast_restore_affinity( int _boast_affinity_set, cpu_set_t * _boast_affinity_mask_old ){
103
+ if ( _boast_affinity_set == 1 ) {
104
+ pthread_setaffinity_np(pthread_self(), sizeof(*_boast_affinity_mask_old), _boast_affinity_mask_old);
105
+ }
106
+ return 0;
107
+ }
108
+
109
+ EOF
110
+ end
111
+
112
+ def decl
113
+ get_output.puts " cpu_set_t _boast_affinity_mask_old;"
114
+ get_output.puts " int _boast_affinity_set;"
115
+ end
116
+
117
+ def configure
118
+ get_output.print <<EOF
119
+ _boast_affinity_set = _boast_affinity_setup( _boast_rb_opts, &_boast_affinity_mask_old);
46
120
  EOF
47
121
  end
48
122
 
@@ -54,16 +128,26 @@ EOF
54
128
 
55
129
  def compute
56
130
  get_output.print <<EOF
57
- if ( _boast_affinity_set == 1 ) {
58
- sched_setaffinity(getpid(), sizeof(_boast_affinity_mask_old), &_boast_affinity_mask_old);
59
- _boast_affinity_set = 0;
60
- }
131
+ _boast_affinity_set = _boast_restore_affinity( _boast_affinity_set, &_boast_affinity_mask_old);
61
132
  EOF
62
133
  end
63
134
 
64
135
  def store
65
136
  end
66
137
 
138
+ def is_available?
139
+ return false if OS.mac?
140
+ return true
141
+ end
142
+
143
+ end
144
+
145
+ if HwlocProbe.is_available?
146
+ AffinityProbe = HwlocProbe
147
+ elsif PthreadAffinityProbe.is_available?
148
+ AffinityProbe = PthreadAffinityProbe
149
+ else
150
+ AffinityProbe = nil
67
151
  end
68
152
 
69
153
  end
@@ -25,18 +25,30 @@ module BOAST
25
25
  get_output.write @code.read
26
26
  end
27
27
 
28
+ def create_procedure_indirect_call_parameters
29
+ return @procedure.parameters.collect { |param|
30
+ par = "#{param_struct.struct_reference(param_struct.type.members[param.name.to_s])}".gsub("_boast_params.","_boast_params->")
31
+ if param.dimension then
32
+ "#{par}"
33
+ elsif param.direction == :out or param.direction == :inout or param.reference? then
34
+ "&#{par}"
35
+ else
36
+ "#{par}"
37
+ end
38
+ }
39
+ end
40
+
28
41
  def create_procedure_call_parameters
29
- params = []
30
- @procedure.parameters.each { |param|
42
+ return @procedure.parameters.collect { |param|
43
+ par = param_struct.struct_reference(param_struct.type.members[param.name.to_s])
31
44
  if param.dimension then
32
- params.push( param.name )
45
+ "#{par}"
33
46
  elsif param.direction == :out or param.direction == :inout or param.reference? then
34
- params.push( "&"+param.name )
47
+ "&#{par}"
35
48
  else
36
- params.push( param.name )
49
+ "#{par}"
37
50
  end
38
51
  }
39
- return params
40
52
  end
41
53
 
42
54
  end
@@ -13,6 +13,7 @@ module BOAST
13
13
  alias fill_decl_module_params_old fill_decl_module_params
14
14
  alias create_procedure_call_parameters_old create_procedure_call_parameters
15
15
  alias store_results_old store_results
16
+ alias create_wrapper_old create_wrapper
16
17
 
17
18
  def fill_module_header
18
19
  fill_module_header_old
@@ -49,7 +50,7 @@ extern "C" {
49
50
  EOF
50
51
  end
51
52
 
52
- def copy_array_param_from_ruby( param, ruby_param )
53
+ def copy_array_param_from_ruby(par, param, ruby_param )
53
54
  rb_ptr = Variable::new("_boast_rb_ptr", CustomType, :type_name => "VALUE")
54
55
  (rb_ptr === ruby_param).pr
55
56
  get_output.print <<EOF
@@ -58,8 +59,8 @@ EOF
58
59
  size_t _boast_array_size;
59
60
  Data_Get_Struct(_boast_rb_ptr, struct NARRAY, _boast_n_ary);
60
61
  _boast_array_size = _boast_n_ary->total * na_sizeof[_boast_n_ary->type];
61
- cudaMalloc( (void **) &#{param}, _boast_array_size);
62
- cudaMemcpy(#{param}, (void *) _boast_n_ary->ptr, _boast_array_size, cudaMemcpyHostToDevice);
62
+ cudaMalloc( (void **) &#{par}, _boast_array_size);
63
+ cudaMemcpy(#{par}, (void *) _boast_n_ary->ptr, _boast_array_size, cudaMemcpyHostToDevice);
63
64
  } else {
64
65
  rb_raise(rb_eArgError, "Wrong type of argument for %s, expecting array!", "#{param}");
65
66
  }
@@ -127,8 +128,11 @@ EOF
127
128
  EOF
128
129
  end
129
130
 
131
+ def create_wrapper
132
+ end
133
+
130
134
  def create_procedure_call_parameters
131
- return create_procedure_call_parameters_old + ["_boast_block_number", "_boast_block_size", "_boast_repeat"]
135
+ return create_procedure_call_parameters_old + ["_boast_block_number", "_boast_block_size", "_boast_params._boast_repeat"]
132
136
  end
133
137
 
134
138
  def create_procedure_call
@@ -138,7 +142,7 @@ EOF
138
142
  get_output.puts " );"
139
143
  end
140
144
 
141
- def copy_array_param_to_ruby(param, ruby_param)
145
+ def copy_array_param_to_ruby(par, param, ruby_param)
142
146
  rb_ptr = Variable::new("_boast_rb_ptr", CustomType, :type_name => "VALUE")
143
147
  (rb_ptr === ruby_param).pr
144
148
  get_output.print <<EOF
@@ -150,11 +154,11 @@ EOF
150
154
  size_t _boast_array_size;
151
155
  Data_Get_Struct(_boast_rb_ptr, struct NARRAY, _boast_n_ary);
152
156
  _boast_array_size = _boast_n_ary->total * na_sizeof[_boast_n_ary->type];
153
- cudaMemcpy((void *) _boast_n_ary->ptr, #{param}, _boast_array_size, cudaMemcpyDeviceToHost);
157
+ cudaMemcpy((void *) _boast_n_ary->ptr, #{par}, _boast_array_size, cudaMemcpyDeviceToHost);
154
158
  EOF
155
159
  end
156
160
  get_output.print <<EOF
157
- cudaFree( (void *) #{param});
161
+ cudaFree( (void *) #{par});
158
162
  } else {
159
163
  rb_raise(rb_eArgError, "Wrong type of argument for %s, expecting array!", "#{param}");
160
164
  }
@@ -0,0 +1,77 @@
1
+ module BOAST
2
+
3
+ class CKernel
4
+
5
+ module Synchro
6
+ extend FFI::Library
7
+ ffi_lib 'pthread'
8
+ typedef :pointer, :mutex
9
+ typedef :pointer, :cond
10
+ typedef :pointer, :spin
11
+ attach_function 'pthread_mutex_init', [ :mutex, :pointer ], :int
12
+ attach_function 'pthread_mutex_destroy', [ :mutex ], :int
13
+ #attach_function 'pthread_mutex_lock', [ :mutex ], :int
14
+ #attach_function 'pthread_mutex_unlock', [ :mutex ], :int
15
+
16
+ attach_function 'pthread_cond_init', [ :cond, :pointer ], :int
17
+ attach_function 'pthread_cond_destroy', [ :cond ], :int
18
+ #attach_function 'pthread_cond_wait', [ :cond, :mutex ], :int
19
+ #attach_function 'pthread_cond_broadcast', [ :cond ], :int
20
+
21
+ begin
22
+ attach_function 'pthread_spin_init', [ :spin, :int ], :int
23
+ attach_function 'pthread_spin_destroy', [ :spin ], :int
24
+ rescue FFI::NotFoundError => e
25
+ warn "spin functions not found"
26
+ end
27
+ end
28
+
29
+ def self.coexecute(kernels)
30
+ semaphore = Mutex.new
31
+ pval = FFI::MemoryPointer::new(:int)
32
+ pval.write_int(kernels.length)
33
+ if synchro == 'MUTEX' then
34
+ mutex = FFI::MemoryPointer::new(128)
35
+ Synchro.pthread_mutex_init(mutex, nil)
36
+ condition = FFI::MemoryPointer::new(128)
37
+ Synchro.pthread_cond_init(mutex, nil)
38
+ sync = [pval, mutex, condition]
39
+ else
40
+ spinlock = FFI::MemoryPointer::new(128)
41
+ Synchro.pthread_spin_init(spinlock, 0)
42
+ sync = [pval, spinlock]
43
+ end
44
+ threads = []
45
+ returns = []
46
+ args = []
47
+ kernels.each_index { |i|
48
+ kernels[i][0].build unless kernels[i][0].methods.include?(:run)
49
+ args[i] = kernels[i][1].dup
50
+ if args[i].last.kind_of?( Hash ) then
51
+ args[i][-1] = args[i].last.dup
52
+ args[i][-1][:coexecute] = sync
53
+ else
54
+ args[i].push( { :coexecute => sync } )
55
+ end
56
+ }
57
+ kernels.each_index { |i|
58
+ threads << Thread::new(i) { |j|
59
+ ret = kernels[j][0].run(*args[j])
60
+ semaphore.synchronize {
61
+ returns[j] = ret
62
+ }
63
+ }
64
+ }
65
+ threads.each { |thr| thr.join }
66
+ if synchro == 'MUTEX' then
67
+ Synchro.pthread_mutex_destroy(mutex)
68
+ Synchro.pthread_cond_destroy(condition)
69
+ else
70
+ Synchro.pthread_spin_destroy(spinlock)
71
+ end
72
+ return returns
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -41,6 +41,7 @@ module BOAST
41
41
  module CompiledRuntime
42
42
  attr_accessor :binary
43
43
  attr_accessor :source
44
+ attr_reader :param_struct
44
45
 
45
46
  private
46
47
 
@@ -206,6 +207,9 @@ module BOAST
206
207
  #include "narray.h"
207
208
  #endif
208
209
  EOF
210
+ get_output.puts "#include <pthread.h>" unless executable?
211
+ get_output.puts "#include <sys/types.h>" unless executable?
212
+ get_output.puts "#include \"ruby/thread.h\"" unless executable?
209
213
  @includes.each { |inc|
210
214
  get_output.puts "#include \"#{inc}\""
211
215
  }
@@ -214,42 +218,25 @@ EOF
214
218
  def fill_module_preamble
215
219
  get_output.print <<EOF
216
220
  VALUE #{module_name} = Qnil;
221
+
222
+ static VALUE method_run(int _boast_argc, VALUE *_boast_argv, VALUE _boast_self);
223
+
217
224
  void Init_#{module_name}();
218
- VALUE method_run(int _boast_argc, VALUE *_boast_argv, VALUE _boast_self);
219
225
  void Init_#{module_name}() {
220
226
  #{module_name} = rb_define_module("#{module_name}");
221
- rb_define_method(#{module_name}, "run", method_run, -1);
227
+ rb_define_method(#{module_name}, "__run", method_run, -1);
222
228
  }
223
- EOF
224
- end
225
229
 
226
- def fill_check_args
227
- get_output.print <<EOF
228
- VALUE _boast_rb_opts;
229
- int _boast_repeat = 1;
230
- if( _boast_argc < #{@procedure.parameters.length} || _boast_argc > #{@procedure.parameters.length + 1} )
231
- rb_raise(rb_eArgError, "Wrong number of arguments for #{@procedure.name} (%d for #{@procedure.parameters.length})!", _boast_argc);
232
- _boast_rb_opts = Qnil;
233
- if( _boast_argc == #{@procedure.parameters.length + 1} ) {
234
- _boast_rb_opts = _boast_argv[_boast_argc -1];
235
- if ( _boast_rb_opts != Qnil ) {
236
- if (TYPE(_boast_rb_opts) != T_HASH)
237
- rb_raise(rb_eArgError, "Options should be passed as a hash");
238
- }
239
- }
240
- EOF
241
- end
230
+ static VALUE _boast_check_get_options(int _boast_argc, VALUE *_boast_argv);
231
+ static VALUE _boast_check_get_options(int _boast_argc, VALUE *_boast_argv) {
232
+ VALUE _boast_rb_opts = Qnil;
233
+ _boast_rb_opts = _boast_argv[_boast_argc -1];
234
+ return _boast_rb_opts;
235
+ }
242
236
 
243
- def add_run_options
244
- get_output.print <<EOF
245
- VALUE _boast_run_opts;
246
- _boast_run_opts = rb_const_get(rb_cObject, rb_intern("BOAST"));
247
- _boast_run_opts = rb_funcall(_boast_run_opts, rb_intern("get_run_config"), 0);
248
- if ( NUM2UINT(rb_funcall(_boast_run_opts, rb_intern("size"), 0)) > 0 ) {
249
- if ( _boast_rb_opts != Qnil )
250
- rb_funcall(_boast_run_opts, rb_intern("update"), 1, _boast_rb_opts);
251
- _boast_rb_opts = _boast_run_opts;
252
- }
237
+ static int _boast_get_repeat(VALUE _boast_rb_opts);
238
+ static int _boast_get_repeat(VALUE _boast_rb_opts) {
239
+ int _boast_repeat = 1;
253
240
  if ( _boast_rb_opts != Qnil ){
254
241
  VALUE _boast_repeat_value = Qnil;
255
242
  _boast_repeat_value = rb_hash_aref(_boast_rb_opts, ID2SYM(rb_intern("repeat")));
@@ -258,25 +245,97 @@ EOF
258
245
  if(_boast_repeat < 0)
259
246
  _boast_repeat = 1;
260
247
  }
248
+ return _boast_repeat;
249
+ }
250
+ EOF
251
+
252
+ if !executable? then
253
+ get_output.print <<EOF
254
+ struct _boast_synchro_struct {
255
+ volatile int * counter;
256
+ EOF
257
+ if get_synchro == 'MUTEX' then
258
+ get_output.print <<EOF
259
+ pthread_mutex_t * mutex;
260
+ pthread_cond_t * condition;
261
+ EOF
262
+ else
263
+ get_output.print <<EOF
264
+ pthread_spinlock_t * spin;
265
+ EOF
266
+ end
267
+ get_output.print <<EOF
268
+ };
269
+ static int _boast_get_coexecute(VALUE _boast_rb_opts, struct _boast_synchro_struct * _boast_synchro);
270
+ static int _boast_get_coexecute(VALUE _boast_rb_opts, struct _boast_synchro_struct * _boast_synchro) {
271
+ int _boast_coexecute = 0;
272
+ if ( _boast_rb_opts != Qnil ){
273
+ VALUE _boast_coexecute_value = Qnil;
274
+ _boast_coexecute_value = rb_hash_aref(_boast_rb_opts, ID2SYM(rb_intern("coexecute")));
275
+ if(_boast_coexecute_value != Qnil) {
276
+ VALUE address;
277
+ _boast_coexecute = 1;
278
+ address = rb_funcall(rb_ary_entry(_boast_coexecute_value, 0), rb_intern("address"), 0);
279
+ _boast_synchro->counter = sizeof(_boast_synchro->counter) == 4 ? (void *) NUM2ULONG(address) : (void *) NUM2ULL(address);
280
+ EOF
281
+ if get_synchro == 'MUTEX' then
282
+ get_output.print <<EOF
283
+ address = rb_funcall(rb_ary_entry(_boast_coexecute_value, 1), rb_intern("address"), 0);
284
+ _boast_synchro->mutex = sizeof(_boast_synchro->mutex) == 4 ? (void *) NUM2ULONG(address) : (void *) NUM2ULL(address);
285
+ address = rb_funcall(rb_ary_entry(_boast_coexecute_value, 2), rb_intern("address"), 0);
286
+ _boast_synchro->condition = sizeof(_boast_synchro->condition) == 4 ? (void *) NUM2ULONG(address) : (void *) NUM2ULL(address);
287
+ EOF
288
+ else
289
+ get_output.print <<EOF
290
+ address = rb_funcall(rb_ary_entry(_boast_coexecute_value, 1), rb_intern("address"), 0);
291
+ _boast_synchro->spin = sizeof(_boast_synchro->spin) == 4 ? (void *) NUM2ULONG(address) : (void *) NUM2ULL(address);
292
+ EOF
293
+ end
294
+ get_output.print <<EOF
295
+ }
296
+ }
297
+ return _boast_coexecute;
298
+ }
299
+
261
300
  EOF
301
+ end
302
+ end
303
+
304
+ def fill_check_args
305
+ get_output.print <<EOF
306
+ VALUE _boast_rb_opts = Qnil;
307
+ _boast_rb_opts = _boast_check_get_options( _boast_argc, _boast_argv);
308
+ EOF
309
+ end
310
+
311
+ def add_run_options
312
+ get_output.print <<EOF
313
+ _boast_params._boast_repeat = _boast_get_repeat( _boast_rb_opts );
314
+ EOF
315
+ get_output.puts " _boast_params._boast_coexecute = _boast_get_coexecute( _boast_rb_opts, &_boast_params._boast_synchro );" unless executable?
316
+ end
317
+
318
+ def fill_param_struct
319
+ pars = @procedure.parameters.collect { |param|
320
+ param.copy(param.name, :const => nil, :constant => nil, :dir => nil, :direction => nil, :reference => nil )
321
+ }
322
+ pars.push @procedure.properties[:return].copy("_boast_ret") if @procedure.properties[:return]
323
+ pars.push Int("_boast_repeat")
324
+ pars.push Int("_boast_coexecute")
325
+ pars.push CStruct("_boast_timer", :type_name => "_boast_timer_struct", :members => [Int(:dummy)]) if @probes.include?(TimerProbe)
326
+ pars.push CStruct("_boast_synchro", :type_name => "_boast_synchro_struct", :members => [Int(:dummy)]) unless executable?
327
+ @param_struct = CStruct("_boast_params", :type_name => "_boast_#{@procedure.name}_params", :members => pars)
262
328
  end
263
329
 
264
330
  def fill_decl_module_params
265
331
  push_env(:decl_module => true) {
266
- @procedure.parameters.each { |param|
267
- param_copy = param.copy
268
- param_copy.constant = nil
269
- param_copy.direction = nil
270
- param_copy.reference = nil
271
- param_copy.decl
272
- }
273
- get_output.puts " #{@procedure.properties[:return].type.decl} _boast_ret;" if @procedure.properties[:return]
332
+ param_struct.decl
274
333
  get_output.puts " VALUE _boast_stats = rb_hash_new();"
275
334
  get_output.puts " VALUE _boast_rb_ptr = Qnil;"
276
335
  refs = false
277
- @procedure.parameters.each_with_index do |param,i|
336
+ @procedure.parameters.each { |param|
278
337
  refs = true if param.scalar_output?
279
- end
338
+ }
280
339
  if refs then
281
340
  get_output.puts " VALUE _boast_refs = rb_hash_new();"
282
341
  get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"reference_return\")),_boast_refs);"
@@ -284,26 +343,26 @@ EOF
284
343
  }
285
344
  end
286
345
 
287
- def copy_scalar_param_from_ruby( param, ruby_param )
346
+ def copy_scalar_param_from_ruby(str_par, param, ruby_param )
288
347
  case param.type
289
348
  when Int
290
- (param === FuncCall::new("NUM2INT", ruby_param)).pr if param.type.size == 4
291
- (param === FuncCall::new("NUM2LONG", ruby_param)).pr if param.type.size == 8
349
+ (str_par === FuncCall::new("NUM2INT", ruby_param)).pr if param.type.size == 4
350
+ (str_par === FuncCall::new("NUM2LONG", ruby_param)).pr if param.type.size == 8
292
351
  when Real
293
- (param === FuncCall::new("NUM2DBL", ruby_param)).pr
352
+ (str_par === FuncCall::new("NUM2DBL", ruby_param)).pr
294
353
  end
295
354
  end
296
355
 
297
- def copy_array_param_from_ruby( param, ruby_param )
356
+ def copy_array_param_from_ruby(str_par, param, ruby_param )
298
357
  rb_ptr = Variable::new("_boast_rb_ptr", CustomType, :type_name => "VALUE")
299
358
  (rb_ptr === ruby_param).pr
300
359
  get_output.print <<EOF
301
360
  if (TYPE(_boast_rb_ptr) == T_STRING) {
302
361
  #{
303
362
  if param.dimension then
304
- "#{param} = (void *)RSTRING_PTR(_boast_rb_ptr)"
363
+ "#{str_par} = (void *)RSTRING_PTR(_boast_rb_ptr)"
305
364
  else
306
- (param === param.copy("*(void *)RSTRING_PTR(_boast_rb_ptr)", :dimension => Dim(), :vector_length => 1)).to_s
365
+ (str_par === param.copy("*(void *)RSTRING_PTR(_boast_rb_ptr)", :dimension => Dim(), :vector_length => 1)).to_s
307
366
  end
308
367
  };
309
368
  } else if ( IsNArray(_boast_rb_ptr) ) {
@@ -311,13 +370,13 @@ EOF
311
370
  Data_Get_Struct(_boast_rb_ptr, struct NARRAY, _boast_n_ary);
312
371
  #{
313
372
  if param.dimension then
314
- "#{param} = (void *) _boast_n_ary->ptr"
373
+ "#{str_par} = (void *) _boast_n_ary->ptr"
315
374
  else
316
- (param === param.copy("*(void *) _boast_n_ary->ptr", :dimension => Dim(), :vector_length => 1)).to_s
375
+ (str_par === param.copy("*(void *) _boast_n_ary->ptr", :dimension => Dim(), :vector_length => 1)).to_s
317
376
  end
318
377
  };
319
378
  } else {
320
- rb_raise(rb_eArgError, "Wrong type of argument for %s, expecting array!", "#{param}");
379
+ rb_raise(rb_eArgError, "Wrong type of argument for #{param}, expecting array!");
321
380
  }
322
381
  EOF
323
382
  end
@@ -328,81 +387,151 @@ EOF
328
387
  push_env(:decl_module => true) {
329
388
  @procedure.parameters.each_index do |i|
330
389
  param = @procedure.parameters[i]
331
- if not param.dimension? and not param.vector? then
332
- copy_scalar_param_from_ruby(param, argv[i])
390
+ par = param_struct.struct_reference(param_struct.type.members[param.name.to_s])
391
+ if param.dimension? or param.vector? then
392
+ copy_array_param_from_ruby(par, param, argv[i])
333
393
  else
334
- copy_array_param_from_ruby(param, argv[i])
394
+ copy_scalar_param_from_ruby(par, param, argv[i])
335
395
  end
336
396
  end
337
397
  }
338
398
  end
339
399
 
340
- def create_procedure_call
400
+ def create_wrapper
401
+ get_output.print <<EOF
402
+ static void * boast_wrapper( void * data ) {
403
+ struct _boast_#{@procedure.name}_params * _boast_params;
404
+ _boast_params = data;
405
+ EOF
406
+ if get_synchro == 'MUTEX' then
407
+ get_output.print <<EOF
408
+ pthread_mutex_lock(_boast_params->_boast_synchro.mutex);
409
+ *_boast_params->_boast_synchro.counter -= 1;
410
+ if( *_boast_params->_boast_synchro.counter == 0 ) {
411
+ pthread_cond_broadcast( _boast_params->_boast_synchro.condition );
412
+ }
413
+ while( *_boast_params->_boast_synchro.counter ) {
414
+ pthread_cond_wait( _boast_params->_boast_synchro.condition, _boast_params->_boast_synchro.mutex );
415
+ }
416
+ pthread_mutex_unlock(_boast_params->_boast_synchro.mutex);
417
+ EOF
418
+ else
419
+ get_output.print <<EOF
420
+ pthread_spin_lock(_boast_params->_boast_synchro.spin);
421
+ *_boast_params->_boast_synchro.counter -= 1;
422
+ while( *_boast_params->_boast_synchro.counter ) {
423
+ pthread_spin_unlock(_boast_params->_boast_synchro.spin);
424
+ pthread_spin_lock(_boast_params->_boast_synchro.spin);
425
+ }
426
+ pthread_spin_unlock(_boast_params->_boast_synchro.spin);
427
+ EOF
428
+ end
429
+ get_output.puts " _boast_timer_start(&_boast_params->_boast_timer);" if @probes.include?(TimerProbe)
430
+ create_procedure_indirect_call
431
+ get_output.puts " _boast_timer_stop(&_boast_params->_boast_timer);" if @probes.include?(TimerProbe)
432
+ get_output.print <<EOF
433
+ return NULL;
434
+ }
435
+ EOF
436
+ end
437
+
438
+ def create_procedure_wrapper_call
439
+ get_output.print <<EOF
440
+ rb_thread_call_without_gvl(boast_wrapper, &_boast_params, RUBY_UBF_PROCESS, NULL);
441
+ EOF
442
+ end
443
+
444
+ def create_procedure_indirect_call
341
445
  get_output.puts " int _boast_i;"
342
- get_output.puts " for(_boast_i = 0; _boast_i < _boast_repeat; ++_boast_i){"
343
- get_output.print " _boast_ret = " if @procedure.properties[:return]
344
- get_output.print " #{method_name}( "
345
- get_output.print create_procedure_call_parameters.join(", ")
346
- get_output.print " );"
446
+ get_output.puts " for(_boast_i = 0; _boast_i < _boast_params->_boast_repeat; ++_boast_i){"
447
+ get_output.print " "
448
+ get_output.print "_boast_params->_boast_ret = " if @procedure.properties[:return]
449
+ get_output.print "#{method_name}( "
450
+ get_output.print create_procedure_indirect_call_parameters.join(", ")
451
+ get_output.puts " );"
347
452
  get_output.puts " }"
348
453
  end
349
454
 
350
- def copy_scalar_param_to_ruby(param, ruby_param)
455
+ def create_procedure_call
456
+ If("_boast_params._boast_coexecute" => lambda {
457
+ create_procedure_wrapper_call
458
+ }, :else => lambda {
459
+ TimerProbe.start if @probes.include?(TimerProbe)
460
+ get_output.puts " int _boast_i;"
461
+ get_output.puts " for(_boast_i = 0; _boast_i < _boast_params._boast_repeat; ++_boast_i){"
462
+ get_output.print " "
463
+ get_output.print "_boast_params._boast_ret = " if @procedure.properties[:return]
464
+ get_output.print "#{method_name}( "
465
+ get_output.print create_procedure_call_parameters.join(", ")
466
+ get_output.puts " );"
467
+ get_output.puts " }"
468
+ TimerProbe.stop if @probes.include?(TimerProbe)
469
+ }).pr
470
+ end
471
+
472
+ def copy_scalar_param_to_ruby(str_par, param, ruby_param)
351
473
  if param.scalar_output? then
352
474
  case param.type
353
475
  when Int
354
- get_output.puts " rb_hash_aset(_boast_refs, ID2SYM(rb_intern(\"#{param}\")),rb_int_new((long long)#{param}));" if param.type.signed?
355
- get_output.puts " rb_hash_aset(_boast_refs, ID2SYM(rb_intern(\"#{param}\")),rb_int_new((unsigned long long)#{param}));" if not param.type.signed?
476
+ if param.type.signed?
477
+ get_output.puts " rb_hash_aset(_boast_refs, ID2SYM(rb_intern(\"#{param}\")),rb_int_new((long long)#{str_par}));"
478
+ else
479
+ get_output.puts " rb_hash_aset(_boast_refs, ID2SYM(rb_intern(\"#{param}\")),rb_int_new((unsigned long long)#{str_par}));"
480
+ end
356
481
  when Real
357
- get_output.puts " rb_hash_aset(_boast_refs, ID2SYM(rb_intern(\"#{param}\")),rb_float_new((double)#{param}));"
482
+ get_output.puts " rb_hash_aset(_boast_refs, ID2SYM(rb_intern(\"#{param}\")),rb_float_new((double)#{str_par}));"
358
483
  end
359
484
  end
360
485
  end
361
486
 
362
- def copy_scalar_param_to_file(param, base_path)
487
+ def copy_scalar_param_to_file(str_par, param, base_path)
363
488
  if param.scalar_output? then
364
489
  get_output.puts <<EOF
365
490
  __boast_f = fopen("#{base_path}/#{param}.out", "wb");
366
- fwrite(&#{param}, sizeof(#{param}), 1, __boast_f);
491
+ fwrite(&(#{str_par}), sizeof(#{str_par}), 1, __boast_f);
367
492
  fclose(__boast_f);
368
493
  EOF
369
494
  end
370
495
  end
371
496
 
372
- def copy_scalar_param_from_file(param, base_path)
497
+ def copy_scalar_param_from_file(str_par, param, base_path)
373
498
  get_output.puts <<EOF
374
499
  __boast_f = fopen("#{base_path}/#{param}.in", "rb");
375
- fread(&#{param}, sizeof(#{param}), 1, __boast_f);
500
+ if( fread(&(#{str_par}), sizeof(#{str_par}), 1, __boast_f) != 1 ) {
501
+ exit(-1);
502
+ }
376
503
  fclose(__boast_f);
377
504
  EOF
378
505
  end
379
506
 
380
- def copy_array_param_to_ruby(param, ruby_param)
507
+ def copy_array_param_to_ruby(str_par, param, ruby_param)
381
508
  end
382
509
 
383
- def copy_array_param_to_file(param, base_path)
510
+ def copy_array_param_to_file(str_par, param, base_path)
384
511
  if param.direction == :out or param.direction == :inout then
385
512
  get_output.puts <<EOF
386
513
  __boast_f = fopen("#{base_path}/#{param}.out", "wb");
387
- fwrite(#{param}, 1, __boast_sizeof_#{param}, __boast_f);
514
+ fwrite(#{str_par}, 1, __boast_sizeof_#{param}, __boast_f);
388
515
  fclose(__boast_f);
389
- free(#{param});
516
+ free(#{str_par});
390
517
  EOF
391
518
  else
392
519
  get_output.puts <<EOF
393
- free(#{param});
520
+ free(#{str_par});
394
521
  EOF
395
522
  end
396
523
  end
397
524
 
398
- def copy_array_param_from_file(param, base_path)
525
+ def copy_array_param_from_file(str_par, param, base_path)
399
526
  get_output.puts <<EOF
400
527
  __boast_f = fopen("#{base_path}/#{param}.in", "rb");
401
528
  fseek(__boast_f, 0L, SEEK_END);
402
529
  __boast_sizeof_#{param} = ftell(__boast_f);
403
530
  rewind(__boast_f);
404
- #{param} = malloc(__boast_sizeof_#{param});
405
- fread(#{param}, 1, __boast_sizeof_#{param}, __boast_f);
531
+ #{str_par} = malloc(__boast_sizeof_#{param});
532
+ if( fread(#{str_par}, 1, __boast_sizeof_#{param}, __boast_f) != __boast_sizeof_#{param} ) {
533
+ exit(-1);
534
+ }
406
535
  fclose(__boast_f);
407
536
  EOF
408
537
  end
@@ -413,10 +542,11 @@ EOF
413
542
  push_env(:decl_module => true) {
414
543
  @procedure.parameters.each_index do |i|
415
544
  param = @procedure.parameters[i]
416
- if not param.dimension then
417
- copy_scalar_param_to_ruby(param, argv[i])
545
+ par = param_struct.struct_reference(param_struct.type.members[param.name.to_s])
546
+ if param.dimension then
547
+ copy_array_param_to_ruby(par, param, argv[i])
418
548
  else
419
- copy_array_param_to_ruby(param, argv[i])
549
+ copy_scalar_param_to_ruby(par, param, argv[i])
420
550
  end
421
551
  end
422
552
  }
@@ -425,19 +555,20 @@ EOF
425
555
  def store_results
426
556
  if @procedure.properties[:return] then
427
557
  type_ret = @procedure.properties[:return].type
428
- get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"return\")),rb_int_new((long long)_boast_ret));" if type_ret.kind_of?(Int) and type_ret.signed
429
- get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"return\")),rb_int_new((unsigned long long)_boast_ret));" if type_ret.kind_of?(Int) and not type_ret.signed
430
- get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"return\")),rb_float_new((double)_boast_ret));" if type_ret.kind_of?(Real)
558
+ get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"return\")),rb_int_new((long long)_boast_params._boast_ret));" if type_ret.kind_of?(Int) and type_ret.signed
559
+ get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"return\")),rb_int_new((unsigned long long)_boast_params._boast_ret));" if type_ret.kind_of?(Int) and not type_ret.signed
560
+ get_output.puts " rb_hash_aset(_boast_stats,ID2SYM(rb_intern(\"return\")),rb_float_new((double)_boast_params._boast_ret));" if type_ret.kind_of?(Real)
431
561
  end
432
562
  end
433
563
 
434
564
  def get_executable_params_value( base_path )
435
565
  push_env(:decl_module => true) {
436
566
  @procedure.parameters.each do |param|
437
- if not param.dimension? then
438
- copy_scalar_param_from_file(param, base_path)
567
+ par = param_struct.struct_reference(param_struct.type.members[param.name.to_s])
568
+ if param.dimension? then
569
+ copy_array_param_from_file(par, param, base_path)
439
570
  else
440
- copy_array_param_from_file(param, base_path)
571
+ copy_scalar_param_from_file(par, param, base_path)
441
572
  end
442
573
  end
443
574
  }
@@ -446,16 +577,18 @@ EOF
446
577
  def get_executable_params_return_value( base_path )
447
578
  push_env(:decl_module => true) {
448
579
  @procedure.parameters.each do |param|
449
- if not param.dimension then
450
- copy_scalar_param_to_file(param, base_path)
580
+ par = param_struct.struct_reference(param_struct.type.members[param.name.to_s])
581
+ if param.dimension then
582
+ copy_array_param_to_file(par, param, base_path)
451
583
  else
452
- copy_array_param_to_file(param, base_path)
584
+ copy_scalar_param_to_file(par, param, base_path)
453
585
  end
454
586
  end
455
587
  }
456
588
  end
457
589
 
458
590
  def fill_executable_source
591
+ fill_param_struct
459
592
  get_output.puts "#include <inttypes.h>"
460
593
  get_output.puts "#include <stdlib.h>"
461
594
  get_output.puts "#include <stdio.h>"
@@ -464,28 +597,24 @@ EOF
464
597
  }
465
598
  @probes.map(&:header)
466
599
  @procedure.boast_header(@lang)
600
+ @probes.map(&:preamble)
467
601
 
602
+ param_struct.type.define
468
603
  get_output.print <<EOF
469
- void Init_#{base_name}( void );
470
- int _boast_repeat;
471
- void Init_#{base_name}( void ) {
604
+ void Init_#{base_name}( int _boast_repeat );
605
+ void Init_#{base_name}( int _boast_repeat ) {
472
606
  EOF
473
607
  increment_indent_level
474
608
  output.puts " FILE * __boast_f;"
609
+ param_struct.decl
475
610
  push_env(:decl_module => true) {
476
611
  @procedure.parameters.each { |param|
477
612
  if param.dimension? then
478
613
  output.puts " size_t __boast_sizeof_#{param};"
479
614
  end
480
- param_copy = param.copy
481
- param_copy.constant = nil
482
- param_copy.direction = nil
483
- param_copy.reference = nil
484
- param_copy.decl
485
615
  }
486
- get_output.puts " #{@procedure.properties[:return].type.decl} _boast_ret;" if @procedure.properties[:return]
487
616
  }
488
- @probes.reverse.map(&:decl)
617
+ @probes.reject{ |e| e ==TimerProbe }.reverse.map(&:decl)
489
618
  @probes.map(&:configure)
490
619
 
491
620
  get_executable_params_value( "#{@tmp_dir}/#{@procedure.name}/#{base_name}" )
@@ -495,7 +624,7 @@ EOF
495
624
  get_output.puts " int _boast_i;"
496
625
  get_output.puts " for(_boast_i = 0; _boast_i < _boast_repeat; ++_boast_i){"
497
626
  get_output.print " "
498
- get_output.print "_boast_ret = " if @procedure.properties[:return]
627
+ get_output.print "_boast_params._boast_ret = " if @procedure.properties[:return]
499
628
  get_output.print "#{method_name}( "
500
629
  get_output.print create_procedure_call_parameters.join(", ")
501
630
  get_output.puts " );"
@@ -506,9 +635,9 @@ EOF
506
635
  get_output.puts ' printf("---\n");'
507
636
  if @procedure.properties[:return] then
508
637
  type_ret = @procedure.properties[:return].type
509
- get_output.puts ' printf(":return: %lld\n", (long long)_boast_ret);' if type_ret.kind_of?(Int) and type_ret.signed
510
- get_output.puts ' printf(":return: %ulld\n", (unsigned long long)_boast_ret);' if type_ret.kind_of?(Int) and not type_ret.signed
511
- get_output.puts ' printf(":return: %lf\n", (double)_boast_ret);' if type_ret.kind_of?(Real)
638
+ get_output.puts ' printf(":return: %lld\n", (long long)_boast_params._boast_ret);' if type_ret.kind_of?(Int) and type_ret.signed
639
+ get_output.puts ' printf(":return: %ulld\n", (unsigned long long)_boast_params._boast_ret);' if type_ret.kind_of?(Int) and not type_ret.signed
640
+ get_output.puts ' printf(":return: %lf\n", (double)_boast_params._boast_ret);' if type_ret.kind_of?(Real)
512
641
 
513
642
  end
514
643
 
@@ -522,8 +651,7 @@ EOF
522
651
  get_output.print <<EOF
523
652
  }
524
653
  int main(int argc, char * argv[]) {
525
- _boast_repeat=atoi(argv[1]);
526
- Init_#{base_name}();
654
+ Init_#{base_name}(atoi(argv[1]));
527
655
  return 0;
528
656
  }
529
657
  EOF
@@ -544,33 +672,41 @@ EOF
544
672
  end
545
673
 
546
674
  def fill_module_file_source
675
+ fill_param_struct
547
676
  fill_module_header
548
677
  @probes.map(&:header)
549
678
  @procedure.boast_header(@lang)
550
679
 
551
680
  fill_module_preamble
681
+ @probes.map(&:preamble)
552
682
 
553
683
  set_transition("VALUE", "VALUE", :default, CustomType::new(:type_name => "VALUE"))
554
- get_output.puts "VALUE method_run(int _boast_argc, VALUE *_boast_argv, VALUE _boast_self) {"
684
+
685
+ param_struct.type.define
686
+
687
+ create_wrapper
688
+
689
+ get_output.puts "static VALUE method_run(int _boast_argc, VALUE *_boast_argv, VALUE _boast_self) {"
690
+
555
691
  increment_indent_level
556
692
 
693
+ fill_decl_module_params
694
+
557
695
  fill_check_args
558
696
 
559
697
  add_run_options
560
698
 
561
- fill_decl_module_params
562
-
563
- @probes.reverse.map(&:decl)
699
+ @probes.reject{ |e| e == TimerProbe }.reverse.map(&:decl)
564
700
 
565
701
  get_params_value
566
702
 
567
703
  @probes.map(&:configure)
568
704
 
569
- @probes.reverse.map(&:start)
705
+ @probes.reject{ |e| e == TimerProbe }.reverse.map(&:start)
570
706
 
571
707
  create_procedure_call
572
708
 
573
- @probes.map(&:stop)
709
+ @probes.reject{ |e| e == TimerProbe }.map(&:stop)
574
710
 
575
711
  get_results
576
712
 
@@ -720,7 +856,7 @@ EOF
720
856
  elsif get_lang != CUDA then
721
857
  @probes = [TimerProbe, PAPIProbe]
722
858
  @probes.push EnergyProbe if EnergyProbe
723
- @probes.push AffinityProbe unless OS.mac?
859
+ @probes.push AffinityProbe if AffinityProbe
724
860
  end
725
861
  @probes = [MPPAProbe] if @architecture == MPPA
726
862
  linker, ldshared, ldshared_flags, ldflags = setup_compilers(@probes, compiler_options)
@@ -748,6 +884,34 @@ EOF
748
884
 
749
885
  eval "self.extend(#{module_name})"
750
886
 
887
+ define_singleton_method(:run) { |*args, **options, &block|
888
+ raise "Wrong number of arguments for #{@procedure.name} (#{args.length} for #{@procedure.parameters.length})" if args.length != @procedure.parameters.length
889
+ config = BOAST::get_run_config
890
+ config.update(options)
891
+ res = nil
892
+ if get_lang != CUDA and config[:PAPI] then
893
+ require 'PAPI'
894
+ PAPI.init
895
+ if config[:coexecute] then
896
+ PAPI.thread_init
897
+ end
898
+ end
899
+ if AffinityProbe == HwlocProbe and config[:cpu_affinity] then
900
+ affinity = config[:cpu_affinity]
901
+ if affinity.kind_of?(Array) then
902
+ cpuset = Hwloc::Cpuset::new( affinity )
903
+ elsif affinity.kind_of?(Hwloc::Bitmap) then
904
+ cpuset = affinity
905
+ end
906
+ AffinityProbe.topology.set_cpubind(cpuset, Hwloc::CPUBIND_THREAD | Hwloc::CPUBIND_STRICT) {
907
+ res = __run(*args, config, &block)
908
+ }
909
+ else
910
+ res = __run(*args, config, &block)
911
+ end
912
+ res
913
+ }
914
+
751
915
  return self
752
916
  end
753
917