drake 0.8.4.1.0.18 → 0.8.4.1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|