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