drake 0.8.4.1.0.18 → 0.8.4.1.1.0
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/Rakefile.drake +2 -31
- data/lib/rake.rb +31 -49
- data/lib/rake/comp_tree/algorithm.rb +29 -34
- data/lib/rake/comp_tree/comp_tree.rb +42 -0
- data/lib/rake/comp_tree/driver.rb +37 -83
- data/lib/rake/comp_tree/error.rb +18 -23
- data/lib/rake/comp_tree/node.rb +25 -12
- data/lib/rake/parallel.rb +9 -14
- data/lib/rake/ruby182_test_unit_fix.rb +0 -0
- data/test/parallel.rb +1 -0
- data/test/shellcommand.rb +0 -0
- data/test/single_threaded.rb +1 -0
- data/test/test_parallel.rb +29 -8
- data/test/test_top_level_functions.rb +4 -8
- metadata +7 -7
- data/lib/rake/comp_tree/diagnostic.rb +0 -38
data/Rakefile.drake
CHANGED
@@ -1,28 +1,6 @@
|
|
1
1
|
|
2
|
-
require 'fileutils'
|
3
|
-
|
4
|
-
######################################################################
|
5
|
-
# git
|
6
|
-
|
7
2
|
def git(*args)
|
8
|
-
|
9
|
-
sh(*cmd)
|
10
|
-
end
|
11
|
-
|
12
|
-
task :add_contrib_first_time => :init_contrib do
|
13
|
-
git(*%w!merge --squash -s ours --no-commit comp_tree/master!)
|
14
|
-
git(*%w!read-tree --prefix=contrib/comp_tree -u comp_tree/master!)
|
15
|
-
git("commit", "-m", "add comp_tree package")
|
16
|
-
end
|
17
|
-
|
18
|
-
task :init_contrib do
|
19
|
-
unless `git remote`.split.include? "comp_tree"
|
20
|
-
git(*%w!remote add -f comp_tree git@github.com:quix/comp_tree.git!)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
task :run_pull_contrib => :init_contrib do
|
25
|
-
git(*%w!pull --no-commit -s subtree comp_tree master!)
|
3
|
+
sh("git", *args)
|
26
4
|
end
|
27
5
|
|
28
6
|
task :pull_mainline do
|
@@ -31,14 +9,7 @@ task :pull_mainline do
|
|
31
9
|
refs/heads/master:refs/heads/origin!)
|
32
10
|
end
|
33
11
|
|
34
|
-
task :
|
35
|
-
|
36
|
-
######################################################################
|
37
|
-
# drake_release
|
38
|
-
|
39
|
-
task :drake_prerelease => [:clean, :gemspec] do
|
40
|
-
rm_rf("html")
|
41
|
-
rm_rf("pkg")
|
12
|
+
task :drake_prerelease => [:clobber, :gemspec] do
|
42
13
|
unless `git status` =~ %r!nothing to commit \(working directory clean\)!
|
43
14
|
raise "Directory not clean"
|
44
15
|
end
|
data/lib/rake.rb
CHANGED
@@ -29,7 +29,7 @@
|
|
29
29
|
# as a library via a require statement, but it can be distributed
|
30
30
|
# independently as an application.
|
31
31
|
|
32
|
-
RAKEVERSION = '0.8.4.1.0
|
32
|
+
RAKEVERSION = '0.8.4.1.1.0'
|
33
33
|
|
34
34
|
require 'rbconfig'
|
35
35
|
require 'fileutils'
|
@@ -581,9 +581,8 @@ module Rake
|
|
581
581
|
end
|
582
582
|
|
583
583
|
def base_invoke(*args) #:nodoc:
|
584
|
-
|
585
|
-
|
586
|
-
InvocationChain::EMPTY)
|
584
|
+
task_args = TaskArguments.new(arg_names, args)
|
585
|
+
invoke_with_call_chain(task_args, InvocationChain::EMPTY)
|
587
586
|
end
|
588
587
|
|
589
588
|
# Invoke the task if it is needed. Prerequites are invoked first.
|
@@ -591,12 +590,12 @@ module Rake
|
|
591
590
|
if application.num_threads == 1
|
592
591
|
base_invoke(*args)
|
593
592
|
else
|
594
|
-
if application.
|
593
|
+
if application.parallel.lock.locked?
|
595
594
|
raise "Calling Task#invoke within a task is not allowed."
|
596
595
|
end
|
597
|
-
application.
|
598
|
-
application.
|
599
|
-
application.
|
596
|
+
application.parallel.lock.synchronize {
|
597
|
+
application.parallel.tasks.clear
|
598
|
+
application.parallel.needed.clear
|
600
599
|
base_invoke(*args)
|
601
600
|
application.invoke_parallel(self.name)
|
602
601
|
}
|
@@ -618,40 +617,25 @@ module Rake
|
|
618
617
|
@prerequisites = @prerequisites.sort_by { rand }
|
619
618
|
end
|
620
619
|
|
621
|
-
prereqs =
|
622
|
-
if application.num_threads == 1
|
623
|
-
invoke_prerequisites(task_args, new_chain)
|
624
|
-
nil
|
625
|
-
else
|
626
|
-
invoke_prerequisites_parallel(task_args, new_chain)
|
627
|
-
end
|
628
|
-
|
629
620
|
if application.num_threads == 1
|
630
|
-
|
631
|
-
|
632
|
-
#
|
633
|
-
if needed?
|
634
|
-
execute(task_args)
|
635
|
-
end
|
621
|
+
invoke_prerequisites(task_args, new_chain)
|
622
|
+
execute(task_args) if needed?
|
636
623
|
else
|
637
624
|
#
|
638
|
-
#
|
625
|
+
# Parallel mode -- gather tasks for batch execution.
|
639
626
|
#
|
640
627
|
# Either the task knows it's needed or we've marked it as
|
641
|
-
#
|
628
|
+
# needed.
|
642
629
|
#
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
# the 'needed?' flag does not propagate.
|
651
|
-
#
|
630
|
+
# Why do we manually mark tasks as needed? Since this is a
|
631
|
+
# dry run, files are not created or modified. Therefore the
|
632
|
+
# 'needed?' result does not propagate through the recursion.
|
633
|
+
#
|
634
|
+
prereqs = invoke_prerequisites_parallel(task_args, new_chain)
|
635
|
+
if needed? or application.parallel.needed[self]
|
636
|
+
application.parallel.tasks[name] = [task_args, prereqs]
|
652
637
|
unless invocation_chain == InvocationChain::EMPTY
|
653
|
-
application.
|
654
|
-
parallel_parent_flags[invocation_chain.value] = true
|
638
|
+
application.parallel.needed[invocation_chain.value] = true
|
655
639
|
end
|
656
640
|
end
|
657
641
|
end
|
@@ -1028,19 +1012,17 @@ end
|
|
1028
1012
|
#
|
1029
1013
|
# +seq+ : Force tasks to be executed sequentially.
|
1030
1014
|
#
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1015
|
+
def seq
|
1016
|
+
Rake::SEQ_LAMBDA
|
1017
|
+
end
|
1018
|
+
module Rake
|
1019
|
+
SEQ_LAMBDA = lambda { |*task_names|
|
1034
1020
|
(1...task_names.size).each { |n|
|
1035
1021
|
task task_names[n] => task_names[n - 1]
|
1036
1022
|
}
|
1037
1023
|
task_names.last
|
1038
1024
|
}
|
1039
|
-
|
1040
|
-
define_method(:seq) {
|
1041
|
-
seq_lambda
|
1042
|
-
}
|
1043
|
-
}
|
1025
|
+
end
|
1044
1026
|
|
1045
1027
|
# ###########################################################################
|
1046
1028
|
# This a FileUtils extension that defines several additional commands to be
|
@@ -1773,9 +1755,7 @@ module Rake
|
|
1773
1755
|
alias :last_comment :last_description # Backwards compatibility
|
1774
1756
|
|
1775
1757
|
attr_accessor :num_threads
|
1776
|
-
attr_reader :
|
1777
|
-
attr_reader :parallel_lock #:nodoc:
|
1778
|
-
attr_reader :parallel_parent_flags #:nodoc:
|
1758
|
+
attr_reader :parallel
|
1779
1759
|
|
1780
1760
|
def initialize
|
1781
1761
|
super
|
@@ -1785,9 +1765,11 @@ module Rake
|
|
1785
1765
|
@last_description = nil
|
1786
1766
|
|
1787
1767
|
@num_threads = 1
|
1788
|
-
|
1789
|
-
@
|
1790
|
-
@
|
1768
|
+
|
1769
|
+
@parallel = Struct.new(:tasks, :needed, :lock).new
|
1770
|
+
@parallel.tasks = Hash.new
|
1771
|
+
@parallel.needed = Hash.new
|
1772
|
+
@parallel.lock = Mutex.new
|
1791
1773
|
end
|
1792
1774
|
|
1793
1775
|
def create_rule(*args, &block)
|
@@ -16,9 +16,7 @@ module Rake::CompTree
|
|
16
16
|
|
17
17
|
def compute_multithreaded(root, num_threads)
|
18
18
|
#trace "Computing #{root.name} with #{num_threads} threads"
|
19
|
-
|
20
|
-
result = nil
|
21
|
-
|
19
|
+
finished = nil
|
22
20
|
tree_mutex = Mutex.new
|
23
21
|
node_finished_condition = ConditionVariable.new
|
24
22
|
thread_wake_condition = ConditionVariable.new
|
@@ -37,8 +35,8 @@ module Rake::CompTree
|
|
37
35
|
|
38
36
|
loop_with(:leave, :again) {
|
39
37
|
node = tree_mutex.synchronize {
|
40
|
-
#trace "Thread #{thread_index}
|
41
|
-
if
|
38
|
+
#trace "Thread #{thread_index} acquired tree lock; begin search"
|
39
|
+
if finished
|
42
40
|
#trace "Thread #{thread_index} detected finish"
|
43
41
|
num_threads_in_use -= 1
|
44
42
|
throw :leave
|
@@ -46,7 +44,8 @@ module Rake::CompTree
|
|
46
44
|
#
|
47
45
|
# Find a node. The node we obtain, if any, will be locked.
|
48
46
|
#
|
49
|
-
|
47
|
+
node = find_node(root)
|
48
|
+
if node
|
50
49
|
#trace "Thread #{thread_index} found node #{node.name}"
|
51
50
|
node
|
52
51
|
else
|
@@ -58,7 +57,10 @@ module Rake::CompTree
|
|
58
57
|
}
|
59
58
|
|
60
59
|
#trace "Thread #{thread_index} computing node"
|
61
|
-
|
60
|
+
#debug {
|
61
|
+
# node.trace_compute
|
62
|
+
#}
|
63
|
+
node.compute
|
62
64
|
#trace "Thread #{thread_index} node computed; waiting for tree lock"
|
63
65
|
|
64
66
|
tree_mutex.synchronize {
|
@@ -66,25 +68,28 @@ module Rake::CompTree
|
|
66
68
|
#debug {
|
67
69
|
# name = "#{node.name}" + ((node == root) ? " (ROOT NODE)" : "")
|
68
70
|
# initial = "Thread #{thread_index} compute result for #{name}: "
|
69
|
-
# status =
|
71
|
+
# status = node.computed.is_a?(Exception) ? "error" : "success"
|
70
72
|
# trace initial + status
|
71
|
-
# trace "Thread #{thread_index} node result: #{
|
73
|
+
# trace "Thread #{thread_index} node result: #{node.result}"
|
72
74
|
#}
|
73
75
|
|
74
|
-
node.
|
75
|
-
|
76
|
+
if node.computed.is_a? Exception
|
77
|
+
#
|
78
|
+
# An error occurred; we are done.
|
79
|
+
#
|
80
|
+
finished = node.computed
|
81
|
+
elsif node == root
|
82
|
+
#
|
83
|
+
# Root node was computed; we are done.
|
84
|
+
#
|
85
|
+
finished = true
|
86
|
+
end
|
87
|
+
|
76
88
|
#
|
77
89
|
# remove locks for this node (shared lock and own lock)
|
78
90
|
#
|
79
91
|
node.unlock
|
80
92
|
|
81
|
-
if node == root or node_result.is_a? Exception
|
82
|
-
#
|
83
|
-
# Root node was computed or error occurred; we are done.
|
84
|
-
#
|
85
|
-
result = node_result
|
86
|
-
end
|
87
|
-
|
88
93
|
#
|
89
94
|
# Tell the main thread that another node was computed.
|
90
95
|
#
|
@@ -106,7 +111,7 @@ module Rake::CompTree
|
|
106
111
|
#trace "Main: waking threads"
|
107
112
|
thread_wake_condition.broadcast
|
108
113
|
|
109
|
-
if
|
114
|
+
if finished
|
110
115
|
#trace "Main: detected finish."
|
111
116
|
break
|
112
117
|
end
|
@@ -129,17 +134,17 @@ module Rake::CompTree
|
|
129
134
|
}
|
130
135
|
|
131
136
|
#trace "Main: computation done."
|
132
|
-
if
|
133
|
-
raise
|
137
|
+
if finished.is_a? Exception
|
138
|
+
raise finished
|
134
139
|
else
|
135
|
-
result
|
140
|
+
root.result
|
136
141
|
end
|
137
142
|
end
|
138
143
|
|
139
144
|
def find_node(node)
|
140
145
|
# --- only called inside shared tree mutex
|
141
146
|
#trace "Looking for a node, starting with #{node.name}"
|
142
|
-
if node.
|
147
|
+
if node.computed
|
143
148
|
#
|
144
149
|
# already computed
|
145
150
|
#
|
@@ -158,20 +163,10 @@ module Rake::CompTree
|
|
158
163
|
#
|
159
164
|
#trace "Checking #{node.name}'s children"
|
160
165
|
node.each_child { |child|
|
161
|
-
|
162
|
-
return next_node
|
163
|
-
end
|
166
|
+
next_node = find_node(child) and return next_node
|
164
167
|
}
|
165
168
|
nil
|
166
169
|
end
|
167
170
|
end
|
168
|
-
|
169
|
-
def compute_node(node)
|
170
|
-
begin
|
171
|
-
node.compute
|
172
|
-
rescue Exception => e
|
173
|
-
e
|
174
|
-
end
|
175
|
-
end
|
176
171
|
end
|
177
172
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2008 James M. Lawrence. All rights reserved.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'rake/comp_tree/driver'
|
24
|
+
|
25
|
+
module Rake end
|
26
|
+
module Rake::CompTree
|
27
|
+
class << self
|
28
|
+
#
|
29
|
+
# Build and run a new computation tree.
|
30
|
+
#
|
31
|
+
# A Driver instance is passed to the given block.
|
32
|
+
#
|
33
|
+
# Options hash:
|
34
|
+
#
|
35
|
+
# <tt>:node_class</tt> -- (Class) CompTree::Node subclass from
|
36
|
+
# which nodes are created.
|
37
|
+
#
|
38
|
+
def build(opts = nil)
|
39
|
+
yield Driver.new(opts)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -13,9 +13,9 @@ module Rake::CompTree
|
|
13
13
|
#
|
14
14
|
class Driver
|
15
15
|
include Algorithm
|
16
|
-
|
16
|
+
|
17
17
|
#
|
18
|
-
#
|
18
|
+
# Build and run a new computation tree.
|
19
19
|
#
|
20
20
|
# Options hash:
|
21
21
|
#
|
@@ -23,18 +23,14 @@ module Rake::CompTree
|
|
23
23
|
# which nodes are created.
|
24
24
|
#
|
25
25
|
def initialize(opts = nil)
|
26
|
-
@node_class =
|
26
|
+
@node_class = (
|
27
27
|
if opts and opts[:node_class]
|
28
28
|
opts[:node_class]
|
29
29
|
else
|
30
30
|
Node
|
31
31
|
end
|
32
|
-
|
32
|
+
)
|
33
33
|
@nodes = Hash.new
|
34
|
-
|
35
|
-
if block_given?
|
36
|
-
yield self
|
37
|
-
end
|
38
34
|
end
|
39
35
|
|
40
36
|
#
|
@@ -45,55 +41,43 @@ module Rake::CompTree
|
|
45
41
|
#
|
46
42
|
# Define a computation node.
|
47
43
|
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
# defined which depends on the nodes +height+, +width+, +offset+.
|
44
|
+
# The first argument is the name of the node to define.
|
45
|
+
# Subsequent arguments are the names of this node's children.
|
51
46
|
#
|
52
|
-
# The
|
53
|
-
#
|
54
|
-
# width*height - offset
|
55
|
-
# }
|
47
|
+
# The values of the child nodes are passed to the block. The
|
48
|
+
# block returns the result of this node.
|
56
49
|
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# width*height - offset
|
60
|
-
# }
|
61
|
-
# (Note the '%' before the brace.)
|
50
|
+
# In this example, a computation node named +area+ is defined
|
51
|
+
# which depends on the nodes +width+ and +height+.
|
62
52
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# }
|
53
|
+
# driver.define(:area, :width, :height) { |width, height|
|
54
|
+
# width*height
|
55
|
+
# }
|
67
56
|
#
|
68
57
|
def define(*args, &block)
|
69
58
|
parent_name = args.first
|
70
59
|
children_names = args[1..-1]
|
71
60
|
|
72
61
|
unless parent_name
|
73
|
-
raise
|
62
|
+
raise ArgumentError, "No name given for node"
|
74
63
|
end
|
75
64
|
|
76
65
|
#
|
77
66
|
# retrieve or create parent and children
|
78
67
|
#
|
79
|
-
parent =
|
80
|
-
|
81
|
-
|
82
|
-
else
|
83
|
-
@nodes[parent_name] = @node_class.new(parent_name)
|
84
|
-
end
|
68
|
+
parent = @nodes[parent_name] || (
|
69
|
+
@nodes[parent_name] = @node_class.new(parent_name)
|
70
|
+
)
|
85
71
|
|
86
72
|
if parent.function
|
87
|
-
raise
|
73
|
+
raise RedefinitionError, "Node `#{parent.name.inspect}' redefined."
|
88
74
|
end
|
89
75
|
parent.function = block
|
90
76
|
|
91
77
|
children = children_names.map { |child_name|
|
92
|
-
|
93
|
-
t
|
94
|
-
else
|
78
|
+
@nodes[child_name] || (
|
95
79
|
@nodes[child_name] = @node_class.new(child_name)
|
96
|
-
|
80
|
+
)
|
97
81
|
}
|
98
82
|
|
99
83
|
#
|
@@ -105,72 +89,37 @@ module Rake::CompTree
|
|
105
89
|
}
|
106
90
|
end
|
107
91
|
|
108
|
-
#
|
109
|
-
# parsing/evaling helper
|
110
|
-
#
|
111
|
-
def evaling_define(*args) #:nodoc:
|
112
|
-
function_name = args[0]
|
113
|
-
function_arg_names = args[1..-2]
|
114
|
-
function_string = args.last.to_str
|
115
|
-
|
116
|
-
comma_separated = function_arg_names.map { |name|
|
117
|
-
name.to_s
|
118
|
-
}.join(",")
|
119
|
-
|
120
|
-
eval_me = %{
|
121
|
-
lambda { |#{comma_separated}|
|
122
|
-
#{function_string}
|
123
|
-
}
|
124
|
-
}
|
125
|
-
|
126
|
-
function = eval(eval_me, TOPLEVEL_BINDING)
|
127
|
-
|
128
|
-
define(function_name, *function_arg_names, &function)
|
129
|
-
end
|
130
|
-
|
131
|
-
def method_missing(symbol, *args, &block) #:nodoc:
|
132
|
-
if match = symbol.to_s.match(%r!\Adefine_(\w+)\Z!)
|
133
|
-
method_name = match.captures.first.to_sym
|
134
|
-
if block
|
135
|
-
define(method_name, *args, &block)
|
136
|
-
else
|
137
|
-
evaling_define(method_name, *args)
|
138
|
-
end
|
139
|
-
else
|
140
|
-
super(symbol, *args, &block)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
92
|
#
|
145
93
|
# Mark this node and all its children as uncomputed.
|
146
94
|
#
|
147
95
|
# Arguments:
|
148
96
|
#
|
149
|
-
# +name+ --
|
97
|
+
# +name+ -- unique node identifier (usually a symbol).
|
150
98
|
#
|
151
99
|
def reset(name)
|
152
100
|
@nodes[name].reset
|
153
101
|
end
|
154
102
|
|
155
103
|
#
|
156
|
-
# Check for a cyclic graph below the given node.
|
157
|
-
#
|
104
|
+
# Check for a cyclic graph below the given node. If found,
|
105
|
+
# returns the names of the nodes (in order) which form a loop.
|
106
|
+
# Otherwise returns nil.
|
158
107
|
#
|
159
108
|
# Arguments:
|
160
109
|
#
|
161
|
-
# +name+ --
|
110
|
+
# +name+ -- unique node identifier (usually a symbol).
|
162
111
|
#
|
163
112
|
def check_circular(name)
|
164
|
-
helper =
|
113
|
+
helper = Proc.new { |root, chain|
|
165
114
|
if chain.include? root
|
166
|
-
|
167
|
-
"Circular dependency detected: #{root} => #{chain.last} => #{root}"
|
115
|
+
return chain + [root]
|
168
116
|
end
|
169
117
|
@nodes[root].children.each { |child|
|
170
118
|
helper.call(child.name, chain + [root])
|
171
119
|
}
|
172
120
|
}
|
173
121
|
helper.call(name, [])
|
122
|
+
nil
|
174
123
|
end
|
175
124
|
|
176
125
|
#
|
@@ -178,18 +127,23 @@ module Rake::CompTree
|
|
178
127
|
#
|
179
128
|
# Arguments:
|
180
129
|
#
|
181
|
-
# +name+ --
|
130
|
+
# +name+ -- unique node identifier (usually a symbol).
|
182
131
|
#
|
183
132
|
# +threads+ -- (Integer) number of threads.
|
184
133
|
#
|
185
|
-
|
134
|
+
# compute(:volume, :threads => 4) syntax is also accepted.
|
135
|
+
#
|
136
|
+
def compute(name, opts)
|
137
|
+
threads = (opts.respond_to?(:to_i) ? opts : opts[:threads]).to_i
|
186
138
|
root = @nodes[name]
|
187
139
|
|
188
140
|
if threads < 1
|
189
|
-
raise
|
141
|
+
raise ArgumentError, "threads is #{threads}"
|
190
142
|
end
|
191
143
|
|
192
|
-
if
|
144
|
+
if root.computed
|
145
|
+
root.result
|
146
|
+
elsif threads == 1
|
193
147
|
root.result = root.compute_now
|
194
148
|
else
|
195
149
|
compute_multithreaded(root, threads)
|
data/lib/rake/comp_tree/error.rb
CHANGED
@@ -1,28 +1,23 @@
|
|
1
1
|
|
2
2
|
module Rake end
|
3
3
|
module Rake::CompTree
|
4
|
-
|
5
|
-
|
6
|
-
class Base < StandardError ; end
|
4
|
+
# Base class for CompTree errors.
|
5
|
+
class Error < StandardError ; end
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
# No function was defined for this node.
|
26
|
-
class NoFunctionError < Base ; end
|
27
|
-
end
|
7
|
+
# Internal error inside CompTree. Please send a bug report.
|
8
|
+
class AssertionFailedError < Error ; end
|
9
|
+
|
10
|
+
# Bad arguments were passed to a method.
|
11
|
+
class ArgumentError < Error ; end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Attempt to redefine a Node.
|
15
|
+
#
|
16
|
+
# If you wish to only replace the function, set
|
17
|
+
# driver.nodes[name].function = some_new_lambda
|
18
|
+
#
|
19
|
+
class RedefinitionError < Error ; end
|
20
|
+
|
21
|
+
# No function was defined for this node.
|
22
|
+
class NoFunctionError < Error ; end
|
28
23
|
end
|
data/lib/rake/comp_tree/node.rb
CHANGED
@@ -13,6 +13,7 @@ module Rake::CompTree
|
|
13
13
|
attr_accessor :children #:nodoc:
|
14
14
|
attr_accessor :function #:nodoc:
|
15
15
|
attr_accessor :result #:nodoc:
|
16
|
+
attr_accessor :computed #:nodoc:
|
16
17
|
attr_accessor :shared_lock #:nodoc:
|
17
18
|
|
18
19
|
#
|
@@ -23,6 +24,7 @@ module Rake::CompTree
|
|
23
24
|
@mutex = Mutex.new
|
24
25
|
@children = []
|
25
26
|
@parents = []
|
27
|
+
@function = nil
|
26
28
|
reset_self
|
27
29
|
end
|
28
30
|
|
@@ -33,6 +35,7 @@ module Rake::CompTree
|
|
33
35
|
@shared_lock = 0
|
34
36
|
@children_results = nil
|
35
37
|
@result = nil
|
38
|
+
@computed = nil
|
36
39
|
end
|
37
40
|
|
38
41
|
#
|
@@ -81,14 +84,18 @@ module Rake::CompTree
|
|
81
84
|
# If all children have been computed, return their results;
|
82
85
|
# otherwise return nil.
|
83
86
|
#
|
87
|
+
# Do not assign to @children_results since own lock is not
|
88
|
+
# necessarily aquired.
|
89
|
+
#
|
84
90
|
def find_children_results #:nodoc:
|
85
|
-
|
86
|
-
@children_results
|
87
|
-
else
|
91
|
+
@children_results or (
|
88
92
|
@children.map { |child|
|
89
|
-
child.
|
93
|
+
unless child.computed
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
child.result
|
90
97
|
}
|
91
|
-
|
98
|
+
)
|
92
99
|
end
|
93
100
|
|
94
101
|
def children_results=(value) #:nodoc:
|
@@ -99,9 +106,9 @@ module Rake::CompTree
|
|
99
106
|
# debug {
|
100
107
|
# # --- own mutex
|
101
108
|
# trace "Computing #{@name}"
|
102
|
-
# raise
|
103
|
-
# raise
|
104
|
-
# raise
|
109
|
+
# raise AssertionFailedError if @computed
|
110
|
+
# raise AssertionFailedError unless @mutex.locked?
|
111
|
+
# raise AssertionFailedError unless @children_results
|
105
112
|
# }
|
106
113
|
#end
|
107
114
|
|
@@ -110,11 +117,17 @@ module Rake::CompTree
|
|
110
117
|
# already acquired.
|
111
118
|
#
|
112
119
|
def compute #:nodoc:
|
113
|
-
|
114
|
-
|
120
|
+
begin
|
121
|
+
unless @function
|
122
|
+
raise NoFunctionError,
|
115
123
|
"No function was defined for node '#{@name.inspect}'"
|
124
|
+
end
|
125
|
+
@result = @function.call(*@children_results)
|
126
|
+
@computed = true
|
127
|
+
rescue Exception => e
|
128
|
+
@computed = e
|
116
129
|
end
|
117
|
-
@
|
130
|
+
@result
|
118
131
|
end
|
119
132
|
|
120
133
|
def try_lock #:nodoc:
|
@@ -134,7 +147,7 @@ module Rake::CompTree
|
|
134
147
|
def unlock #:nodoc:
|
135
148
|
# --- shared tree mutex and own mutex
|
136
149
|
#debug {
|
137
|
-
# raise
|
150
|
+
# raise AssertionFailedError unless @mutex.locked?
|
138
151
|
# trace "Unlocking #{@name}"
|
139
152
|
#}
|
140
153
|
each_upward { |node|
|
data/lib/rake/parallel.rb
CHANGED
@@ -1,28 +1,23 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
require 'rake/comp_tree/driver'
|
2
|
+
require 'rake/comp_tree/comp_tree'
|
5
3
|
|
6
4
|
module Rake
|
7
5
|
module TaskManager
|
8
6
|
def invoke_parallel(root_task_name) # :nodoc:
|
9
|
-
CompTree
|
7
|
+
CompTree.build do |driver|
|
10
8
|
#
|
11
9
|
# Build the computation tree from task prereqs.
|
12
10
|
#
|
13
|
-
|
11
|
+
self.parallel.tasks.each_pair { |task_name, cache|
|
14
12
|
task = self[task_name]
|
15
13
|
task_args, prereqs = cache
|
16
|
-
children_names = prereqs.map { |child|
|
17
|
-
|
18
|
-
}
|
19
|
-
driver.define(task_name.to_sym, *children_names) {
|
14
|
+
children_names = prereqs.map { |child| child.name }
|
15
|
+
driver.define(task_name, *children_names) {
|
20
16
|
task.execute(task_args)
|
21
|
-
true
|
22
17
|
}
|
23
18
|
}
|
24
19
|
|
25
|
-
root_node = driver.nodes[root_task_name
|
20
|
+
root_node = driver.nodes[root_task_name]
|
26
21
|
|
27
22
|
#
|
28
23
|
# If there were nothing to do, there would be no root node.
|
@@ -33,16 +28,16 @@ module Rake
|
|
33
28
|
#
|
34
29
|
root_node.each_downward { |node|
|
35
30
|
unless node.function
|
36
|
-
node.
|
31
|
+
node.computed = true
|
37
32
|
end
|
38
33
|
}
|
39
34
|
|
40
35
|
#
|
41
36
|
# Launch the computation.
|
42
37
|
#
|
43
|
-
driver.compute(root_node.name, num_threads)
|
38
|
+
driver.compute(root_node.name, self.num_threads)
|
44
39
|
end
|
45
|
-
|
40
|
+
end
|
46
41
|
end
|
47
42
|
end
|
48
43
|
end
|
File without changes
|
data/test/parallel.rb
CHANGED
data/test/shellcommand.rb
CHANGED
File without changes
|
data/test/single_threaded.rb
CHANGED
data/test/test_parallel.rb
CHANGED
@@ -2,9 +2,28 @@
|
|
2
2
|
require 'rbconfig'
|
3
3
|
require 'test/unit'
|
4
4
|
|
5
|
+
PARALLEL_TEST_MESSAGE = <<'EOS'
|
6
|
+
|
7
|
+
|
8
|
+
Task graph for sample parallel execution:
|
9
|
+
|
10
|
+
default
|
11
|
+
/ \
|
12
|
+
/ \
|
13
|
+
a b
|
14
|
+
/ \
|
15
|
+
/ \
|
16
|
+
x y
|
17
|
+
|
18
|
+
EOS
|
19
|
+
|
5
20
|
if Rake.application.num_threads > 1
|
6
21
|
class TestSimpleParallel < Test::Unit::TestCase
|
7
|
-
def
|
22
|
+
def setup
|
23
|
+
puts PARALLEL_TEST_MESSAGE
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_parallel
|
8
27
|
here = File.dirname(__FILE__)
|
9
28
|
rake = File.expand_path("#{here}/../bin/rake")
|
10
29
|
|
@@ -18,15 +37,17 @@ if Rake.application.num_threads > 1
|
|
18
37
|
lib
|
19
38
|
end
|
20
39
|
}.call
|
21
|
-
|
40
|
+
|
22
41
|
[
|
23
|
-
"Rakefile.simple",
|
24
|
-
"Rakefile.seq",
|
25
|
-
].each { |file|
|
42
|
+
["Rakefile.simple", true],
|
43
|
+
["Rakefile.seq", false],
|
44
|
+
].each { |file, disp|
|
26
45
|
(1..5).each { |n|
|
27
|
-
args = [rake, "--threads", n.to_s, "-f", "test/#{file}"]
|
28
|
-
|
29
|
-
|
46
|
+
args = [rake, "--threads", n.to_s, "-s", "-f", "test/#{file}"]
|
47
|
+
if disp
|
48
|
+
puts "\nvisual check: #{n} thread#{n > 1 ? 's' : ''}"
|
49
|
+
puts args.join(" ")
|
50
|
+
end
|
30
51
|
assert(ruby(*args))
|
31
52
|
}
|
32
53
|
}
|
@@ -33,14 +33,10 @@ class TestTopLevelFunctions < Test::Unit::TestCase
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_import
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
Rake.application.should_receive(:add_import).with("y").once.ordered
|
41
|
-
Rake.application.should_receive(:add_import).with("z").once.ordered
|
42
|
-
import('x', 'y', 'z')
|
43
|
-
end
|
36
|
+
Rake.application.should_receive(:add_import).with("x").once.ordered
|
37
|
+
Rake.application.should_receive(:add_import).with("y").once.ordered
|
38
|
+
Rake.application.should_receive(:add_import).with("z").once.ordered
|
39
|
+
import('x', 'y', 'z')
|
44
40
|
end
|
45
41
|
|
46
42
|
def test_when_writing
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: drake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.4.1.0
|
4
|
+
version: 0.8.4.1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James M. Lawrence
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-09 00:00:00 -04:00
|
13
13
|
default_executable: drake
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -56,6 +56,11 @@ files:
|
|
56
56
|
- lib/rake/alt_system.rb
|
57
57
|
- lib/rake/classic_namespace.rb
|
58
58
|
- lib/rake/clean.rb
|
59
|
+
- lib/rake/comp_tree/algorithm.rb
|
60
|
+
- lib/rake/comp_tree/comp_tree.rb
|
61
|
+
- lib/rake/comp_tree/driver.rb
|
62
|
+
- lib/rake/comp_tree/error.rb
|
63
|
+
- lib/rake/comp_tree/node.rb
|
59
64
|
- lib/rake/contrib/compositepublisher.rb
|
60
65
|
- lib/rake/contrib/ftptools.rb
|
61
66
|
- lib/rake/contrib/publisher.rb
|
@@ -74,11 +79,6 @@ files:
|
|
74
79
|
- lib/rake/testtask.rb
|
75
80
|
- lib/rake/win32.rb
|
76
81
|
- lib/rake.rb
|
77
|
-
- lib/rake/comp_tree/algorithm.rb
|
78
|
-
- lib/rake/comp_tree/diagnostic.rb
|
79
|
-
- lib/rake/comp_tree/driver.rb
|
80
|
-
- lib/rake/comp_tree/error.rb
|
81
|
-
- lib/rake/comp_tree/node.rb
|
82
82
|
- test/capture_stdout.rb
|
83
83
|
- test/check_expansion.rb
|
84
84
|
- test/check_no_expansion.rb
|
@@ -1,38 +0,0 @@
|
|
1
|
-
|
2
|
-
module Rake end
|
3
|
-
module Rake::CompTree
|
4
|
-
module Diagnostic
|
5
|
-
module_function
|
6
|
-
|
7
|
-
def show(desc = nil, stream = STDOUT, &block)
|
8
|
-
if desc
|
9
|
-
stream.puts(desc)
|
10
|
-
end
|
11
|
-
if block
|
12
|
-
expression = block.call
|
13
|
-
result = eval(expression, block.binding)
|
14
|
-
stream.printf("%-16s => %s\n", expression, result.inspect)
|
15
|
-
result
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
if $DEBUG
|
20
|
-
def debug
|
21
|
-
yield
|
22
|
-
end
|
23
|
-
|
24
|
-
def debugging?
|
25
|
-
true
|
26
|
-
end
|
27
|
-
|
28
|
-
def trace(desc = nil, &block)
|
29
|
-
show(desc, STDERR, &block)
|
30
|
-
end
|
31
|
-
else
|
32
|
-
def debug ; end
|
33
|
-
def debugging? ; end
|
34
|
-
def trace(*args) ; end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|