pwrake 0.9.7 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8936d0357e38b7b50bee817594555714412fb763
4
- data.tar.gz: 1aca5697a842735520300b7c8c81355c08b31240
3
+ metadata.gz: d50d7fd5c00627f0eea3d59e26632c4e9e4c0f6d
4
+ data.tar.gz: 3d9d6638a9dde0ce9feebc1ba210d9ce1d94b310
5
5
  SHA512:
6
- metadata.gz: c4204a54c3920365eaaf4b430a0217b7e63cbe19a4878594dbd7c6381d21e8fceb0e8f3a4a31e238ec8b2dbc4b1d2ca95b914199e1e0c973565540db1c740654
7
- data.tar.gz: f2c433d66cb1ecd7eb5340394e1b93d13530238b055d481d5b28c16f48f61402d69c1350a02b5389eaab1af39670db4e108346e70e33afdcaf4236909224df73
6
+ metadata.gz: c7517d29d640a06db61bc8a656615d43706564c49596d594830cadbbe0134b79bfe71c542e182de003baff492b58008bcb90e60b97aab587de1460f21cd99ce6
7
+ data.tar.gz: 99f101b28c359ea3157caf688205da6734bb95569dd1eea6fed5cc6787e6b1f9a7bd01a35ab1e7dd694e2782c0969480f4abea1d18bc68d963bc85658d9432c6
@@ -64,6 +64,7 @@ module Pwrake
64
64
  standard_exception_handling do
65
65
  init("pwrake")
66
66
  @master = Master.new
67
+ @master.init
67
68
  load_rakefile
68
69
  begin
69
70
  top_level
@@ -0,0 +1,184 @@
1
+ module Pwrake
2
+
3
+ class MTimePriorityArray < Array
4
+
5
+ def order_by(item)
6
+ item.input_file_mtime
7
+ end
8
+
9
+ def push(t)
10
+ order_value = order_by(t)
11
+ if empty? || order_by(last) <= order_value
12
+ super(t)
13
+ elsif order_by(first) > order_value
14
+ unshift(t)
15
+ else
16
+ lower = 0
17
+ upper = size-1
18
+ while lower+1 < upper
19
+ mid = ((lower + upper) / 2).to_i
20
+ if order_by(self[mid]) <= order_value
21
+ lower = mid
22
+ else
23
+ upper = mid
24
+ end
25
+ end
26
+ insert(upper,t)
27
+ end
28
+ end
29
+
30
+ def index(t)
31
+ if size < 40
32
+ return super(t)
33
+ end
34
+ order_value = t.order_by
35
+ if order_by(last) < order_value || order_by(first) > order_value
36
+ nil
37
+ else
38
+ lower = 0
39
+ upper = size-1
40
+ while lower+1 < upper
41
+ mid = ((lower + upper) / 2).to_i
42
+ if order_by(self[mid]) < order_value
43
+ lower = mid
44
+ else
45
+ upper = mid
46
+ end
47
+ end
48
+ mid = upper
49
+ if order_by(self[mid]) == order_value
50
+ Log.debug "--- TQA#index=#{mid}, order_value=#{order_value}"
51
+ mid
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+
58
+ # rank-Even Last In First Out
59
+ class CacheAwareQueue
60
+ def initialize(n)
61
+ @q = []
62
+ @i = 0
63
+ @size = 0
64
+ @n = (n>0) ? n : 1
65
+ end
66
+
67
+ def push(t)
68
+ r = t.rank
69
+ a = @q[r]
70
+ if a.nil?
71
+ @q[r] = a = MTimePriorityArray.new
72
+ end
73
+ @size += 1
74
+ a.push(t)
75
+ end
76
+
77
+ def size
78
+ @size
79
+ end
80
+
81
+ def empty?
82
+ @size == 0
83
+ end
84
+
85
+ def shift
86
+ if empty?
87
+ return nil
88
+ elsif @size < @n*2
89
+ return shift_high_rank
90
+ else
91
+ return shift_weighted
92
+ end
93
+ end
94
+
95
+ def shift_high_rank
96
+ (@q.size-1).downto(0) do |i|
97
+ a = @q[i]
98
+ next if a.nil? || a.empty?
99
+ @size -= 1
100
+ return pop_last_max(a)
101
+ end
102
+ nil
103
+ end
104
+
105
+ def shift_weighted
106
+ weight, weight_avg = RANK_STAT.rank_weight
107
+ wsum = 0.0
108
+ q = []
109
+ @q.each_with_index do |a,i|
110
+ next if a.nil? || a.empty?
111
+ w = weight[i]
112
+ w = weight_avg if w.nil?
113
+ # w *= a.size
114
+ wsum += w
115
+ q << [a,wsum]
116
+ end
117
+ #
118
+ x = rand() * wsum
119
+ Log.debug "--- shift_weighted x=#{x} wsum=#{wsum} weight=#{weight.inspect}"
120
+ @size -= 1
121
+ q.each do |a,w|
122
+ if w > x
123
+ return a.pop
124
+ end
125
+ end
126
+ raise "ELIFO: wsum=#{wsum} x=#{x}"
127
+ end
128
+
129
+ def pop_last_max(a)
130
+ if a.size < 2
131
+ return a.pop
132
+ end
133
+ y_max = nil
134
+ i_max = nil
135
+ n = [@n, a.size].min
136
+ (-n..-1).each do |i|
137
+ y = a[i].input_file_size
138
+ if y_max.nil? || y > y_max
139
+ y_max = y
140
+ i_max = i
141
+ end
142
+ end
143
+ a.delete_at(i_max)
144
+ end
145
+
146
+ def first
147
+ return nil if empty?
148
+ @q.size.times do |i|
149
+ a = @q[i]
150
+ unless a.nil? || a.empty?
151
+ return a.first
152
+ end
153
+ end
154
+ end
155
+
156
+ def last
157
+ return nil if empty?
158
+ @q.size.times do |i|
159
+ a = @q[-i-1]
160
+ unless a.nil? || a.empty?
161
+ return a.last
162
+ end
163
+ end
164
+ end
165
+
166
+ def delete(t)
167
+ n = 0
168
+ @q.each do |a|
169
+ if a
170
+ a.delete(t)
171
+ n += a.size
172
+ end
173
+ end
174
+ @size = n
175
+ end
176
+
177
+ def clear
178
+ @q.clear
179
+ @i = 0
180
+ @size = 0
181
+ end
182
+ end
183
+
184
+ end
@@ -1,3 +1,5 @@
1
+ require 'pwrake/gfwhere_pool'
2
+
1
3
  module Pwrake
2
4
 
3
5
  module GfarmPath
@@ -207,43 +209,13 @@ module Pwrake
207
209
  class GfarmPostprocess
208
210
 
209
211
  def initialize
210
- @lock = Mutex.new
211
- @io = IO.popen('gfwhere-pipe','r+')
212
- @io.sync = true
213
- end
214
-
215
- def gfwhere(file)
216
- return [] if file==''
217
- @lock.synchronize do
218
- @io.puts(file)
219
- @io.flush
220
- s = @io.gets
221
- if s.nil?
222
- raise "gfwhere: unexpected end"
223
- end
224
- s.chomp!
225
- if s != file
226
- raise "gfwhere: file=#{file}, result=#{s}"
227
- end
228
- while s = @io.gets
229
- s.chomp!
230
- case s
231
- when ""
232
- next
233
- when /^gfarm:\/\//
234
- next
235
- when /^Error:/
236
- return []
237
- else
238
- return s.split(/\s+/)
239
- end
240
- end
241
- end
212
+ max = Pwrake.application.pwrake_options['MAX_GFWHERE_WORKER']
213
+ @gfwhere_pool = WorkerPool.new(GfwhereWorker,max)
242
214
  end
243
215
 
244
216
  def postprocess(t)
245
217
  if t.kind_of? Rake::FileTask
246
- t.location = gfwhere(t.name)
218
+ t.location = @gfwhere_pool.work(t.name)
247
219
  end
248
220
  end
249
221
 
@@ -0,0 +1,112 @@
1
+ module Pwrake
2
+
3
+ class WorkerPool
4
+
5
+ def initialize(wk_class, max)
6
+ @worker_class = wk_class
7
+ @max = max
8
+ @pool = []
9
+ @cond_pool = ConditionVariable.new
10
+ @mutex = Mutex.new
11
+ end
12
+
13
+ def find_worker
14
+ @mutex.synchronize do
15
+ while true
16
+ @pool.each do |w|
17
+ return w if w.acquire
18
+ end
19
+ if @pool.size < @max
20
+ Log.debug "--- #{@worker_class}:new_worker #{@pool.size+1}"
21
+ w = @worker_class.new(@cond_pool)
22
+ @pool << w
23
+ return w if w.acquire
24
+ end
25
+ # wait for end of work in @pool
26
+ print "wait\n"
27
+ @cond_pool.wait(@mutex)
28
+ end
29
+ end
30
+ end
31
+
32
+ def work(*args)
33
+ w = find_worker
34
+ w.run(*args)
35
+ end
36
+ end
37
+
38
+
39
+ class Worker
40
+
41
+ def initialize(cond_pool)
42
+ @cond_pool = cond_pool
43
+ @mutex = Mutex.new
44
+ @aquired = false
45
+ end
46
+
47
+ def acquire
48
+ return false if @mutex.locked?
49
+ if @aquired
50
+ return false
51
+ else
52
+ @aquired = true
53
+ return true
54
+ end
55
+ end
56
+
57
+ def run(*args)
58
+ @mutex.synchronize do
59
+ raise "no aquired" unless @aquired
60
+ r = work(*args)
61
+ @aquired = false
62
+ @cond_pool.signal
63
+ return r
64
+ end
65
+ end
66
+
67
+ def work(*args)
68
+ # inplement in subclass
69
+ return nil
70
+ end
71
+ end
72
+
73
+
74
+ class GfwhereWorker < Worker
75
+
76
+ def initialize(cond_pool)
77
+ super(cond_pool)
78
+ @io = IO.popen('gfwhere-pipe','r+')
79
+ @io.sync = true
80
+ end
81
+
82
+ def work(file)
83
+ return [] if file==''
84
+ t = Time.now
85
+ @io.puts(file)
86
+ @io.flush
87
+ s = @io.gets
88
+ if s.nil?
89
+ raise "gfwhere: unexpected end"
90
+ end
91
+ s.chomp!
92
+ if s != file
93
+ raise "gfwhere: file=#{file}, result=#{s}"
94
+ end
95
+ while s = @io.gets
96
+ s.chomp!
97
+ case s
98
+ when ""
99
+ next
100
+ when /^gfarm:\/\//
101
+ next
102
+ when /^Error:/
103
+ return []
104
+ else
105
+ Log.debug "gfwhere:path %.6f sec, file=%s" % [Time.now-t,file]
106
+ return s.split(/\s+/)
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ end
@@ -131,14 +131,16 @@ module Pwrake
131
131
  end # class Throughput
132
132
 
133
133
 
134
- def init_queue(hosts)
134
+ def init_queue(core_list)
135
+ @host_count = Hash.new{0}
136
+ core_list.each{|h| @host_count[h] += 1}
137
+ @hosts = @host_count.keys
135
138
  @cv = LocalityConditionVariable.new
136
- @hosts = hosts
137
139
  @throughput = Throughput.new
138
140
  @size = 0
139
141
  @q = {}
140
- @hosts.each{|h| @q[h]=@array_class.new}
141
- @q_remote = @array_class.new
142
+ @host_count.each{|h,n| @q[h] = @array_class.new(n)}
143
+ @q_remote = @array_class.new(0)
142
144
  @q_later = Array.new
143
145
  @enable_steal = !Pwrake.application.pwrake_options['DISABLE_STEAL']
144
146
  @steal_wait = (Pwrake.application.pwrake_options['STEAL_WAIT'] || 0).to_i
@@ -213,10 +215,7 @@ module Pwrake
213
215
  if q && !q.empty?
214
216
  t = q.shift
215
217
  t.assigned.each do |h|
216
- a = @q[h]
217
- if i = a.index(t)
218
- a.delete_at(i)
219
- end
218
+ @q[h].delete(t)
220
219
  end
221
220
  @size -= 1
222
221
  return t
@@ -250,11 +249,14 @@ module Pwrake
250
249
  when 0
251
250
  s += "[]\n"
252
251
  when 1
253
- s += "[#{q[0].name}]\n"
252
+ s += "[#{q.first.name}]\n"
253
+ when 2
254
+ s += "[#{q.first.name}, #{q.last.name}]\n"
254
255
  else
255
- s += "[#{q[0].name},..]\n"
256
+ s += "[#{q.first.name},.. #{q.last.name}]\n"
256
257
  end
257
258
  }
259
+ b.call("noaction",@q_noaction)
258
260
  @q.each(&b)
259
261
  b.call("remote",@q_remote)
260
262
  b.call("later",@q_later)
@@ -266,17 +268,17 @@ module Pwrake
266
268
  end
267
269
 
268
270
  def clear
271
+ @q_noaction.clear
269
272
  @q.each{|h,q| q.clear}
270
273
  @q_remote.clear
271
274
  @q_later.clear
272
- @reserved_q.clear
273
275
  end
274
276
 
275
277
  def empty?
276
278
  @q.all?{|h,q| q.empty?} &&
279
+ @q_noaction.empty? &&
277
280
  @q_remote.empty? &&
278
- @q_later.empty? &&
279
- @reserved_q.empty?
281
+ @q_later.empty?
280
282
  end
281
283
 
282
284
  def finish
data/lib/pwrake/master.rb CHANGED
@@ -22,19 +22,22 @@ module Pwrake
22
22
  attr_reader :postprocess
23
23
 
24
24
  def initialize
25
- init_option # Pwrake::Option
26
- setup_option # Pwrake::Option
27
25
  @started = false
28
26
  @lock = Mutex.new
29
27
  @current_task_id = -1
30
28
  end
31
29
 
30
+ def init
31
+ init_option # Pwrake::Option
32
+ setup_option # Pwrake::Option
33
+ end
34
+
32
35
  def start
33
36
  return if @task_queue
34
37
  timer = Timer.new("start_worker")
35
38
  @finish_queue = Queue.new
36
39
  @task_queue = @queue_class.new(@core_list)
37
- @shell_set = []
40
+ @shell_set = (1..@num_noaction_threads).map{ NoActionShell.new }
38
41
  @core_list.each_with_index do |h,i|
39
42
  @shell_set << @shell_class.new(h,@shell_opt)
40
43
  end
@@ -53,6 +56,7 @@ module Pwrake
53
56
  def start_threads
54
57
  Thread.abort_on_exception = true
55
58
  @threads = []
59
+ @exit_task = {}
56
60
  t_intvl = Pwrake.application.pwrake_options['THREAD_CREATE_INTERVAL']
57
61
  @shell_set.each do |c|
58
62
  tc0 = Time.now
@@ -75,7 +79,9 @@ module Pwrake
75
79
  end
76
80
 
77
81
  def thread_loop(conn,last=nil)
78
- @task_queue.reserve(last) if last
82
+ if last
83
+ @exit_task[last] = Thread.current
84
+ end
79
85
  hint = (conn) ? conn.host : nil
80
86
  standard_exception_handling do
81
87
  while true
@@ -85,7 +91,9 @@ module Pwrake
85
91
  time_deq = Time.now - time_start
86
92
  Log.debug "--- Master#thread_loop deq t=#{t.inspect} time=#{time_deq}sec"
87
93
  t.pw_invoke
88
- return if t == last
94
+ if th = @exit_task.delete(t)
95
+ @task_queue.thread_end(th)
96
+ end
89
97
  end
90
98
  end
91
99
  end
data/lib/pwrake/option.rb CHANGED
@@ -12,9 +12,9 @@ module Pwrake
12
12
 
13
13
  def parse_opt(s)
14
14
  case s
15
- when /false|nil|off/i
15
+ when /^(false|nil|off)$/i
16
16
  false
17
- when /true|on/i
17
+ when /^(true|on)$/i
18
18
  true
19
19
  else
20
20
  s
@@ -41,10 +41,11 @@ module Pwrake
41
41
  'DEBUG',
42
42
  'PLOT_PARALLELISM',
43
43
  'HALT_QUEUE_WHILE_SEARCH',
44
- 'THREAD_CREATE_INTERVAL',
45
44
  'SHOW_CONF',
46
45
  'FAILED_TARGET', # rename(default), delete, leave
47
- 'QUEUE_PRIORITY', # DFS(default), FIFO,
46
+ 'QUEUE_PRIORITY', # RANK(default), FIFO, LIFO, DFS
47
+ 'NOACTION_QUEUE_PRIORITY', # FIFO(default), LIFO, RAND
48
+ 'NUM_NOACTION_THREADS', # default=4 when gfarm, else 1
48
49
  'STEAL_WAIT',
49
50
  'STEAL_WAIT_MAX',
50
51
 
@@ -88,16 +89,18 @@ module Pwrake
88
89
  end
89
90
  }],
90
91
  ['NUM_THREADS', proc{|v| v && v.to_i}],
92
+ ['THREAD_CREATE_INTERVAL', proc{|v| (v || 0.010).to_f}],
91
93
  ['DISABLE_AFFINITY', proc{|v| v || ENV['AFFINITY']=='off'}],
92
94
  ['DISABLE_STEAL', proc{|v| v || ENV['STEAL']=='off'}],
93
95
  ['GFARM_BASEDIR', proc{|v| v || '/tmp'}],
94
96
  ['GFARM_PREFIX', proc{|v| v || "pwrake_#{ENV['USER']}"}],
95
97
  ['GFARM_SUBDIR', proc{|v| v || '/'}],
96
- #['MASTER_HOSTNAME', proc{|v| v || `hostname -f`.chomp}],
98
+ ['MAX_GFWHERE_WORKER', proc{|v| (v || 8).to_i}],
99
+ ['MASTER_HOSTNAME', proc{|v| (v || begin;`hostname -f`;rescue;end || '').chomp}],
97
100
  ['WORK_DIR',proc{|v|
98
101
  v ||= '$HOME/%CWD_RELATIVE_TO_HOME'
99
102
  v.sub('%CWD_RELATIVE_TO_HOME',cwd_relative_to_home)
100
- }]
103
+ }],
101
104
  ]
102
105
  end
103
106
 
@@ -155,9 +158,7 @@ module Pwrake
155
158
  @yaml = open(@pwrake_conf){|f| YAML.load(f) }
156
159
  end
157
160
 
158
- @opts = {'PWRAKE_CONF' => @pwrake_conf,
159
- 'THREAD_CREATE_INTERVAL' => 0.006,
160
- }
161
+ @opts = { 'PWRAKE_CONF' => @pwrake_conf, }
161
162
 
162
163
  option_data.each do |a|
163
164
  prc = nil
@@ -376,6 +377,8 @@ module Pwrake
376
377
  end
377
378
  end
378
379
 
380
+ n_noaction_th = @opts['NUM_NOACTION_THREADS']
381
+
379
382
  case @filesystem
380
383
  when 'gfarm'
381
384
  require "pwrake/locality_aware_queue"
@@ -394,12 +397,14 @@ module Pwrake
394
397
  else
395
398
  @queue_class = LocalityAwareQueue
396
399
  end
400
+ @num_noaction_threads = (n_noaction_th || [8,@num_threads].max).to_i
397
401
  @postprocess = GfarmPostprocess.new
398
402
  Log.debug "--- @queue_class=#{@queue_class}"
399
403
  else
400
404
  @filesystem = 'nfs'
401
405
  @shell_class = Shell
402
406
  @queue_class = TaskQueue
407
+ @num_noaction_threads = (n_noaction_th || 1).to_i
403
408
  end
404
409
  end
405
410