BOAST 2.0.2 → 2.1.0

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