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.
@@ -1,3 +1,5 @@
1
+ require "pwrake/cache_aware_queue.rb"
2
+
1
3
  module Pwrake
2
4
 
3
5
  class TaskConditionVariable < ConditionVariable
@@ -6,7 +8,12 @@ module Pwrake
6
8
  end
7
9
  end
8
10
 
11
+
9
12
  class PriorityQueueArray < Array
13
+ def initialize(n)
14
+ super()
15
+ end
16
+
10
17
  def push(t)
11
18
  task_id = t.task_id
12
19
  if empty? || last.task_id <= task_id
@@ -55,80 +62,324 @@ module Pwrake
55
62
  end
56
63
  end # PriorityQueueArray
57
64
 
65
+
58
66
  class LifoQueueArray < Array
67
+ def initialize(n)
68
+ super()
69
+ end
70
+
59
71
  def shift
60
72
  pop
61
73
  end
62
74
  end
63
75
 
76
+
77
+ class FifoQueueArray < Array
78
+ def initialize(n)
79
+ super()
80
+ end
81
+ end
82
+
83
+
84
+ # Rank-Even Last In First Out
85
+ class RankQueueArray
86
+ def initialize(n)
87
+ @q = []
88
+ @size = 0
89
+ @n = (n>0) ? n : 1
90
+ end
91
+
92
+ def push(t)
93
+ r = t.rank
94
+ a = @q[r]
95
+ if a.nil?
96
+ @q[r] = a = []
97
+ end
98
+ @size += 1
99
+ a.push(t)
100
+ end
101
+
102
+ def size
103
+ @size
104
+ end
105
+
106
+ def empty?
107
+ @size == 0
108
+ end
109
+
110
+ def shift
111
+ if empty?
112
+ return nil
113
+ end
114
+ (@q.size-1).downto(0) do |i|
115
+ a = @q[i]
116
+ next if a.nil? || a.empty?
117
+ @size -= 1
118
+ if a.size <= @n
119
+ return pop_last_max(a)
120
+ else
121
+ return shift_weighted
122
+ end
123
+ end
124
+ raise "ELIFO: @q=#{@q.inspect}"
125
+ end
126
+
127
+ def shift_weighted
128
+ weight, weight_avg = RANK_STAT.rank_weight
129
+ wsum = 0.0
130
+ q = []
131
+ @q.each_with_index do |a,i|
132
+ next if a.nil? || a.empty?
133
+ w = weight[i]
134
+ w = weight_avg if w.nil?
135
+ # w *= a.size
136
+ wsum += w
137
+ q << [a,wsum]
138
+ end
139
+ #
140
+ x = rand() * wsum
141
+ Log.debug "--- shift_weighted x=#{x} wsum=#{wsum} weight=#{weight.inspect}"
142
+ q.each do |a,w|
143
+ if w > x
144
+ return a.pop
145
+ end
146
+ end
147
+ raise "ELIFO: wsum=#{wsum} x=#{x}"
148
+ end
149
+
150
+ def pop_last_max(a)
151
+ if a.size < 2
152
+ return a.pop
153
+ end
154
+ y_max = nil
155
+ i_max = nil
156
+ n = [@n, a.size].min
157
+ (-n..-1).each do |i|
158
+ y = a[i].input_file_size
159
+ if y_max.nil? || y > y_max
160
+ y_max = y
161
+ i_max = i
162
+ end
163
+ end
164
+ a.delete_at(i_max)
165
+ end
166
+
167
+ def first
168
+ return nil if empty?
169
+ @q.size.times do |i|
170
+ a = @q[i]
171
+ unless a.nil? || a.empty?
172
+ return a.first
173
+ end
174
+ end
175
+ end
176
+
177
+ def last
178
+ return nil if empty?
179
+ @q.size.times do |i|
180
+ a = @q[-i-1]
181
+ unless a.nil? || a.empty?
182
+ return a.last
183
+ end
184
+ end
185
+ end
186
+
187
+ def delete(t)
188
+ n = 0
189
+ @q.each do |a|
190
+ if a
191
+ a.delete(t)
192
+ n += a.size
193
+ end
194
+ end
195
+ @size = n
196
+ end
197
+
198
+ def clear
199
+ @q.clear
200
+ @size = 0
201
+ end
202
+ end
203
+
204
+
205
+ class NoActionQueue
206
+ def initialize
207
+ @que = []
208
+ @num_waiting = 0
209
+ @mutex = Mutex.new
210
+ @cond = ConditionVariable.new
211
+ @halt = false
212
+ @th_end = {}
213
+ prio = Pwrake.application.pwrake_options['NOACTION_QUEUE_PRIORITY'] || 'fifo'
214
+ case prio
215
+ when /fifo/i
216
+ @prio = 0
217
+ Log.debug "--- NOACTION_QUEUE_PRIORITY=FIFO"
218
+ when /lifo/i
219
+ @prio = 1
220
+ Log.debug "--- NOACTION_QUEUE_PRIORITY=LIFO"
221
+ when /rand/i
222
+ @prio = 2
223
+ Log.debug "--- NOACTION_QUEUE_PRIORITY=RAND"
224
+ else
225
+ raise RuntimeError,"unknown option for NOACTION_QUEUE_PRIORITY: "+prio
226
+ end
227
+ end
228
+
229
+ def push(obj)
230
+ if @halt
231
+ @que.push obj
232
+ else
233
+ @mutex.synchronize do
234
+ @que.push obj
235
+ @cond.signal
236
+ end
237
+ end
238
+ end
239
+ alias << push
240
+ alias enq push
241
+
242
+ def pop
243
+ @mutex.synchronize do
244
+ t = Time.now
245
+ while true
246
+ if @th_end.delete(Thread.current)
247
+ return false
248
+ elsif @halt
249
+ @cond.wait @mutex
250
+ elsif @que.empty?
251
+ if @finished
252
+ @cond.signal
253
+ return false
254
+ end
255
+ @cond.wait @mutex
256
+ else
257
+ case @prio
258
+ when 0
259
+ x = @que.shift
260
+ when 1
261
+ x = @que.pop
262
+ when 2
263
+ x = @que.delete_at(rand(@que.size))
264
+ end
265
+ Log.debug "--- NATQ#deq %.6f sec #{x.inspect}"%[Time.now-t]
266
+ return x
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ alias shift pop
273
+ alias deq pop
274
+
275
+ def halt
276
+ @mutex.lock
277
+ @halt = true
278
+ end
279
+
280
+ def resume
281
+ @halt = false
282
+ @mutex.unlock
283
+ @cond.broadcast
284
+ end
285
+
286
+ def empty?
287
+ @que.empty?
288
+ end
289
+
290
+ def clear
291
+ @que.clear
292
+ end
293
+
294
+ def length
295
+ @que.length
296
+ end
297
+ alias size length
298
+
299
+ def first
300
+ @que.first
301
+ end
302
+
303
+ def last
304
+ @que.last
305
+ end
306
+
307
+ def finish
308
+ @finished = true
309
+ @cond.broadcast
310
+ end
311
+
312
+ def thread_end(th)
313
+ @th_end[th] = true
314
+ @cond.broadcast
315
+ end
316
+
317
+ def stop
318
+ clear
319
+ finish
320
+ end
321
+ end
322
+
323
+
64
324
  class TaskQueue
65
325
 
66
- def initialize(*args)
326
+ def initialize(core_list)
67
327
  @finished = false
68
328
  @halt = false
69
329
  @mutex = Mutex.new
70
- @th_end = []
330
+ @th_end = {}
71
331
  @enable_steal = true
72
- @reservation = {}
73
- @reserved_q = {}
74
- case Pwrake.application.pwrake_options['QUEUE_PRIORITY']||"DFS"
332
+ @q_noaction = NoActionQueue.new
333
+ pri = Pwrake.application.pwrake_options['QUEUE_PRIORITY'] || "RANK"
334
+ case pri
75
335
  when /dfs/i
76
336
  @array_class = PriorityQueueArray
77
337
  when /fifo/i
78
- @array_class = Array # Fifo
338
+ @array_class = FifoQueueArray # Array # Fifo
79
339
  when /lifo/i
80
340
  @array_class = LifoQueueArray
341
+ when /rank/i
342
+ @array_class = RankQueueArray
81
343
  else
82
- raise RuntimeError,"unknown option for QUEUE_PRIORITY"
344
+ raise RuntimeError,"unknown option for QUEUE_PRIORITY: "+pri
83
345
  end
84
346
  Log.debug "--- TQ#initialize @array_class=#{@array_class.inspect}"
85
- init_queue(*args)
347
+ init_queue(core_list)
86
348
  end
87
349
 
88
- def init_queue(*args)
350
+ def init_queue(core_list)
89
351
  @cv = TaskConditionVariable.new
90
- @q_prior = @array_class.new
352
+ @q_input = @array_class.new(core_list.size)
91
353
  @q_later = Array.new
92
354
  end
93
355
 
94
356
  attr_reader :mutex
95
357
  attr_accessor :enable_steal
96
358
 
97
- def reserve(item)
98
- @reservation[item] = Thread.current
99
- end
100
-
101
359
  def halt
102
- @mutex.synchronize do
103
- @halt = true
104
- end
360
+ @q_noaction.halt
361
+ @mutex.lock
362
+ @halt = true
105
363
  end
106
364
 
107
365
  def resume
108
- @mutex.synchronize do
109
- @halt = false
110
- @cv.broadcast
111
- end
366
+ @halt = false
367
+ @q_noaction.resume
368
+ @mutex.unlock
369
+ @cv.broadcast
112
370
  end
113
371
 
114
372
  def synchronize(condition)
115
373
  ret = nil
116
374
  if condition
117
- @mutex.lock
118
- @halt = true
119
- begin
375
+ halt
376
+ begin
120
377
  ret = yield
121
- @cv.broadcast
122
- ensure
123
- @halt = false
124
- @mutex.unlock
378
+ ensure
379
+ resume
125
380
  end
126
381
  else
127
- ret = yield
128
- end
129
- @reserved_q.keys.each do |th|
130
- Log.debug "--- run #{th}";
131
- th.run
382
+ ret = yield
132
383
  end
133
384
  ret
134
385
  end
@@ -137,46 +388,41 @@ module Pwrake
137
388
  def enq(item)
138
389
  Log.debug "--- TQ#enq #{item.name}"
139
390
  t0 = Time.now
140
- if @halt
141
- enq_body(item)
391
+ if item.actions.empty?
392
+ @q_noaction.enq(item)
393
+ elsif @halt
394
+ enq_body(item)
142
395
  else
143
396
  @mutex.synchronize do
144
- enq_body(item)
145
- @cv.signal(item.suggest_location)
397
+ enq_body(item)
398
+ @cv.signal(item.suggest_location)
146
399
  end
147
400
  end
148
- @reserved_q.keys.each{|th|
149
- Log.debug "--- run #{th}";
150
- th.run
151
- }
152
401
  Log.debug "--- TQ#enq #{item.name} enq_time=#{Time.now-t0}"
153
402
  end
154
403
 
155
404
  def enq_body(item)
156
- if th = @reservation[item]
157
- @reserved_q[th] = item
158
- else
159
- enq_impl(item)
160
- end
405
+ enq_impl(item)
161
406
  end
162
407
 
163
- def enq_impl(item)
164
- if item.prior?
165
- @q_prior.push(item)
408
+ def enq_impl(t)
409
+ if t.has_input_file?
410
+ @q_input.push(t)
166
411
  else
167
- @q_later.push(item)
412
+ @q_later.push(t)
168
413
  end
169
414
  end
170
415
 
171
-
172
416
  # deq
173
417
  def deq(hint=nil)
418
+ if hint == '(noaction)'
419
+ return @q_noaction.deq
420
+ end
174
421
  n = 0
175
422
  loop do
176
423
  @mutex.synchronize do
177
424
  t0 = Time.now
178
- if @th_end.first == Thread.current
179
- @th_end.shift
425
+ if @th_end.delete(Thread.current)
180
426
  return false
181
427
 
182
428
  elsif @halt
@@ -184,17 +430,11 @@ module Pwrake
184
430
  @cv.wait(@mutex)
185
431
  n = 0
186
432
 
187
- elsif item = @reserved_q.delete(Thread.current)
188
- Log.debug "--- deq from reserved_q=#{item.inspect}"
189
- return item
190
-
191
433
  elsif empty? # no item in queue
192
- #Log.debug "--- empty=true in #{self.class}#deq @finished=#{@finished.inspect}"
193
434
  if @finished
194
- @cv.signal
435
+ @cv.signal
195
436
  return false
196
437
  end
197
- #Log.debug "--- waiting in #{self.class}#deq @finished=#{@finished.inspect}"
198
438
  @cv.wait(@mutex)
199
439
  n = 0
200
440
 
@@ -204,36 +444,38 @@ module Pwrake
204
444
  Log.debug "--- TQ#deq #{t_inspect} deq_time=#{Time.now-t0}"
205
445
  return t
206
446
  end
207
- #@cv.signal([hint])
208
447
  n += 1
209
448
  end
210
449
  end
211
- #Thread.pass
212
450
  end
213
451
  end
214
452
 
215
453
  def deq_impl(hint,n)
216
454
  Log.debug "--- TQ#deq_impl #{@q.inspect}"
217
- @q_prior.shift || @q_later.shift
455
+ @q_input.shift || @q_later.shift
218
456
  end
219
457
 
220
458
  def clear
221
- @q_prior.clear
459
+ @q_noaction.clear
460
+ @q_input.clear
222
461
  @q_later.clear
223
- @reserved_q.clear
224
462
  end
225
463
 
226
464
  def empty?
227
- @q_prior.empty? && @q_later.empty? && @reserved_q.empty?
465
+ @q_noaction.empty? &&
466
+ @q_input.empty? &&
467
+ @q_later.empty?
228
468
  end
229
469
 
230
470
  def finish
231
471
  Log.debug "--- TQ#finish"
472
+ @q_noaction.finish
232
473
  @finished = true
233
474
  @cv.broadcast
234
475
  end
235
476
 
236
477
  def stop
478
+ @q_noaction.stop
237
479
  @mutex.synchronize do
238
480
  clear
239
481
  finish
@@ -241,8 +483,9 @@ module Pwrake
241
483
  end
242
484
 
243
485
  def thread_end(th)
244
- @th_end.push(th)
486
+ @th_end[th] = true
245
487
  @cv.broadcast
488
+ @q_noaction.thread_end(th)
246
489
  end
247
490
 
248
491
  def after_check(tasks)
@@ -1,3 +1,3 @@
1
1
  module Pwrake
2
- VERSION = "0.9.7"
2
+ VERSION = "0.9.8"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwrake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahiro TANAKA
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-06 00:00:00.000000000 Z
11
+ date: 2013-10-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Parallel workflow extension for Rake
14
14
  email:
@@ -26,9 +26,11 @@ files:
26
26
  - bin/pwrake
27
27
  - lib/pwrake.rb
28
28
  - lib/pwrake/application.rb
29
+ - lib/pwrake/cache_aware_queue.rb
29
30
  - lib/pwrake/counter.rb
30
31
  - lib/pwrake/file_utils.rb
31
32
  - lib/pwrake/gfarm_feature.rb
33
+ - lib/pwrake/gfwhere_pool.rb
32
34
  - lib/pwrake/graphviz.rb
33
35
  - lib/pwrake/locality_aware_queue.rb
34
36
  - lib/pwrake/logger.rb