drake 0.8.2.1.0.3 → 0.8.2.1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.drake +5 -0
- data/README +5 -4
- data/Rakefile.drake +3 -34
- data/lib/rake.rb +6 -4
- data/lib/rake/parallel.rb +4 -7
- metadata +2 -12
- data/lib/rake/comp_tree/algorithm.rb +0 -234
- data/lib/rake/comp_tree/bucket_ipc.rb +0 -175
- data/lib/rake/comp_tree/driver.rb +0 -291
- data/lib/rake/comp_tree/error.rb +0 -51
- data/lib/rake/comp_tree/node.rb +0 -189
- data/lib/rake/comp_tree/quix/builtin/kernel/tap.rb +0 -57
- data/lib/rake/comp_tree/quix/diagnostic.rb +0 -92
- data/lib/rake/comp_tree/quix/kernel.rb +0 -109
- data/lib/rake/comp_tree/retriable_fork.rb +0 -66
- data/lib/rake/comp_tree/task_node.rb +0 -46
@@ -1,291 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
######################################################
|
5
|
-
#
|
6
|
-
# **** DO NOT EDIT ****
|
7
|
-
#
|
8
|
-
# **** THIS IS A GENERATED FILE *****
|
9
|
-
#
|
10
|
-
######################################################
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require 'rake/comp_tree/bucket_ipc'
|
15
|
-
require 'rake/comp_tree/quix/diagnostic'
|
16
|
-
require 'rake/comp_tree/quix/kernel'
|
17
|
-
require 'rake/comp_tree/algorithm'
|
18
|
-
require 'rake/comp_tree/node'
|
19
|
-
require 'rake/comp_tree/task_node'
|
20
|
-
require 'rake/comp_tree/error'
|
21
|
-
|
22
|
-
require 'thread'
|
23
|
-
|
24
|
-
module Rake::CompTree
|
25
|
-
#
|
26
|
-
# Driver is the main interface to the computation tree. It is
|
27
|
-
# responsible for defining nodes and running computations.
|
28
|
-
#
|
29
|
-
class Driver
|
30
|
-
DEFAULTS = {
|
31
|
-
:threads => 1,
|
32
|
-
:fork => false,
|
33
|
-
:timeout => 5.0,
|
34
|
-
:wait_interval => 0.02,
|
35
|
-
}
|
36
|
-
|
37
|
-
include Quix::Diagnostic #:nodoc:
|
38
|
-
include Quix::Kernel #:nodoc:
|
39
|
-
|
40
|
-
#
|
41
|
-
# Begin a new computation tree.
|
42
|
-
#
|
43
|
-
# Options hash:
|
44
|
-
#
|
45
|
-
# <tt>:node_class</tt> -- (Class) Rake::CompTree::Node subclass from
|
46
|
-
# which nodes are created.
|
47
|
-
#
|
48
|
-
# <tt>:discard_result</tt> -- (boolean) If you are <em>not</em>
|
49
|
-
# interested in the final answer, but only in the actions which
|
50
|
-
# complete the computation, then set this to +true+. This is
|
51
|
-
# equivalent to saying <tt>:node_class => Rake::CompTree::TaskNode</tt>.
|
52
|
-
# (If you are forking processes, it is good to know that IPC is
|
53
|
-
# not needed to communicate the result.)
|
54
|
-
#
|
55
|
-
def initialize(opts = nil)
|
56
|
-
if opts and opts[:node_class] and opts[:discard_result]
|
57
|
-
raise(
|
58
|
-
Error::ArgumentError,
|
59
|
-
"#{self.class.name}.new: :discard_result and :node_class " +
|
60
|
-
"are mutually exclusive")
|
61
|
-
end
|
62
|
-
|
63
|
-
@node_class =
|
64
|
-
if opts and opts[:node_class]
|
65
|
-
opts[:node_class]
|
66
|
-
elsif opts and opts[:discard_result]
|
67
|
-
TaskNode
|
68
|
-
else
|
69
|
-
Node
|
70
|
-
end
|
71
|
-
|
72
|
-
@nodes = Hash.new
|
73
|
-
|
74
|
-
if block_given?
|
75
|
-
yield self
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
#
|
80
|
-
# Name-to-node hash.
|
81
|
-
#
|
82
|
-
attr_reader :nodes
|
83
|
-
|
84
|
-
#
|
85
|
-
# Define a computation node.
|
86
|
-
#
|
87
|
-
# There are three distinct forms of a node definition. In each of
|
88
|
-
# the following examples, a computation node named +area+ is
|
89
|
-
# defined which depends on the nodes +height+, +width+, +offset+.
|
90
|
-
#
|
91
|
-
# The method_missing form:
|
92
|
-
# driver.define_area(:width, :height, :offset) { |width, height, offset|
|
93
|
-
# width*height - offset
|
94
|
-
# }
|
95
|
-
#
|
96
|
-
# The eval form:
|
97
|
-
# driver.define_area :width, :height, :offset, %{
|
98
|
-
# width*height - offset
|
99
|
-
# }
|
100
|
-
# (Note the '%' before the brace.)
|
101
|
-
#
|
102
|
-
# The raw form:
|
103
|
-
# driver.define(:area, :width, :height, :offset) { |width, height, offset|
|
104
|
-
# width*height - offset
|
105
|
-
# }
|
106
|
-
#
|
107
|
-
def define(*args, &block)
|
108
|
-
parent_name = args.first
|
109
|
-
children_names = args[1..-1]
|
110
|
-
|
111
|
-
unless parent_name
|
112
|
-
raise Error::ArgumentError, "No name given for node"
|
113
|
-
end
|
114
|
-
|
115
|
-
#
|
116
|
-
# retrieve or create parent and children
|
117
|
-
#
|
118
|
-
parent =
|
119
|
-
if t = @nodes[parent_name]
|
120
|
-
t
|
121
|
-
else
|
122
|
-
@nodes[parent_name] = @node_class.new(parent_name)
|
123
|
-
end
|
124
|
-
|
125
|
-
if parent.function
|
126
|
-
raise Error::RedefinitionError, "Node #{parent.name} already defined."
|
127
|
-
end
|
128
|
-
parent.function = block
|
129
|
-
|
130
|
-
children = children_names.map { |child_name|
|
131
|
-
if t = @nodes[child_name]
|
132
|
-
t
|
133
|
-
else
|
134
|
-
@nodes[child_name] = @node_class.new(child_name)
|
135
|
-
end
|
136
|
-
}
|
137
|
-
|
138
|
-
#
|
139
|
-
# link
|
140
|
-
#
|
141
|
-
parent.children = children
|
142
|
-
children.each { |child|
|
143
|
-
child.parents << parent
|
144
|
-
}
|
145
|
-
end
|
146
|
-
|
147
|
-
#
|
148
|
-
# parsing/evaling helper
|
149
|
-
#
|
150
|
-
def evaling_define(*args) #:nodoc:
|
151
|
-
function_name = args[0]
|
152
|
-
function_arg_names = args[1..-2]
|
153
|
-
function_string = args.last.to_str
|
154
|
-
|
155
|
-
comma_separated = function_arg_names.map { |name|
|
156
|
-
name.to_s
|
157
|
-
}.join(",")
|
158
|
-
|
159
|
-
eval_me = %{
|
160
|
-
lambda { |#{comma_separated}|
|
161
|
-
#{function_string}
|
162
|
-
}
|
163
|
-
}
|
164
|
-
|
165
|
-
function = eval(eval_me, TOPLEVEL_BINDING)
|
166
|
-
|
167
|
-
define(function_name, *function_arg_names, &function)
|
168
|
-
end
|
169
|
-
|
170
|
-
def method_missing(symbol, *args, &block) #:nodoc:
|
171
|
-
if match = symbol.to_s.match(%r!\Adefine_(\w+)\Z!)
|
172
|
-
method_name = match.captures.first.to_sym
|
173
|
-
if block
|
174
|
-
define(method_name, *args, &block)
|
175
|
-
else
|
176
|
-
evaling_define(method_name, *args)
|
177
|
-
end
|
178
|
-
else
|
179
|
-
super(symbol, *args, &block)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
#
|
184
|
-
# Mark this node and all its children as uncomputed.
|
185
|
-
#
|
186
|
-
# Arguments:
|
187
|
-
#
|
188
|
-
# +name+ -- (Symbol) node name.
|
189
|
-
#
|
190
|
-
def reset(name)
|
191
|
-
@nodes[name].reset
|
192
|
-
end
|
193
|
-
|
194
|
-
#
|
195
|
-
# Check for a cyclic graph below the given node. Raises
|
196
|
-
# Rake::CompTree::Error::CircularError if found.
|
197
|
-
#
|
198
|
-
# Arguments:
|
199
|
-
#
|
200
|
-
# +name+ -- (Symbol) node name.
|
201
|
-
#
|
202
|
-
def check_circular(name)
|
203
|
-
helper = lambda { |root, chain|
|
204
|
-
if chain.include? root
|
205
|
-
raise Error::CircularError,
|
206
|
-
"Circular dependency detected: #{root} => #{chain.last} => #{root}"
|
207
|
-
end
|
208
|
-
@nodes[root].children.each { |child|
|
209
|
-
helper.call(child.name, chain + [root])
|
210
|
-
}
|
211
|
-
}
|
212
|
-
helper.call(name, [])
|
213
|
-
end
|
214
|
-
|
215
|
-
#
|
216
|
-
# Compute this node.
|
217
|
-
#
|
218
|
-
# Arguments:
|
219
|
-
#
|
220
|
-
# +name+ -- (Symbol) node name.
|
221
|
-
#
|
222
|
-
# Options hash:
|
223
|
-
#
|
224
|
-
# <tt>:threads</tt> -- (Integer) Number of parallel threads.
|
225
|
-
#
|
226
|
-
# <tt>:fork</tt> -- (boolean) Whether to fork each computation
|
227
|
-
# node into its own process.
|
228
|
-
#
|
229
|
-
# Defaults options are taken from Driver::DEFAULTS.
|
230
|
-
#
|
231
|
-
def compute(name, opts = nil)
|
232
|
-
#
|
233
|
-
# Undocumented options:
|
234
|
-
#
|
235
|
-
# <tt>:wait_interval</tt> -- (seconds) (Obscure) How long to
|
236
|
-
# wait after an IPC failure.
|
237
|
-
#
|
238
|
-
# <tt>:timeout</tt> -- (seconds) (Obscure) Give up after this
|
239
|
-
# period of persistent IPC failures.
|
240
|
-
#
|
241
|
-
|
242
|
-
abort_on_exception {
|
243
|
-
compute_private(name, opts || Hash.new)
|
244
|
-
}
|
245
|
-
end
|
246
|
-
|
247
|
-
private
|
248
|
-
|
249
|
-
def compute_private(name, opts_in)
|
250
|
-
opts = DEFAULTS.merge(opts_in)
|
251
|
-
root = @nodes[name]
|
252
|
-
|
253
|
-
if opts[:threads] < 1
|
254
|
-
raise Error::ArgumentError, "threads is #{opts[:threads]}"
|
255
|
-
end
|
256
|
-
|
257
|
-
if opts[:threads] == 1
|
258
|
-
root.result = root.compute_now
|
259
|
-
elsif opts[:fork] and not @node_class.discard_result?
|
260
|
-
#
|
261
|
-
# Use buckets to send results across forks.
|
262
|
-
#
|
263
|
-
result = nil
|
264
|
-
BucketIPC::Driver.new(opts[:threads], opts) { |buckets|
|
265
|
-
result =
|
266
|
-
Algorithm.compute_multithreaded(
|
267
|
-
root, opts[:threads], opts[:fork], buckets)
|
268
|
-
}
|
269
|
-
result
|
270
|
-
else
|
271
|
-
#
|
272
|
-
# Multithreaded computation without fork.
|
273
|
-
#
|
274
|
-
Algorithm.compute_multithreaded(
|
275
|
-
root, opts[:threads], opts[:fork], nil)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
######################################################
|
284
|
-
#
|
285
|
-
# **** DO NOT EDIT ****
|
286
|
-
#
|
287
|
-
# **** THIS IS A GENERATED FILE *****
|
288
|
-
#
|
289
|
-
######################################################
|
290
|
-
|
291
|
-
|
data/lib/rake/comp_tree/error.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
######################################################
|
5
|
-
#
|
6
|
-
# **** DO NOT EDIT ****
|
7
|
-
#
|
8
|
-
# **** THIS IS A GENERATED FILE *****
|
9
|
-
#
|
10
|
-
######################################################
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
module Rake::CompTree
|
15
|
-
module Error
|
16
|
-
# Base class for Rake::CompTree errors.
|
17
|
-
class Base < StandardError ; end
|
18
|
-
|
19
|
-
# Internal error inside Rake::CompTree. Please send a bug report.
|
20
|
-
class AssertionFailed < Base ; end
|
21
|
-
|
22
|
-
# Bad arguments were passed to a method.
|
23
|
-
class ArgumentError < Base ; end
|
24
|
-
|
25
|
-
#
|
26
|
-
# Attempt to redefine a Node.
|
27
|
-
#
|
28
|
-
# If you wish to only replace the function, set
|
29
|
-
# driver.nodes[name].function = some_new_lambda
|
30
|
-
#
|
31
|
-
class RedefinitionError < Base ; end
|
32
|
-
|
33
|
-
# A Cyclic graph was detected.
|
34
|
-
class CircularError < Base ; end
|
35
|
-
|
36
|
-
# No function was defined for this node.
|
37
|
-
class NoFunctionError < Base ; end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
######################################################
|
44
|
-
#
|
45
|
-
# **** DO NOT EDIT ****
|
46
|
-
#
|
47
|
-
# **** THIS IS A GENERATED FILE *****
|
48
|
-
#
|
49
|
-
######################################################
|
50
|
-
|
51
|
-
|
data/lib/rake/comp_tree/node.rb
DELETED
@@ -1,189 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
######################################################
|
5
|
-
#
|
6
|
-
# **** DO NOT EDIT ****
|
7
|
-
#
|
8
|
-
# **** THIS IS A GENERATED FILE *****
|
9
|
-
#
|
10
|
-
######################################################
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require 'rake/comp_tree/quix/diagnostic'
|
15
|
-
require 'thread'
|
16
|
-
|
17
|
-
module Rake::CompTree
|
18
|
-
#
|
19
|
-
# Base class for nodes in the computation tree.
|
20
|
-
#
|
21
|
-
class Node
|
22
|
-
include Quix::Diagnostic #:nodoc:
|
23
|
-
|
24
|
-
attr_reader :name #:nodoc:
|
25
|
-
|
26
|
-
attr_accessor :parents #:nodoc:
|
27
|
-
attr_accessor :children #:nodoc:
|
28
|
-
attr_accessor :function #:nodoc:
|
29
|
-
attr_accessor :result #:nodoc:
|
30
|
-
attr_accessor :shared_lock #:nodoc:
|
31
|
-
|
32
|
-
#
|
33
|
-
# Create a node
|
34
|
-
#
|
35
|
-
def initialize(name) #:nodoc:
|
36
|
-
@name = name
|
37
|
-
@mutex = Mutex.new
|
38
|
-
@children = []
|
39
|
-
@parents = []
|
40
|
-
reset_self
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# Reset the computation for this node.
|
45
|
-
#
|
46
|
-
def reset_self #:nodoc:
|
47
|
-
@shared_lock = 0
|
48
|
-
@children_results = nil
|
49
|
-
@result = nil
|
50
|
-
end
|
51
|
-
|
52
|
-
#
|
53
|
-
# Reset the computation for this node and all children.
|
54
|
-
#
|
55
|
-
def reset #:nodoc:
|
56
|
-
each_downward { |node|
|
57
|
-
node.reset_self
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
def each_downward(&block) #:nodoc:
|
62
|
-
block.call(self)
|
63
|
-
@children.each { |child|
|
64
|
-
child.each_downward(&block)
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
def each_upward(&block) #:nodoc:
|
69
|
-
block.call(self)
|
70
|
-
@parents.each { |parent|
|
71
|
-
parent.each_upward(&block)
|
72
|
-
}
|
73
|
-
end
|
74
|
-
|
75
|
-
def each_child #:nodoc:
|
76
|
-
@children.each { |child|
|
77
|
-
yield(child)
|
78
|
-
}
|
79
|
-
end
|
80
|
-
|
81
|
-
#
|
82
|
-
# Force computation of all children; intended for
|
83
|
-
# single-threaded mode.
|
84
|
-
#
|
85
|
-
def compute_now #:nodoc:
|
86
|
-
unless @children_results
|
87
|
-
@children_results = @children.map { |child|
|
88
|
-
child.compute_now
|
89
|
-
}
|
90
|
-
end
|
91
|
-
compute
|
92
|
-
end
|
93
|
-
|
94
|
-
#
|
95
|
-
# If all children have been computed, return their results;
|
96
|
-
# otherwise return nil.
|
97
|
-
#
|
98
|
-
def children_results #:nodoc:
|
99
|
-
if @children_results
|
100
|
-
@children_results
|
101
|
-
else
|
102
|
-
results = @children.map { |child|
|
103
|
-
if child_result = child.result
|
104
|
-
child_result
|
105
|
-
else
|
106
|
-
return nil
|
107
|
-
end
|
108
|
-
}
|
109
|
-
@children_results = results
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def trace_compute #:nodoc:
|
114
|
-
debug {
|
115
|
-
# --- own mutex
|
116
|
-
trace "Computing #{@name}"
|
117
|
-
raise Error::AssertionFailed if @result
|
118
|
-
raise Error::AssertionFailed unless @mutex.locked?
|
119
|
-
raise Error::AssertionFailed unless @children_results
|
120
|
-
}
|
121
|
-
end
|
122
|
-
|
123
|
-
#
|
124
|
-
# Compute this node; children must be computed and lock must be
|
125
|
-
# already acquired.
|
126
|
-
#
|
127
|
-
def compute #:nodoc:
|
128
|
-
unless defined?(@function) and @function
|
129
|
-
raise Error::NoFunctionError,
|
130
|
-
"No function was defined for node '#{@name.inspect}'"
|
131
|
-
end
|
132
|
-
@function.call(*@children_results)
|
133
|
-
end
|
134
|
-
|
135
|
-
def try_lock #:nodoc:
|
136
|
-
# --- shared tree mutex and own mutex
|
137
|
-
if @shared_lock == 0 and @mutex.try_lock
|
138
|
-
trace "Locking #{@name}"
|
139
|
-
each_upward { |node|
|
140
|
-
node.shared_lock += 1
|
141
|
-
trace "#{node.name} locked by #{@name}: level: #{node.shared_lock}"
|
142
|
-
}
|
143
|
-
true
|
144
|
-
else
|
145
|
-
false
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def unlock #:nodoc:
|
150
|
-
# --- shared tree mutex and own mutex
|
151
|
-
debug {
|
152
|
-
raise Error::AssertionFailed unless @mutex.locked?
|
153
|
-
trace "Unlocking #{@name}"
|
154
|
-
}
|
155
|
-
each_upward { |node|
|
156
|
-
node.shared_lock -= 1
|
157
|
-
debug {
|
158
|
-
if node.shared_lock == 0
|
159
|
-
trace "#{node.name} unlocked by #{@name}"
|
160
|
-
end
|
161
|
-
}
|
162
|
-
}
|
163
|
-
@mutex.unlock
|
164
|
-
end
|
165
|
-
|
166
|
-
class << self
|
167
|
-
#
|
168
|
-
# Throw away the computation result?
|
169
|
-
#
|
170
|
-
# This Node base class always returns false.
|
171
|
-
#
|
172
|
-
def discard_result?
|
173
|
-
false
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
######################################################
|
182
|
-
#
|
183
|
-
# **** DO NOT EDIT ****
|
184
|
-
#
|
185
|
-
# **** THIS IS A GENERATED FILE *****
|
186
|
-
#
|
187
|
-
######################################################
|
188
|
-
|
189
|
-
|