pwrake 0.9.9 → 0.9.9.2
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 +4 -4
- data/README.md +23 -11
- data/bin/gfwhere-pipe +159 -0
- data/lib/pwrake.rb +1 -0
- data/lib/pwrake/application.rb +13 -3
- data/lib/pwrake/gfarm_feature.rb +1 -1
- data/lib/pwrake/gfwhere_pool.rb +0 -3
- data/lib/pwrake/host_list.rb +88 -0
- data/lib/pwrake/locality_aware_queue.rb +77 -23
- data/lib/pwrake/master.rb +2 -2
- data/lib/pwrake/mcgp.rb +444 -0
- data/lib/pwrake/option.rb +6 -48
- data/lib/pwrake/report/report.rb +15 -2
- data/lib/pwrake/task_algorithm.rb +52 -19
- data/lib/pwrake/task_queue.rb +126 -30
- data/lib/pwrake/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5f302ea2a00a59015b371e07ddf10f646f06eaa
|
4
|
+
data.tar.gz: 57d72fefb63e1a2b8270adf3b479aaba0add62f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
([
|
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
|
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`
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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.
|
129
|
-
* Rake
|
140
|
+
* Ruby 2.1.4
|
141
|
+
* Rake 10.1.0
|
130
142
|
* CentOS 6.4
|
131
143
|
|
132
144
|
## Acknowledgment
|
data/bin/gfwhere-pipe
ADDED
@@ -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
|
data/lib/pwrake.rb
CHANGED
data/lib/pwrake/application.rb
CHANGED
@@ -47,8 +47,8 @@ module Pwrake
|
|
47
47
|
@master.start
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
51
|
-
@master.
|
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
|
-
|
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
|
data/lib/pwrake/gfarm_feature.rb
CHANGED
data/lib/pwrake/gfwhere_pool.rb
CHANGED
@@ -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(
|
205
|
-
@
|
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
|
-
|
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
|
288
|
-
|
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
|
-
@
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
311
|
-
deq_locate(max_host)
|
365
|
+
nil
|
312
366
|
end
|
313
367
|
|
314
368
|
def inspect_q
|