pwrake 0.9.7 → 0.9.8

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: 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