pwrake 0.9.9 → 0.9.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cdc080259b5fb3f1b2c487375c56d2c319c4ad4b
4
- data.tar.gz: 8f28b6ff5df2e0160abf7c259808d85632c5db27
3
+ metadata.gz: b5f302ea2a00a59015b371e07ddf10f646f06eaa
4
+ data.tar.gz: 57d72fefb63e1a2b8270adf3b479aaba0add62f4
5
5
  SHA512:
6
- metadata.gz: ba5588c3bf612d56321bba8e36d331f2a4404b2815d3765b6b0baf7a483462498e852f31780147c38631c3c11b46ba9583849faeaec00d3792bbff29f9e332fb
7
- data.tar.gz: b6dd586b0982cfedd38ea166c9f7621fce13f90af61ad2f0ae334c659b9bd70be014d63c7ed9719c259ae5ca613940ab338fd627c11218fb5f2be3ba5510d08e
6
+ metadata.gz: 4990bd96c5a5bc7e268d26efbe07e0cb297b6a629f63f350b3d595e8b27c0831569fdece5a4070991ca7c7017b9914e934c5ed6a0ca444cc5ca3ef937721d040
7
+ data.tar.gz: 5b89d6aad26a1f802b1e4626aba67815f9914d3549dbb154864eb927558a58e8a16afcdf06025ffafe3724ae99666b8e4ef4db2bf62a3de57cf7f0678d50d7bb
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Parallel workflow extension for Rake
4
4
  * Author: Masahiro Tanaka
5
5
 
6
- ([日本語README](https://github.com/masa16/pwrake/wiki/Pwrake.ja)),
6
+ ([README in Japanese](https://github.com/masa16/pwrake/wiki/Pwrake.ja)),
7
7
  ([GitHub Repository](https://github.com/masa16/pwrake))
8
8
 
9
9
  ## Features
@@ -99,7 +99,12 @@ Or, gem install:
99
99
  GNU_TIME If true, obtains PROFILEs using GNU time
100
100
  PLOT_PARALLELISM If true, plot parallelism using GNUPLOT
101
101
  FAILED_TARGET ( rename(default) | delete | leave ) failed files
102
- QUEUE_PRIORITY ( DFS(default) | FIFO )
102
+ QUEUE_PRIORITY RANK(default), FIFO, LIFO, LIHR
103
+ NOACTION_QUEUE_PRIORITY FIFO(default), LIFO, RAND
104
+ NUM_NOACTION_THREADS default=4 when gfarm, else 1
105
+ THREAD_CREATE_INTERVAL default=0.01 (sec)
106
+ HALT_QUEUE_WHILE_SEARCH true|false
107
+ GRAPH_PARTITION true|false
103
108
 
104
109
  for Gfarm system:
105
110
 
@@ -111,22 +116,29 @@ Or, gem install:
111
116
  GFARM_BASEDIR default="/tmp"
112
117
  GFARM_PREFIX default="pwrake_$USER"
113
118
  GFARM_SUBDIR default='/'
119
+ MAX_GFWHERE_WORKER default=8
114
120
 
115
121
  ## Note for Gfarm
116
122
 
117
- * `gfwhere-pipe` command is required for file-affinity scheduling.
123
+ * `gfwhere-pipe` script (included in Pwrake) is used for file-affinity scheduling.
124
+ This script requires Ruby/FFI (https://github.com/ffi/ffi). Install FFI by
118
125
 
119
- wget https://gist.github.com/masa16/5787473/raw/6df5deeb80a4cea6b9d1d1ce01f390f65d650717/gfwhere-pipe.patch
120
- cd gfarm-2.5.8.1
121
- patch -p1 < ../gfwhere-pipe.patch
122
- ./configure --prefix=...
123
- make
124
- make install
126
+ gem install ffi
127
+
128
+ ## For Graph Partitioning
129
+
130
+ * Compile and Install METIS 5.1.0 (http://www.cs.umn.edu/~metis/). This requires CMake.
131
+
132
+ * Install RbMetis (https://github.com/masa16/rbmetis) by
133
+
134
+ gem install rbmetis -- \
135
+ --with-metis-include=/usr/local/include \
136
+ --with-metis-lib=/usr/local/lib
125
137
 
126
138
  ## Tested Platform
127
139
 
128
- * Ruby 2.0.0
129
- * Rake 0.9.6
140
+ * Ruby 2.1.4
141
+ * Rake 10.1.0
130
142
  * CentOS 6.4
131
143
 
132
144
  ## Acknowledgment
@@ -0,0 +1,159 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'ffi'
4
+ require 'singleton'
5
+
6
+ module Gfarm
7
+ class GfarmError < StandardError
8
+ end
9
+ GFARM_ERR_NO_ERROR = 0
10
+
11
+ module FFI
12
+ def find_executable(name)
13
+ path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin"
14
+ begin
15
+ $stderr = open(File::NULL,"w")
16
+ path = ENV['PATH']
17
+ ensure
18
+ $stderr = STDERR
19
+ end
20
+ path = path.split(File::PATH_SEPARATOR)
21
+ path.each do |dir|
22
+ file = File.join(dir, name)
23
+ begin
24
+ stat = File.stat(file)
25
+ rescue SystemCallError
26
+ else
27
+ return file if stat.file? and stat.executable?
28
+ end
29
+ end
30
+ nil
31
+ end
32
+ module_function :find_executable
33
+
34
+ LIBGFARM_PATH = nil
35
+ LIBGFARM_FILE = "libgfarm.so"
36
+ if LIBGFARM_PATH
37
+ path = File.join(LIBGFARM_PATH,LIBGFARM_FILE)
38
+ elsif x = find_executable('gfwhere')
39
+ d = File.dirname(x)
40
+ %w[lib64 lib].each do |l|
41
+ f = File.join(d,"..",l,LIBGFARM_FILE)
42
+ if File.file?(f)
43
+ path = f
44
+ break
45
+ end
46
+ end
47
+ end
48
+ extend ::FFI::Library
49
+ ffi_lib path
50
+ attach_function :gfarm_initialize, [:pointer, :pointer], :int
51
+ attach_function :gfarm_terminate, [], :int
52
+ attach_function :gfarm_realpath_by_gfarm2fs, [:string, :pointer], :int
53
+ attach_function :gfarm_error_string, [:int], :string
54
+ attach_function :gfs_replica_info_by_name, [:string, :int, :pointer], :int
55
+ attach_function :gfs_replica_info_number, [:pointer], :int
56
+ attach_function :gfs_replica_info_free, [:pointer], :void
57
+ attach_function :gfs_replica_info_nth_host, [:pointer, :int], :string
58
+ end
59
+
60
+
61
+ def connection(*args)
62
+ Connection.set_args(args)
63
+ Connection.instance
64
+ end
65
+ module_function :connection
66
+
67
+
68
+ class Connection
69
+ include Singleton
70
+
71
+ def self.callback
72
+ proc{ FFI.gfarm_terminate }
73
+ end
74
+
75
+ def self.set_args(args)
76
+ @@args = args
77
+ end
78
+
79
+ def initialize
80
+ args = @@args || []
81
+ argc = ::FFI::MemoryPointer.new(:int, 1)
82
+ argc.write_int(args.size)
83
+ ary = args.map do |s|
84
+ str = ::FFI::MemoryPointer.new(:string, s.size)
85
+ str.write_string(s)
86
+ str
87
+ end
88
+ ptr = ::FFI::MemoryPointer.new(:pointer, args.size)
89
+ ptr.write_array_of_pointer(ary)
90
+ argv = ::FFI::MemoryPointer.new(:pointer, 1)
91
+ argv.write_pointer(ptr)
92
+ e = FFI.gfarm_initialize(argc, argv)
93
+ if e != GFARM_ERR_NO_ERROR
94
+ raise GfarmError, FFI.gfarm_error_string(e)
95
+ end
96
+ ObjectSpace.define_finalizer(self, self.class.callback)
97
+ end
98
+
99
+ def realpath_by_gfarm2fs(path)
100
+ ptr = ::FFI::MemoryPointer.new(:pointer, 1)
101
+ e = FFI.gfarm_realpath_by_gfarm2fs(path, ptr)
102
+ if e != GFARM_ERR_NO_ERROR
103
+ raise GfarmError, FFI.gfarm_error_string(e)
104
+ end
105
+ ptr.read_pointer().read_string()
106
+ end
107
+
108
+ def replica_info_by_name(name)
109
+ ReplicaInfo.new(self,name)
110
+ end
111
+ end
112
+
113
+
114
+ class ReplicaInfo < ::FFI::AutoPointer
115
+
116
+ def self.release(ptr)
117
+ FFI.gfs_replica_info_free(ptr)
118
+ end
119
+
120
+ def initialize(gfarm, path)
121
+ @gfarm = gfarm
122
+ @realpath = @gfarm.realpath_by_gfarm2fs(path)
123
+ flag = 0
124
+ ptr = ::FFI::MemoryPointer.new(:pointer, 1)
125
+ e = FFI.gfs_replica_info_by_name(@realpath, flag, ptr)
126
+ if e != GFARM_ERR_NO_ERROR
127
+ raise GfarmError, @realpath+" "+FFI.gfarm_error_string(e)
128
+ end
129
+ @ri = ptr.read_pointer()
130
+ super @ri
131
+ end
132
+ attr_reader :realpath
133
+
134
+ def number
135
+ FFI.gfs_replica_info_number(@ri)
136
+ end
137
+
138
+ def nth_host(i)
139
+ FFI.gfs_replica_info_nth_host(@ri,i)
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ gfarm = Gfarm.connection
146
+
147
+ while path=$stdin.gets
148
+ path.chomp!
149
+ $stdout.print path+"\n"
150
+ $stdout.flush
151
+ begin
152
+ ri = gfarm.replica_info_by_name(path)
153
+ hosts = ri.number.times.map{|i| ri.nth_host(i) }
154
+ $stdout.print ri.realpath+":\n"+hosts.join(" ")+"\n"
155
+ rescue
156
+ $stdout.print "Error: "+path+"\n"
157
+ end
158
+ $stdout.flush
159
+ end
@@ -11,6 +11,7 @@ require "pwrake/profiler"
11
11
  require "pwrake/shell"
12
12
  require "pwrake/task_algorithm"
13
13
  require "pwrake/task_queue"
14
+ require "pwrake/host_list"
14
15
  require "pwrake/option"
15
16
  require "pwrake/master"
16
17
  require "pwrake/application"
@@ -47,8 +47,8 @@ module Pwrake
47
47
  @master.start
48
48
  end
49
49
 
50
- def core_list
51
- @master.core_list
50
+ def host_list
51
+ @master.host_list
52
52
  end
53
53
 
54
54
  def task_logger
@@ -67,7 +67,11 @@ module Pwrake
67
67
  @master.init
68
68
  load_rakefile
69
69
  begin
70
- top_level
70
+ begin
71
+ top_level
72
+ rescue
73
+ puts $!.message
74
+ end
71
75
  ensure
72
76
  @master.finish
73
77
  end
@@ -189,6 +193,12 @@ module Pwrake
189
193
  @master.counter.count( host_list, host )
190
194
  end
191
195
 
196
+ =begin
197
+ def host_weigts
198
+ @master.counter.host_weights
199
+ end
200
+ =end
201
+
192
202
  # from Michael Grosser's parallel
193
203
  # https://github.com/grosser/parallel
194
204
  def processor_count
@@ -214,7 +214,7 @@ module Pwrake
214
214
  end
215
215
 
216
216
  def postprocess(t)
217
- if t.kind_of? Rake::FileTask
217
+ if t.kind_of?(Rake::FileTask) && t.location.empty?
218
218
  t.location = @gfwhere_pool.work(t.name)
219
219
  end
220
220
  end
@@ -23,7 +23,6 @@ module Pwrake
23
23
  return w if w.acquire
24
24
  end
25
25
  # wait for end of work in @pool
26
- print "wait\n"
27
26
  @cond_pool.wait(@mutex)
28
27
  end
29
28
  end
@@ -95,8 +94,6 @@ module Pwrake
95
94
  while s = @io.gets
96
95
  s.chomp!
97
96
  case s
98
- when ""
99
- next
100
97
  when /^gfarm:\/\//
101
98
  next
102
99
  when /^Error:/
@@ -0,0 +1,88 @@
1
+ module Pwrake
2
+
3
+ class HostInfo
4
+ def initalize(name,group=0,weight=1)
5
+ @name = name
6
+ @group = group
7
+ @weight = weight
8
+ end
9
+ attr_reader :name, :group, :weight
10
+ end
11
+
12
+ class HostList
13
+ attr_reader :group_hosts
14
+ attr_reader :group_core_weight
15
+ attr_reader :group_weight_sum
16
+ attr_reader :host2group
17
+ attr_reader :num_threads
18
+ attr_reader :core_list
19
+ attr_reader :host_count
20
+
21
+ def initialize(file=nil)
22
+ @file = file
23
+ @group_hosts = []
24
+ @group_core_weight = []
25
+ @group_weight_sum = []
26
+ @host2group = {}
27
+ require "socket"
28
+ if @file
29
+ read_host(@file)
30
+ @num_threads = @core_list.size
31
+ else
32
+ @num_threads = 1 if !@num_threads
33
+ @core_list = ['localhost'] * @num_threads
34
+ end
35
+ end
36
+
37
+ def size
38
+ @num_threads
39
+ end
40
+
41
+ def read_host(file)
42
+ tmplist = []
43
+ File.open(file) do |f|
44
+ re = /\[\[([\w\d]+)-([\w\d]+)\]\]/o
45
+ while l = f.gets
46
+ l = $1 if /^([^#]*)#/ =~ l
47
+ host, ncore, weight, group = l.split
48
+ if host
49
+ if re =~ host
50
+ hosts = ($1..$2).map{|i| host.sub(re,i)}
51
+ else
52
+ hosts = [host]
53
+ end
54
+ hosts.each do |host|
55
+ begin
56
+ host = Socket.gethostbyname(host)[0]
57
+ rescue
58
+ Log.info "-- FQDN not resoved : #{host}"
59
+ end
60
+ ncore = (ncore || 1).to_i
61
+ weight = (weight || 1).to_f
62
+ w = ncore * weight
63
+ group = (group || 0).to_i
64
+ tmplist << ([host] * ncore.to_i)
65
+ (@group_hosts[group] ||= []) << host
66
+ (@group_core_weight[group] ||= []) << w
67
+ @group_weight_sum[group] = (@group_weight_sum[group]||0) + w
68
+ @host2group[host] = group
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ @core_list = []
75
+ begin # alternative order
76
+ sz = 0
77
+ tmplist.each do |a|
78
+ @core_list << a.shift if !a.empty?
79
+ sz += a.size
80
+ end
81
+ end while sz>0
82
+
83
+ @host_count = Hash.new{0}
84
+ core_list.each{|h| @host_count[h] += 1}
85
+ end
86
+
87
+ end
88
+ end
@@ -108,6 +108,36 @@ module Pwrake
108
108
  self
109
109
  end
110
110
 
111
+
112
+ def signal_with_hints(hints)
113
+ if !Array===hints
114
+ raise ArgumentError,"argument must be an Array"
115
+ end
116
+ thread =
117
+ @waiters_mutex.synchronize do
118
+ th = nil
119
+ @waiters.each do |t,v|
120
+ Log.debug "--- LCV#signal_with_hints: t[:hint]=#{t[:hint]}"
121
+ if hints.include?(t[:hint])
122
+ th = t
123
+ break
124
+ end
125
+ end
126
+ Log.debug "--- LCV#signal_with_hints: hints=#{hints.inspect} thread_to_run=#{th.inspect} @waiters.size=#{@waiters.size}"
127
+ if th
128
+ @waiters.delete(th)
129
+ end
130
+ th
131
+ end
132
+ begin
133
+ thread.run if thread
134
+ rescue ThreadError
135
+ retry # t was already dead?
136
+ end
137
+ thread
138
+ end
139
+
140
+
111
141
  def broadcast(hints=nil)
112
142
  if hints.nil?
113
143
  super()
@@ -201,15 +231,22 @@ module Pwrake
201
231
  end # class Throughput
202
232
 
203
233
 
204
- def init_queue(core_list)
205
- @host_count = Hash.new{0}
206
- core_list.each{|h| @host_count[h] += 1}
207
- @hosts = @host_count.keys
234
+ def init_queue(host_list)
235
+ @host_list = host_list
208
236
  @cv = LocalityConditionVariable.new
209
- @throughput = Throughput.new
210
237
  @size = 0
211
238
  @q = {}
212
- @host_count.each{|h,n| @q[h] = @array_class.new(n)}
239
+ @host_list.host_count.each{|h,n| @q[h] = @array_class.new(n)}
240
+ @q_group = {}
241
+ @host_list.group_hosts.each do |g|
242
+ other = @host_list.host_count.dup
243
+ q1 = {}
244
+ g.each{|h| q1[h] = @q[h]; other.delete(h)}
245
+ q2 = {}
246
+ other.each{|h,v| q2[h] = @q[h]}
247
+ a = [q1,q2]
248
+ g.each{|h| @q_group[h] = a}
249
+ end
213
250
  @q_remote = @array_class.new(0)
214
251
  @q_later = Array.new
215
252
  @enable_steal = !Pwrake.application.pwrake_options['DISABLE_STEAL']
@@ -224,7 +261,7 @@ module Pwrake
224
261
 
225
262
 
226
263
  def enq_impl(t)
227
- hints = t.suggest_location
264
+ hints = t && t.suggest_location
228
265
  if hints.nil? || hints.empty?
229
266
  @q_later.push(t)
230
267
  else
@@ -247,35 +284,44 @@ module Pwrake
247
284
 
248
285
  def deq_impl(host,n)
249
286
  if t = deq_locate(host)
250
- Log.info "-- deq_locate n=#{n} task=#{t.name} host=#{host}"
287
+ Log.info "-- deq_locate n=#{n} task=#{t&&t.name} host=#{host}"
251
288
  Log.debug "--- deq_impl\n#{inspect_q}"
252
289
  return t
253
290
  end
254
291
 
292
+ #hints = []
293
+ #@q.each do |h,q|
294
+ # hints << h if !q.empty?
295
+ #end
296
+ #if (!hints.empty?) && @cv.signal_with_hints(hints)
297
+ # return nil
298
+ #end
299
+
255
300
  if !@q_remote.empty?
256
301
  t = @q_remote.shift
257
- Log.info "-- deq_remote n=#{n} task=#{t.name} host=#{host}"
302
+ Log.info "-- deq_remote n=#{n} task=#{t&&t.name} host=#{host}"
258
303
  Log.debug "--- deq_impl\n#{inspect_q}"
259
304
  return t
260
305
  end
261
306
 
262
307
  if !@q_later.empty?
263
308
  t = @q_later.shift
264
- Log.info "-- deq_later n=#{n} task=#{t.name} host=#{host}"
309
+ Log.info "-- deq_later n=#{n} task=#{t&&t.name} host=#{host}"
265
310
  Log.debug "--- deq_impl\n#{inspect_q}"
266
311
  return t
267
312
  end
268
313
 
269
314
  if @enable_steal && n > 0 && Time.now-@last_enq_time > @steal_wait_after_enq
270
315
  if t = deq_steal(host)
271
- Log.info "-- deq_steal n=#{n} task=#{t.name} host=#{host}"
316
+ Log.info "-- deq_steal n=#{n} task=#{t&&t.name} host=#{host}"
272
317
  Log.debug "--- deq_impl\n#{inspect_q}"
273
318
  return t
274
319
  end
275
320
  end
276
321
 
277
- m = [@steal_wait*(2**n), @steal_wait_max].min
278
- @cv.wait(@mutex,m)
322
+ #m = [@steal_wait*(2**n), @steal_wait_max].min
323
+ #@cv.wait(@mutex,m)
324
+ @cv.wait(@mutex)
279
325
  nil
280
326
  end
281
327
 
@@ -284,8 +330,10 @@ module Pwrake
284
330
  q = @q[host]
285
331
  if q && !q.empty?
286
332
  t = q.shift
287
- t.assigned.each do |h|
288
- @q[h].delete(t)
333
+ if t
334
+ t.assigned.each do |h|
335
+ @q[h].delete(t)
336
+ end
289
337
  end
290
338
  @size -= 1
291
339
  return t
@@ -298,17 +346,23 @@ module Pwrake
298
346
  # select a task based on many and close
299
347
  max_host = nil
300
348
  max_num = 0
301
- @q.each do |h,a|
302
- if !a.empty?
303
- d = a.size
304
- if d > max_num
305
- max_host = h
306
- max_num = d
349
+ @q_group[host].each do |qg|
350
+ qg.each do |h,a|
351
+ if !a.empty?
352
+ d = a.size
353
+ if d > max_num
354
+ max_host = h
355
+ max_num = d
356
+ end
307
357
  end
308
358
  end
359
+ if max_num > 0
360
+ Log.info "-- deq_steal max_host=#{max_host} max_num=#{max_num}"
361
+ t = deq_locate(max_host)
362
+ return t if t
363
+ end
309
364
  end
310
- Log.info "-- deq_steal max_host=#{max_host} max_num=#{max_num}"
311
- deq_locate(max_host)
365
+ nil
312
366
  end
313
367
 
314
368
  def inspect_q