comp_tree 0.5.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGES +24 -0
  2. data/README +19 -52
  3. data/Rakefile +1 -138
  4. data/comp_tree.gemspec +33 -30
  5. data/install.rb +3 -3
  6. data/lib/comp_tree/algorithm.rb +117 -156
  7. data/lib/comp_tree/driver.rb +39 -154
  8. data/lib/comp_tree/error.rb +18 -23
  9. data/lib/comp_tree/node.rb +46 -50
  10. data/lib/comp_tree.rb +56 -0
  11. data/rakelib/jumpstart/ruby.rb +51 -0
  12. data/{contrib/quix/lib/quix → rakelib/jumpstart}/simple_installer.rb +11 -13
  13. data/test/common.rb +29 -0
  14. data/test/test_basic.rb +189 -0
  15. data/test/test_circular.rb +34 -31
  16. data/test/test_drain.rb +38 -0
  17. data/test/test_exception.rb +37 -86
  18. data/test/test_flood.rb +14 -0
  19. data/test/test_grind.rb +77 -0
  20. data/test/test_sequential.rb +21 -0
  21. metadata +45 -58
  22. data/contrib/quix/Rakefile +0 -16
  23. data/contrib/quix/install.rb +0 -3
  24. data/contrib/quix/lib/quix/builtin/dir/casefold_brackets.rb +0 -7
  25. data/contrib/quix/lib/quix/builtin/kernel/tap.rb +0 -9
  26. data/contrib/quix/lib/quix/builtin/module/include.rb +0 -21
  27. data/contrib/quix/lib/quix/builtin/module/private.rb +0 -41
  28. data/contrib/quix/lib/quix/config.rb +0 -37
  29. data/contrib/quix/lib/quix/cygwin.rb +0 -60
  30. data/contrib/quix/lib/quix/diagnostic.rb +0 -44
  31. data/contrib/quix/lib/quix/enumerable.rb +0 -33
  32. data/contrib/quix/lib/quix/fileutils.rb +0 -37
  33. data/contrib/quix/lib/quix/hash_struct.rb +0 -27
  34. data/contrib/quix/lib/quix/kernel.rb +0 -61
  35. data/contrib/quix/lib/quix/lazy_struct.rb +0 -55
  36. data/contrib/quix/lib/quix/string.rb +0 -38
  37. data/contrib/quix/lib/quix/subpackager.rb +0 -52
  38. data/contrib/quix/lib/quix/thread_local.rb +0 -32
  39. data/contrib/quix/lib/quix/vars.rb +0 -138
  40. data/contrib/quix/lib/quix.rb +0 -32
  41. data/contrib/quix/test/all.rb +0 -12
  42. data/contrib/quix/test/test_deps.rb +0 -25
  43. data/contrib/quix/test/test_include.rb +0 -47
  44. data/contrib/quix/test/test_private.rb +0 -86
  45. data/contrib/quix/test/test_root.rb +0 -19
  46. data/contrib/quix/test/test_struct.rb +0 -48
  47. data/contrib/quix/test/test_vars.rb +0 -187
  48. data/lib/comp_tree/bucket_ipc.rb +0 -151
  49. data/lib/comp_tree/diagnostic.rb +0 -44
  50. data/lib/comp_tree/misc.rb +0 -61
  51. data/lib/comp_tree/retriable_fork.rb +0 -42
  52. data/lib/comp_tree/tap.rb +0 -9
  53. data/lib/comp_tree/task_node.rb +0 -22
  54. data/test/all.rb +0 -12
  55. data/test/test_bucketipc.rb +0 -72
  56. data/test/test_comp_tree.rb +0 -364
data/test/common.rb ADDED
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
2
+
3
+ require 'test/unit'
4
+ require 'comp_tree'
5
+ require 'benchmark'
6
+
7
+ module TestCommon
8
+ if ARGV.include?("--bench")
9
+ def separator
10
+ puts
11
+ puts "-"*60
12
+ end
13
+
14
+ def bench_output(desc = nil, stream = STDOUT, &block)
15
+ if desc
16
+ stream.puts(desc)
17
+ end
18
+ if block
19
+ expression = block.call
20
+ result = eval(expression, block.binding)
21
+ stream.printf("%-16s => %s\n", expression, result.inspect)
22
+ result
23
+ end
24
+ end
25
+ else
26
+ def separator() end
27
+ def bench_output(desc = nil, stream = STDOUT, &block) end
28
+ end
29
+ end
@@ -0,0 +1,189 @@
1
+ require File.dirname(__FILE__) + "/common"
2
+
3
+ class TestBasic < Test::Unit::TestCase
4
+ def test_define
5
+ (1..20).each { |threads|
6
+ CompTree.build { |driver|
7
+ driver.define(:area, :width, :height, :offset) { |width, height, offset|
8
+ width*height - offset
9
+ }
10
+
11
+ driver.define(:width, :border) { |border|
12
+ 2 + border
13
+ }
14
+
15
+ driver.define(:height, :border) { |border|
16
+ 3 + border
17
+ }
18
+
19
+ driver.define(:border) {
20
+ 5
21
+ }
22
+
23
+ driver.define(:offset) {
24
+ 7
25
+ }
26
+
27
+ assert_equal((2 + 5)*(3 + 5) - 7, driver.compute(:area, threads))
28
+ }
29
+ }
30
+ end
31
+
32
+ def test_already_computed
33
+ [nil, false, true, 33].each { |result|
34
+ CompTree.build { |driver|
35
+ driver.define(:a) { result }
36
+ (1..3).each { |n|
37
+ assert_equal(result, driver.compute(:a, n))
38
+ }
39
+ }
40
+ }
41
+ end
42
+
43
+ def test_threads_opt
44
+ (1..20).each { |threads|
45
+ CompTree.build do |driver|
46
+ driver.define(:a) { 33 }
47
+ assert_equal(33, driver.compute(:a, :threads => threads))
48
+ end
49
+ }
50
+ end
51
+
52
+ def test_malformed
53
+ CompTree.build { |driver|
54
+ assert_raise(CompTree::ArgumentError) {
55
+ driver.define {
56
+ }
57
+ }
58
+ assert_raise(CompTree::RedefinitionError) {
59
+ driver.define(:a) {
60
+ }
61
+ driver.define(:a) {
62
+ }
63
+ }
64
+ assert_raise(CompTree::ArgumentError) {
65
+ driver.define(:b) {
66
+ }
67
+ driver.compute(:b, 0)
68
+ }
69
+ assert_raise(CompTree::ArgumentError) {
70
+ driver.define(:c) {
71
+ }
72
+ driver.compute(:c, -1)
73
+ }
74
+ }
75
+ end
76
+
77
+ def test_exception_in_compute
78
+ test_error = Class.new(RuntimeError)
79
+ CompTree.build { |driver|
80
+ driver.define(:area, :width, :height, :offset) { |width, height, offset|
81
+ width*height - offset
82
+ }
83
+
84
+ driver.define(:width, :border) { |border|
85
+ 2 + border
86
+ }
87
+
88
+ driver.define(:height, :border) { |border|
89
+ 3 + border
90
+ }
91
+
92
+ driver.define(:border) {
93
+ raise test_error
94
+ }
95
+
96
+ driver.define(:offset) {
97
+ 7
98
+ }
99
+
100
+ assert_raise(test_error) {
101
+ driver.compute(:area, 6)
102
+ }
103
+ }
104
+ end
105
+
106
+ def test_node_subclass
107
+ data = Object.new
108
+ subclass = Class.new(CompTree::Node) {
109
+ define_method :stuff do
110
+ data
111
+ end
112
+ }
113
+ CompTree.build(:node_class => subclass) { |driver|
114
+ driver.define(:a) { }
115
+ assert_equal(data, driver.nodes[:a].stuff)
116
+ }
117
+ end
118
+
119
+ def test_non_symbols
120
+ width_id = Object.new
121
+ height_id = 272727
122
+ (1..3).each { |threads|
123
+ CompTree.build { |driver|
124
+ driver.define("area", width_id, height_id, :offset) {
125
+ |width, height, offset|
126
+ width*height - offset
127
+ }
128
+
129
+ driver.define(width_id, :border) { |border|
130
+ 2 + border
131
+ }
132
+
133
+ driver.define(height_id, :border) { |border|
134
+ 3 + border
135
+ }
136
+
137
+ driver.define(:border) {
138
+ 5
139
+ }
140
+
141
+ driver.define(:offset) {
142
+ 7
143
+ }
144
+
145
+ assert_equal((2 + 5)*(3 + 5) - 7, driver.compute("area", threads))
146
+ }
147
+ }
148
+ end
149
+
150
+ def test_node_name_equality_comparison
151
+ CompTree.build { |driver|
152
+ driver.define("hello") { }
153
+ assert_raise(CompTree::RedefinitionError) {
154
+ driver.define("hello") { }
155
+ }
156
+ }
157
+ end
158
+
159
+ def test_result_variety
160
+ [true, false, nil, Object.new, 33].each { |result|
161
+ (1..20).each { |threads|
162
+ CompTree.build { |driver|
163
+ driver.define(:area, :width, :height, :offset) {
164
+ |width, height, offset|
165
+ result
166
+ }
167
+
168
+ driver.define(:width, :border) { |border|
169
+ result
170
+ }
171
+
172
+ driver.define(:height, :border) { |border|
173
+ result
174
+ }
175
+
176
+ driver.define(:border) {
177
+ result
178
+ }
179
+
180
+ driver.define(:offset) {
181
+ result
182
+ }
183
+
184
+ assert_equal(result, driver.compute(:area, threads))
185
+ }
186
+ }
187
+ }
188
+ end
189
+ end
@@ -1,36 +1,39 @@
1
- $LOAD_PATH.unshift(File.expand_path("#{File.dirname(__FILE__)}/../lib"))
1
+ require File.dirname(__FILE__) + "/common"
2
2
 
3
- require 'comp_tree'
4
- require 'test/unit'
3
+ class TestCircular < Test::Unit::TestCase
4
+ def test_circular
5
+ CompTree.build { |driver|
6
+ driver.define(:area, :width, :height, :offset) { |width, height, offset|
7
+ width*height - offset
8
+ }
9
+
10
+ driver.define(:width, :border) { |border|
11
+ 2 + border
12
+ }
13
+
14
+ driver.define(:height, :border) { |border|
15
+ 3 + border
16
+ }
17
+
18
+ driver.define(:border) {
19
+ 5
20
+ }
21
+
22
+ driver.define(:offset, :area) {
23
+ 7
24
+ }
5
25
 
6
- module CompTree
7
- class TestCircular < Test::Unit::TestCase
8
- def test_1
9
- CompTree::Driver.new { |driver|
10
- driver.define(:area, :width, :height, :offset) { |width, height, offset|
11
- width*height - offset
12
- }
13
-
14
- driver.define(:width, :border) { |border|
15
- 2 + border
16
- }
17
-
18
- driver.define(:height, :border) { |border|
19
- 3 + border
20
- }
21
-
22
- driver.define(:border) {
23
- 5
24
- }
25
-
26
- driver.define(:offset, :area) {
27
- 7
28
- }
26
+ assert_equal([:area, :offset, :area], driver.check_circular(:area))
27
+ assert_equal([:offset, :area, :offset], driver.check_circular(:offset))
28
+ }
29
+ end
29
30
 
30
- assert_raises(Error::CircularError) {
31
- driver.check_circular(:area)
32
- }
33
- }
34
- end
31
+ def test_not_circular
32
+ CompTree.build { |driver|
33
+ driver.define(:a, :b) { true }
34
+ driver.define(:b) { true }
35
+ assert_nil(driver.check_circular(:a))
36
+ assert_nil(driver.check_circular(:b))
37
+ }
35
38
  end
36
39
  end
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + "/common"
2
+
3
+ class TestDrain < Test::Unit::TestCase
4
+ include TestCommon
5
+
6
+ def drain
7
+ 500000.times { }
8
+ end
9
+
10
+ def run_drain(threads)
11
+ CompTree.build { |driver|
12
+ func = lambda { |*args|
13
+ drain
14
+ }
15
+ driver.define(:area, :width, :height, :offset, &func)
16
+ driver.define(:width, :border, &func)
17
+ driver.define(:height, :border, &func)
18
+ driver.define(:border, &func)
19
+ driver.define(:offset, &func)
20
+ bench_output "number of threads: #{threads}"
21
+ bench = Benchmark.measure { driver.compute(:area, threads) }
22
+ bench_output bench
23
+ }
24
+ end
25
+
26
+ def each_drain
27
+ (1..10).each { |threads|
28
+ yield threads
29
+ }
30
+ end
31
+
32
+ def test_drain
33
+ separator
34
+ each_drain { |threads|
35
+ run_drain(threads)
36
+ }
37
+ end
38
+ end
@@ -1,97 +1,48 @@
1
-
2
- #
3
- # Mean workaround using separate processes due to assert_raise causing
4
- # problems with threads.
5
- #
6
-
7
- require 'test/unit'
8
-
9
- module WorkaroundConfig
10
- HERE = File.dirname(__FILE__)
11
- LIB_DIR = File.expand_path("#{HERE}/../lib")
12
- QUIX_LIB_DIR = File.expand_path("#{HERE}/../contrib/quix/lib")
13
- OUTPUT_FILE = "#{HERE}/#{File.basename(__FILE__)}.output"
14
-
15
- $LOAD_PATH.unshift LIB_DIR
16
- $LOAD_PATH.unshift QUIX_LIB_DIR
17
- end
18
-
19
- require 'comp_tree'
20
- require 'quix/config'
21
-
22
- module CompTree
23
- class TestRaises < Test::Unit::TestCase
24
- include WorkaroundConfig
25
-
26
- def test_exception
27
- if RUBY_PLATFORM =~ %r!java!
28
- puts "skipping #{File.basename(__FILE__)}."
29
- else
30
- [true, false].each { |use_fork|
31
- [true, false].each { |define_all|
32
- assert(
33
- !system(
34
- ::Quix::Config.ruby_executable,
35
- "-e",
36
- code(use_fork, define_all)))
1
+ require File.dirname(__FILE__) + "/common"
2
+
3
+ class TestException < Test::Unit::TestCase
4
+ def test_exception
5
+ test_error = Class.new StandardError
6
+ [true, false].each { |define_all|
7
+ error = (
8
+ begin
9
+ CompTree.build { |driver|
10
+ driver.define(:area, :width, :height, :offset) {
11
+ |width, height, offset|
12
+ width*height - offset
13
+ }
37
14
 
38
- output = File.read(OUTPUT_FILE)
15
+ driver.define(:width, :border) { |border|
16
+ 2 + border
17
+ }
39
18
 
19
+ driver.define(:height, :border) { |border|
20
+ 3 + border
21
+ }
22
+
40
23
  if define_all
41
- assert_match(%r!CompTreeTestError!, output)
42
- else
43
- assert_match(%r!NoFunctionError!, output)
24
+ driver.define(:border) {
25
+ raise test_error
26
+ }
44
27
  end
45
28
 
46
- File.unlink(OUTPUT_FILE) # leave when exception raised above
47
- }
48
- }
49
- end
50
- end
51
-
52
- def code(use_fork, define_all)
53
- %Q(
54
- $LOAD_PATH.unshift '#{LIB_DIR}'
55
- require 'comp_tree'
56
- require 'open3'
57
-
58
- class CompTreeTestError < Exception ; end
59
-
60
- CompTree::Driver.new { |driver|
61
- driver.define(:area, :width, :height, :offset) {
62
- |width, height, offset|
63
- width*height - offset
64
- }
65
-
66
- driver.define(:width, :border) { |border|
67
- 2 + border
29
+ driver.define(:offset) {
30
+ 7
31
+ }
32
+
33
+ driver.compute(:area, 99)
68
34
  }
35
+ nil
36
+ rescue => e
37
+ e
38
+ end
39
+ )
69
40
 
70
- driver.define(:height, :border) { |border|
71
- 3 + border
72
- }
73
- ) +
74
41
  if define_all
75
- %Q(
76
- driver.define(:border) {
77
- raise CompTreeTestError
78
- }
79
- )
42
+ assert_block { error.is_a? test_error }
80
43
  else
81
- ""
82
- end +
83
- %Q(
84
- driver.define(:offset) {
85
- 7
86
- }
87
-
88
- File.open('#{OUTPUT_FILE}', "w") { |out|
89
- $stderr = out
90
- driver.compute(
91
- :area, :threads => 99, :fork => #{use_fork.inspect})
92
- }
93
- }
94
- )
95
- end
44
+ assert_block { error.is_a? CompTree::NoFunctionError }
45
+ end
46
+ }
96
47
  end
97
48
  end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + "/common"
2
+
3
+ class TestFlood < Test::Unit::TestCase
4
+ def test_thread_flood
5
+ (1..200).each { |num_threads|
6
+ CompTree.build { |driver|
7
+ noop = lambda { |*args| true }
8
+ driver.define(:a, :b, &noop)
9
+ driver.define(:b, &noop)
10
+ driver.compute(:a, num_threads)
11
+ }
12
+ }
13
+ end
14
+ end
@@ -0,0 +1,77 @@
1
+ require File.dirname(__FILE__) + "/common"
2
+
3
+ class TestGrind < Test::Unit::TestCase
4
+ include TestCommon
5
+
6
+ GENERATOR_DATA = {
7
+ :level_range => 1..4,
8
+ :children_range => 1..6,
9
+ :thread_range => 1..6,
10
+ :drain_iterations => 0,
11
+ }
12
+
13
+ ROOT = 'a'
14
+
15
+ def test_grind
16
+ run_generated_tree(GENERATOR_DATA)
17
+ end
18
+
19
+ def generate_comp_tree(num_levels, num_children, drain_iterations)
20
+ CompTree.build { |driver|
21
+ name_gen = ROOT.dup
22
+ pick_names = lambda { |*args|
23
+ (0..rand(num_children)).map {
24
+ name_gen.succ!
25
+ name_gen.dup
26
+ }
27
+ }
28
+ drain = lambda { |*args|
29
+ drain_iterations.times {
30
+ }
31
+ }
32
+ build_tree = lambda { |parent, children, level|
33
+ #trace "building #{parent} --> #{children.join(' ')}"
34
+
35
+ driver.define(parent, *children, &drain)
36
+
37
+ if level < num_levels
38
+ children.each { |child|
39
+ build_tree.call(child, pick_names.call, level + 1)
40
+ }
41
+ else
42
+ children.each { |child|
43
+ driver.define(child, &drain)
44
+ }
45
+ end
46
+ }
47
+ build_tree.call(ROOT, pick_names.call, drain_iterations)
48
+ driver
49
+ }
50
+ end
51
+
52
+ def run_generated_tree(args)
53
+ args[:level_range].each { |num_levels|
54
+ args[:children_range].each { |num_children|
55
+ separator
56
+ bench_output {%{num_levels}}
57
+ bench_output {%{num_children}}
58
+ driver = generate_comp_tree(
59
+ num_levels,
60
+ num_children,
61
+ args[:drain_iterations])
62
+ args[:thread_range].each { |threads|
63
+ bench_output {%{threads}}
64
+ 2.times {
65
+ driver.reset(ROOT)
66
+ result = nil
67
+ bench = Benchmark.measure {
68
+ result = driver.compute(ROOT, threads)
69
+ }
70
+ bench_output bench
71
+ assert_equal(result, args[:drain_iterations])
72
+ }
73
+ }
74
+ }
75
+ }
76
+ end
77
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + "/common"
2
+
3
+ class TestSequential < Test::Unit::TestCase
4
+ def test_sequential
5
+ (1..50).each { |num_threads|
6
+ [1, 2, 3, 20, 50].each { |num_nodes|
7
+ CompTree.build { |driver|
8
+ driver.define(:root) { true }
9
+ (1..num_nodes).each { |n|
10
+ if n == 0
11
+ driver.define("a#{n}".to_s, :root) { true }
12
+ else
13
+ driver.define("a#{n}".to_s, "a#{n-1}".to_s) { true }
14
+ end
15
+ }
16
+ driver.compute(:root, num_threads)
17
+ }
18
+ }
19
+ }
20
+ end
21
+ end