From 5591e7182b374fdf7b23e74554caf20aed3b0e5f Mon Sep 17 00:00:00 2001 From: quix Date: Mon, 6 Apr 2009 00:08:42 -0400 Subject: [PATCH] update comp_tree --- lib/rake/comp_tree/algorithm.rb | 52 ++++++++++++++++----------------- lib/rake/comp_tree/driver.rb | 17 +++++------ lib/rake/comp_tree/node.rb | 31 ++++++++++++++------ lib/rake/parallel.rb | 3 +- 4 files changed, 55 insertions(+), 48 deletions(-) diff --git a/lib/rake/comp_tree/algorithm.rb b/lib/rake/comp_tree/algorithm.rb index 0a89c141f..1e532652c 100644 --- a/lib/rake/comp_tree/algorithm.rb +++ b/lib/rake/comp_tree/algorithm.rb @@ -16,7 +16,7 @@ def loop_with(leave, again) def compute_multithreaded(root, num_threads) #trace "Computing #{root.name} with #{num_threads} threads" - result = nil + finished = nil tree_mutex = Mutex.new node_finished_condition = ConditionVariable.new thread_wake_condition = ConditionVariable.new @@ -36,7 +36,7 @@ def compute_multithreaded(root, num_threads) loop_with(:leave, :again) { node = tree_mutex.synchronize { #trace "Thread #{thread_index} acquired tree lock; begin search" - if result + if finished #trace "Thread #{thread_index} detected finish" num_threads_in_use -= 1 throw :leave @@ -57,7 +57,10 @@ def compute_multithreaded(root, num_threads) } #trace "Thread #{thread_index} computing node" - node_result = compute_node(node) + #debug { + # node.trace_compute + #} + node.compute #trace "Thread #{thread_index} node computed; waiting for tree lock" tree_mutex.synchronize { @@ -65,25 +68,28 @@ def compute_multithreaded(root, num_threads) #debug { # name = "#{node.name}" + ((node == root) ? " (ROOT NODE)" : "") # initial = "Thread #{thread_index} compute result for #{name}: " - # status = node_result.is_a?(Exception) ? "error" : "success" + # status = node.computed.is_a?(Exception) ? "error" : "success" # trace initial + status - # trace "Thread #{thread_index} node result: #{node_result}" + # trace "Thread #{thread_index} node result: #{node.result}" #} - node.result = node_result - + if node.computed.is_a? Exception + # + # An error occurred; we are done. + # + finished = node.computed + elsif node == root + # + # Root node was computed; we are done. + # + finished = true + end + # # remove locks for this node (shared lock and own lock) # node.unlock - if node == root or node_result.is_a? Exception - # - # Root node was computed or error occurred; we are done. - # - result = node_result - end - # # Tell the main thread that another node was computed. # @@ -105,7 +111,7 @@ def compute_multithreaded(root, num_threads) #trace "Main: waking threads" thread_wake_condition.broadcast - if result + if finished #trace "Main: detected finish." break end @@ -128,17 +134,17 @@ def compute_multithreaded(root, num_threads) } #trace "Main: computation done." - if result.is_a? Exception - raise result + if finished.is_a? Exception + raise finished else - result + root.result end end def find_node(node) # --- only called inside shared tree mutex #trace "Looking for a node, starting with #{node.name}" - if node.result + if node.computed # # already computed # @@ -162,13 +168,5 @@ def find_node(node) nil end end - - def compute_node(node) - begin - node.compute - rescue Exception => e - e - end - end end end diff --git a/lib/rake/comp_tree/driver.rb b/lib/rake/comp_tree/driver.rb index 3f25fd7af..e51f992dd 100644 --- a/lib/rake/comp_tree/driver.rb +++ b/lib/rake/comp_tree/driver.rb @@ -54,9 +54,6 @@ def initialize(opts = nil) # width*height # } # - # NOTE: You must return a non-nil value to signal the computation - # is complete. If nil is returned, the node will be recomputed. - # def define(*args, &block) parent_name = args.first children_names = args[1..-1] @@ -144,13 +141,13 @@ def compute(name, opts) raise ArgumentError, "threads is #{threads}" end - root.result or ( - if threads == 1 - root.result = root.compute_now - else - compute_multithreaded(root, threads) - end - ) + if root.computed + root.result + elsif threads == 1 + root.result = root.compute_now + else + compute_multithreaded(root, threads) + end end end end diff --git a/lib/rake/comp_tree/node.rb b/lib/rake/comp_tree/node.rb index 545745a9c..d105d1f1c 100644 --- a/lib/rake/comp_tree/node.rb +++ b/lib/rake/comp_tree/node.rb @@ -13,6 +13,7 @@ class Node attr_accessor :children #:nodoc: attr_accessor :function #:nodoc: attr_accessor :result #:nodoc: + attr_accessor :computed #:nodoc: attr_accessor :shared_lock #:nodoc: # @@ -23,6 +24,7 @@ def initialize(name) #:nodoc: @mutex = Mutex.new @children = [] @parents = [] + @function = nil reset_self end @@ -33,6 +35,7 @@ def reset_self #:nodoc: @shared_lock = 0 @children_results = nil @result = nil + @computed = nil end # @@ -81,14 +84,18 @@ def compute_now #:nodoc: # If all children have been computed, return their results; # otherwise return nil. # + # Do not assign to @children_results since own lock is not + # necessarily aquired. + # def find_children_results #:nodoc: - if @children_results - @children_results - else + @children_results or ( @children.map { |child| - child.result or return nil + unless child.computed + return nil + end + child.result } - end + ) end def children_results=(value) #:nodoc: @@ -99,7 +106,7 @@ def children_results=(value) #:nodoc: # debug { # # --- own mutex # trace "Computing #{@name}" - # raise AssertionFailedError if @result + # raise AssertionFailedError if @computed # raise AssertionFailedError unless @mutex.locked? # raise AssertionFailedError unless @children_results # } @@ -110,11 +117,17 @@ def children_results=(value) #:nodoc: # already acquired. # def compute #:nodoc: - unless defined?(@function) and @function - raise NoFunctionError, + begin + unless @function + raise NoFunctionError, "No function was defined for node '#{@name.inspect}'" + end + @result = @function.call(*@children_results) + @computed = true + rescue Exception => e + @computed = e end - @function.call(*@children_results) + @result end def try_lock #:nodoc: diff --git a/lib/rake/parallel.rb b/lib/rake/parallel.rb index f38e932d4..00ff32101 100644 --- a/lib/rake/parallel.rb +++ b/lib/rake/parallel.rb @@ -14,7 +14,6 @@ def invoke_parallel(root_task_name) # :nodoc: children_names = prereqs.map { |child| child.name } driver.define(task_name, *children_names) { task.execute(task_args) - true } } @@ -29,7 +28,7 @@ def invoke_parallel(root_task_name) # :nodoc: # root_node.each_downward { |node| unless node.function - node.result = true + node.computed = true end }