pwrake 0.9.3
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.
- data/.gitignore +30 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +57 -0
- data/Rakefile +1 -0
- data/bin/pwrake +36 -0
- data/lib/pwrake/application.rb +187 -0
- data/lib/pwrake/counter.rb +54 -0
- data/lib/pwrake/file_utils.rb +70 -0
- data/lib/pwrake/gfarm_feature.rb +229 -0
- data/lib/pwrake/graphviz.rb +113 -0
- data/lib/pwrake/locality_aware_queue.rb +254 -0
- data/lib/pwrake/logger.rb +153 -0
- data/lib/pwrake/master.rb +109 -0
- data/lib/pwrake/option.rb +367 -0
- data/lib/pwrake/profiler.rb +88 -0
- data/lib/pwrake/rake_modify.rb +14 -0
- data/lib/pwrake/shell.rb +151 -0
- data/lib/pwrake/task_algorithm.rb +171 -0
- data/lib/pwrake/task_queue.rb +167 -0
- data/lib/pwrake/timer.rb +22 -0
- data/lib/pwrake/version.rb +3 -0
- data/lib/pwrake.rb +18 -0
- data/pwrake.gemspec +19 -0
- data/setup.rb +1585 -0
- data/spec/001/Rakefile +5 -0
- data/spec/002/Rakefile +19 -0
- data/spec/003/Rakefile +9 -0
- data/spec/004/Rakefile +7 -0
- data/spec/005/Rakefile +11 -0
- data/spec/006/Rakefile +3 -0
- data/spec/006/pwrake_conf.yaml +3 -0
- data/spec/007/Rakefile +22 -0
- data/spec/008/Rakefile +3 -0
- data/spec/008/pwrake_conf.yaml +3 -0
- data/spec/009/Rakefile +18 -0
- data/spec/009/pwrake_conf.yaml +2 -0
- data/spec/helper.rb +82 -0
- data/spec/hosts +3 -0
- data/spec/pwrake_spec.rb +83 -0
- metadata +119 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
InvocationChain = Rake::InvocationChain
|
4
|
+
TaskArguments = Rake::TaskArguments
|
5
|
+
|
6
|
+
module TaskAlgorithm
|
7
|
+
|
8
|
+
def location
|
9
|
+
@location ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def location=(a)
|
13
|
+
@location = a
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def invoke_modify(*args)
|
18
|
+
task_args = TaskArguments.new(arg_names, args)
|
19
|
+
flag = application.pwrake_options['HALT_QUEUE_WHILE_SEARCH']
|
20
|
+
start_time = Time.now
|
21
|
+
if flag
|
22
|
+
application.task_queue.enq_synchronize do
|
23
|
+
search_with_call_chain(self, task_args, InvocationChain::EMPTY)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
search_with_call_chain(self, task_args, InvocationChain::EMPTY)
|
27
|
+
end
|
28
|
+
Log.info "-- search_tasks %.6fs" % (Time.now-start_time)
|
29
|
+
|
30
|
+
if conn = Pwrake.current_shell
|
31
|
+
@waiting_thread = nil
|
32
|
+
application.thread_loop(conn,self)
|
33
|
+
else
|
34
|
+
@waiting_thread = Thread.current
|
35
|
+
Log.debug "--- sleep in invoke_modify #{self.name} #{@waiting_thread.inspect}"
|
36
|
+
sleep
|
37
|
+
Log.debug "--- awake in invoke_modify"
|
38
|
+
pw_invoke
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def pw_invoke
|
44
|
+
shell = Pwrake.current_shell
|
45
|
+
if shell
|
46
|
+
shell.current_task = self
|
47
|
+
log_host(shell.host)
|
48
|
+
end
|
49
|
+
@lock.synchronize do
|
50
|
+
return if @already_invoked
|
51
|
+
@already_invoked = true
|
52
|
+
end
|
53
|
+
pw_execute(@arg_data) if needed?
|
54
|
+
start_time = Time.now
|
55
|
+
pw_enq_subsequents
|
56
|
+
Log.info "-- pw_enq_subsequents(%s) %.6fs"%[self.name,Time.now-start_time]
|
57
|
+
shell.current_task = nil if shell
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Execute the actions associated with this task.
|
62
|
+
def pw_execute(args=nil)
|
63
|
+
args ||= Rake::EMPTY_TASK_ARGS
|
64
|
+
if application.options.dryrun
|
65
|
+
Log.info "** Execute (dry run) #{name}"
|
66
|
+
return
|
67
|
+
end
|
68
|
+
if application.options.trace
|
69
|
+
Log.info "** Execute #{name}"
|
70
|
+
end
|
71
|
+
application.enhance_with_matching_rule(name) if @actions.empty?
|
72
|
+
@actions.each do |act|
|
73
|
+
case act.arity
|
74
|
+
when 1
|
75
|
+
act.call(self)
|
76
|
+
else
|
77
|
+
act.call(self, args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def pw_enq_subsequents
|
83
|
+
@lock.synchronize do
|
84
|
+
my_name = self.name
|
85
|
+
application.task_queue.enq_synchronize do
|
86
|
+
@subsequents.each do |t| # <<--- competition !!!
|
87
|
+
t && t.check_and_enq(my_name)
|
88
|
+
end
|
89
|
+
@already_finished = true # <<--- competition !!!
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_and_enq(preq_name=nil)
|
95
|
+
@unfinished_prereq.delete(preq_name)
|
96
|
+
if @unfinished_prereq.empty?
|
97
|
+
if @waiting_thread
|
98
|
+
Log.debug "--- @waiting_thread.wakeup name=#{self.name} "
|
99
|
+
@waiting_thread.wakeup
|
100
|
+
else
|
101
|
+
Log.debug "--- check_and_enq enq name=#{self.name} "
|
102
|
+
application.task_queue.enq(self)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Same as search, but explicitly pass a call chain to detect
|
108
|
+
# circular dependencies.
|
109
|
+
def search_with_call_chain(subseq, task_args, invocation_chain) # :nodoc:
|
110
|
+
new_chain = InvocationChain.append(self, invocation_chain)
|
111
|
+
@lock.synchronize do
|
112
|
+
if application.options.trace
|
113
|
+
Log.info "** Search #{name} #{format_search_flags}"
|
114
|
+
end
|
115
|
+
|
116
|
+
return true if @already_finished # <<--- competition !!!
|
117
|
+
@subsequents ||= []
|
118
|
+
@subsequents << subseq # <<--- competition !!!
|
119
|
+
|
120
|
+
if ! @already_searched
|
121
|
+
@already_searched = true
|
122
|
+
@arg_data = task_args
|
123
|
+
search_prerequisites(task_args, new_chain)
|
124
|
+
end
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
rescue Exception => ex
|
128
|
+
add_chain_to(ex, new_chain)
|
129
|
+
raise ex
|
130
|
+
end
|
131
|
+
|
132
|
+
# Search all the prerequisites of a task.
|
133
|
+
def search_prerequisites(task_args, invocation_chain) # :nodoc:
|
134
|
+
@unfinished_prereq = @prerequisites.dup
|
135
|
+
prerequisite_tasks.each { |prereq|
|
136
|
+
#prereq_args = task_args.new_scope(prereq.arg_names) # in vain
|
137
|
+
if prereq.search_with_call_chain(self, task_args, invocation_chain)
|
138
|
+
@unfinished_prereq.delete(prereq.name)
|
139
|
+
end
|
140
|
+
}
|
141
|
+
check_and_enq
|
142
|
+
end
|
143
|
+
|
144
|
+
# Format the trace flags for display.
|
145
|
+
def format_search_flags
|
146
|
+
flags = []
|
147
|
+
flags << "finished" if @already_finished
|
148
|
+
flags << "first_time" unless @already_searched
|
149
|
+
flags << "not_needed" unless needed?
|
150
|
+
flags.empty? ? "" : "(" + flags.join(", ") + ")"
|
151
|
+
end
|
152
|
+
private :format_search_flags
|
153
|
+
|
154
|
+
|
155
|
+
def log_host(exec_host)
|
156
|
+
# exec_host = Pwrake.current_shell.host
|
157
|
+
prereq_name = @prerequisites[0]
|
158
|
+
if kind_of?(Rake::FileTask) and prereq_name
|
159
|
+
Pwrake.application.count( @location, exec_host )
|
160
|
+
if @location and @location.include? exec_host
|
161
|
+
compare = "=="
|
162
|
+
else
|
163
|
+
compare = "!="
|
164
|
+
end
|
165
|
+
Log.info "-- access to #{prereq_name}: file_host=#{@location.inspect} #{compare} exec_host=#{exec_host}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end # module Pwrake
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
class TaskQueue
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
@finished = false
|
7
|
+
@halt = false
|
8
|
+
@mutex = Mutex.new
|
9
|
+
@cv = ConditionVariable.new
|
10
|
+
@th_end = []
|
11
|
+
@enable_steal = true
|
12
|
+
@q = []
|
13
|
+
@reservation = {}
|
14
|
+
@reserved_q = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :mutex
|
18
|
+
attr_accessor :enable_steal
|
19
|
+
|
20
|
+
def reserve(item)
|
21
|
+
@reservation[item] = Thread.current
|
22
|
+
end
|
23
|
+
|
24
|
+
def halt
|
25
|
+
@mutex.synchronize do
|
26
|
+
@halt = true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def resume
|
31
|
+
@mutex.synchronize do
|
32
|
+
@halt = false
|
33
|
+
@cv.broadcast
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def enq_synchronize
|
38
|
+
if @halt
|
39
|
+
yield
|
40
|
+
else
|
41
|
+
@mutex.synchronize do
|
42
|
+
yield
|
43
|
+
enq_finish
|
44
|
+
end
|
45
|
+
@cv.broadcast
|
46
|
+
end
|
47
|
+
@reserved_q.keys.each do |th|
|
48
|
+
Log.debug "--- run #{th}";
|
49
|
+
th.run
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def enq_finish
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def enq(item,hint=nil)
|
58
|
+
if th = @reservation[item]
|
59
|
+
@reserved_q[th] = item
|
60
|
+
else
|
61
|
+
enq_impl(item,hint)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def enq_bak(item,hint=nil)
|
67
|
+
# Log.debug "--- #{self.class}#enq #{item.inspect}"
|
68
|
+
th = nil
|
69
|
+
if @halt
|
70
|
+
if th = @reservation[item]
|
71
|
+
@reserved_q[th] = item
|
72
|
+
else
|
73
|
+
enq_impl(item,hint)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
@mutex.synchronize do
|
77
|
+
if th = @reservation[item]
|
78
|
+
@reserved_q[th] = item
|
79
|
+
else
|
80
|
+
enq_impl(item,hint)
|
81
|
+
@cv.signal
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
@reserved_q.keys.each{|th|
|
86
|
+
Log.debug "--- run #{th}";
|
87
|
+
th.run
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def enq_impl(item,hint)
|
92
|
+
@q.push(item) # FIFO Queue
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
def deq(hint=nil)
|
97
|
+
# Log.debug "--- #{self.class}#deq #{self.inspect}"
|
98
|
+
n = 0
|
99
|
+
loop do
|
100
|
+
@mutex.synchronize do
|
101
|
+
if @th_end.first == Thread.current
|
102
|
+
@th_end.shift
|
103
|
+
return false
|
104
|
+
|
105
|
+
elsif @halt
|
106
|
+
Log.debug "--- halt in #{self.class}#deq @q=#{@q.inspect}"
|
107
|
+
@cv.wait(@mutex)
|
108
|
+
n = 0
|
109
|
+
|
110
|
+
elsif item = @reserved_q.delete(Thread.current)
|
111
|
+
Log.debug "--- deq from reserved_q=#{item.inspect}"
|
112
|
+
return item
|
113
|
+
|
114
|
+
elsif empty? # no item in queue
|
115
|
+
Log.debug "--- empty=true in #{self.class}#deq @finished=#{@finished.inspect}"
|
116
|
+
if @finished
|
117
|
+
@cv.signal
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
Log.debug "--- waiting in #{self.class}#deq @finished=#{@finished.inspect}"
|
121
|
+
@cv.wait(@mutex)
|
122
|
+
n = 0
|
123
|
+
|
124
|
+
else
|
125
|
+
if t = deq_impl(hint,n)
|
126
|
+
Log.debug "--- #{self.class}#deq #{t.inspect}"
|
127
|
+
return t
|
128
|
+
end
|
129
|
+
n += 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def deq_impl(hint,n)
|
136
|
+
@q.shift # FIFO Queue
|
137
|
+
end
|
138
|
+
|
139
|
+
def clear
|
140
|
+
@q.clear
|
141
|
+
@reserved_q.clear
|
142
|
+
end
|
143
|
+
|
144
|
+
def empty?
|
145
|
+
@q.empty? && @reserved_q.empty?
|
146
|
+
end
|
147
|
+
|
148
|
+
def finish
|
149
|
+
Log.debug "--- #{self.class}#finish"
|
150
|
+
@finished = true
|
151
|
+
@cv.signal
|
152
|
+
end
|
153
|
+
|
154
|
+
def stop
|
155
|
+
@mutex.synchronize do
|
156
|
+
clear
|
157
|
+
finish
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def thread_end(th)
|
162
|
+
@th_end.push(th)
|
163
|
+
@cv.broadcast
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
data/lib/pwrake/timer.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
class Timer
|
4
|
+
|
5
|
+
def initialize(prefix,*extra)
|
6
|
+
@prefix = prefix
|
7
|
+
@start_time = Time.now
|
8
|
+
str = "%s[start]:%s %s" %
|
9
|
+
[@prefix, Log.fmt_time(@start_time), extra.join(' ')]
|
10
|
+
Log.info(str)
|
11
|
+
end
|
12
|
+
|
13
|
+
def finish(*extra)
|
14
|
+
end_time = Time.now
|
15
|
+
elap_time = end_time - @start_time
|
16
|
+
str = "%s[end]:%s elap=%.3f %s" %
|
17
|
+
[@prefix, Log.fmt_time(end_time), elap_time, extra.join(' ')]
|
18
|
+
Log.info(str)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/pwrake.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "thread"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
require "pwrake/version"
|
5
|
+
|
6
|
+
require "pwrake/logger"
|
7
|
+
require "pwrake/timer"
|
8
|
+
require "pwrake/counter"
|
9
|
+
require "pwrake/file_utils"
|
10
|
+
require "pwrake/profiler"
|
11
|
+
require "pwrake/shell"
|
12
|
+
require "pwrake/task_algorithm"
|
13
|
+
require "pwrake/task_queue"
|
14
|
+
require "pwrake/option"
|
15
|
+
require "pwrake/master"
|
16
|
+
require "pwrake/application"
|
17
|
+
|
18
|
+
require "pwrake/rake_modify"
|
data/pwrake.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pwrake/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "pwrake"
|
8
|
+
gem.version = Pwrake::VERSION
|
9
|
+
gem.authors = ["Masahiro TANAKA"]
|
10
|
+
gem.email = ["masa16.tanaka@gmail.com"]
|
11
|
+
gem.description = %q{Parallel workflow extension for Rake}
|
12
|
+
gem.summary = %q{Adding Parallel and Distributed feature to Rake}
|
13
|
+
gem.homepage = "http://masa16.github.com/pwrake"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|