tiamat 0.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.
Files changed (43) hide show
  1. data/CHANGES.rdoc +7 -0
  2. data/MANIFEST +42 -0
  3. data/README.rdoc +194 -0
  4. data/Rakefile +19 -0
  5. data/bin/tiamat-server +31 -0
  6. data/devel/jumpstart.rb +987 -0
  7. data/install.rb +2 -0
  8. data/lib/tiamat.rb +43 -0
  9. data/lib/tiamat/autoconfig.rb +8 -0
  10. data/lib/tiamat/child_server.rb +21 -0
  11. data/lib/tiamat/config/ruby_parser.rb +6 -0
  12. data/lib/tiamat/connector.rb +23 -0
  13. data/lib/tiamat/error.rb +24 -0
  14. data/lib/tiamat/farm.rb +32 -0
  15. data/lib/tiamat/local_child_farm.rb +23 -0
  16. data/lib/tiamat/local_child_server.rb +25 -0
  17. data/lib/tiamat/local_child_worker.rb +11 -0
  18. data/lib/tiamat/remote_farm.rb +11 -0
  19. data/lib/tiamat/remote_worker.rb +10 -0
  20. data/lib/tiamat/server.rb +42 -0
  21. data/lib/tiamat/tiamat.rb +49 -0
  22. data/lib/tiamat/tiamat_server.rb +48 -0
  23. data/lib/tiamat/util.rb +37 -0
  24. data/lib/tiamat/version.rb +4 -0
  25. data/lib/tiamat/worker.rb +61 -0
  26. data/spec/connector_spec.rb +11 -0
  27. data/spec/drb_connection_spec.rb +18 -0
  28. data/spec/local_child_farm_spec.rb +29 -0
  29. data/spec/local_child_server_path_spec.rb +37 -0
  30. data/spec/local_child_server_spec.rb +24 -0
  31. data/spec/local_child_worker_spec.rb +140 -0
  32. data/spec/pure_spec.rb +59 -0
  33. data/spec/readme_spec.rb +29 -0
  34. data/spec/remote_farm_spec.rb +36 -0
  35. data/spec/remote_worker_spec.rb +59 -0
  36. data/spec/server_spec.rb +48 -0
  37. data/spec/tiamat_open_local_spec.rb +77 -0
  38. data/spec/tiamat_open_remote_spec.rb +67 -0
  39. data/spec/tiamat_server_spec.rb +51 -0
  40. data/spec/tiamat_spec_base.rb +36 -0
  41. data/spec/util_spec.rb +29 -0
  42. data/spec/worker_spec.rb +19 -0
  43. metadata +209 -0
@@ -0,0 +1,4 @@
1
+
2
+ module Tiamat
3
+ VERSION = "0.1.0"
4
+ end
@@ -0,0 +1,61 @@
1
+
2
+ module Tiamat
3
+ class Worker
4
+ def define_function_begin(pure_module, num_parallel)
5
+ end
6
+
7
+ def define_function(spec)
8
+ lambda { |*args|
9
+ self.class.farm.lend_server { |server|
10
+ server.evaluate_function(spec, *args)
11
+ }
12
+ }
13
+ end
14
+
15
+ def define_function_end
16
+ end
17
+
18
+ def num_parallel
19
+ self.class.num_parallel
20
+ end
21
+
22
+ class << self
23
+ attr_reader :farm
24
+
25
+ def open(farm)
26
+ unless closed?
27
+ raise AlreadyOpenError.new(self)
28
+ end
29
+ @farm = farm
30
+ if block_given?
31
+ previous_worker = Pure.worker
32
+ Pure.worker = self
33
+ begin
34
+ yield
35
+ ensure
36
+ Pure.worker = previous_worker
37
+ close
38
+ end
39
+ end
40
+ end
41
+
42
+ def close
43
+ unless closed?
44
+ @farm.close
45
+ @farm = nil
46
+ end
47
+ end
48
+
49
+ def closed?
50
+ not defined?(@farm) or @farm.nil?
51
+ end
52
+
53
+ def num_parallel
54
+ @farm.num_servers
55
+ end
56
+
57
+ def num_parallel=(value)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe Tiamat::Connector do
4
+ it "should raise for nonexistent server" do
5
+ lambda {
6
+ Tiamat::Connector.connect(0.1, 0.5) {
7
+ DRbObject.new_with_uri("druby://localhost:9999").foo
8
+ }
9
+ }.should raise_error(DRb::DRbConnError)
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe "drb connection" do
4
+ before :all do
5
+ @uri = "druby://localhost:22334"
6
+ @server = Tiamat::LocalChildServer.new(@uri, *Tiamat.compiler.reverse)
7
+ end
8
+
9
+ after :all do
10
+ @server.close
11
+ end
12
+
13
+ it "should be creatable" do
14
+ @server.instance_eval do
15
+ @drb_object.ping
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe Tiamat::LocalChildFarm do
4
+ before :all do
5
+ @farm = Tiamat::LocalChildFarm.new(4, *Tiamat.compiler.reverse)
6
+ end
7
+
8
+ after :all do
9
+ @farm.close
10
+ end
11
+
12
+ it "should provide local servers" do
13
+ mod = pure(Pure::Parser::RubyParser) do
14
+ def f
15
+ 33 + 44
16
+ end
17
+ end
18
+ spec = Pure::ExtractedFunctions[Pure::Parser::RubyParser][mod][:f]
19
+
20
+ 20.times {
21
+ @farm.lend_server { |server_a|
22
+ @farm.lend_server { |server_b|
23
+ server_a.evaluate_function(spec).should eql(77)
24
+ server_b.evaluate_function(spec).should eql(77)
25
+ }
26
+ }
27
+ }
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe "Tiamat::LocalChildServer launch" do
4
+ before :all do
5
+ require 'fileutils'
6
+ @dummy_server = File.expand_path(
7
+ File.dirname(__FILE__) +
8
+ "/data/" +
9
+ Tiamat::LocalChildServer.server_basename
10
+ )
11
+ FileUtils.mkdir_p(File.dirname(@dummy_server))
12
+ FileUtils.touch(@dummy_server)
13
+ end
14
+
15
+ after :all do
16
+ FileUtils.rm_r(File.dirname(@dummy_server))
17
+ end
18
+
19
+ it "should prefer #{Tiamat::LocalChildServer.server_basename} in path" do
20
+ new_path = (
21
+ ENV["PATH"].
22
+ split(File::PATH_SEPARATOR).
23
+ unshift(File.dirname(@dummy_server))
24
+ ).join(File::PATH_SEPARATOR)
25
+
26
+ fallback = File.expand_path(
27
+ File.dirname(__FILE__) +
28
+ "/../bin/" +
29
+ Tiamat::LocalChildServer.server_basename
30
+ )
31
+ Tiamat::LocalChildServer.server_path.should eql(fallback)
32
+ TiamatSpecBase.with_env("PATH" => new_path) {
33
+ Tiamat::LocalChildServer.server_path.should eql(@dummy_server)
34
+ }
35
+ Tiamat::LocalChildServer.server_path.should eql(fallback)
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe Tiamat::LocalChildServer do
4
+ before :all do
5
+ @server = Tiamat::LocalChildServer.new(
6
+ "druby://localhost:27272", *Tiamat.compiler.reverse
7
+ )
8
+ end
9
+
10
+ after :all do
11
+ @server.close
12
+ end
13
+
14
+ it "should evaluate a pure function spec" do
15
+ mod = pure(Pure::Parser::RubyParser) do
16
+ def f
17
+ 33 + 44
18
+ end
19
+ end
20
+ spec = Pure::ExtractedFunctions[Pure::Parser::RubyParser][mod][:f]
21
+
22
+ @server.evaluate_function(spec).should == 77
23
+ end
24
+ end
@@ -0,0 +1,140 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ require 'benchmark'
4
+
5
+ describe Tiamat::LocalChildWorker do
6
+ before :all do
7
+ Tiamat::LocalChildWorker.open(2, *Tiamat.compiler.reverse)
8
+ end
9
+
10
+ after :all do
11
+ Tiamat::LocalChildWorker.close
12
+ end
13
+
14
+ it "should evaluate a pure function with no args" do
15
+ result = pure do
16
+ def f
17
+ 11 + 22
18
+ end
19
+ end.compute(Tiamat::LocalChildWorker)
20
+
21
+ result.f.should == 33
22
+ end
23
+
24
+ it "should evaluate a pure function with args" do
25
+ mod = pure do
26
+ def f(x, y)
27
+ x + y
28
+ end
29
+ def x
30
+ 33
31
+ end
32
+ def y
33
+ 44
34
+ end
35
+ end.compute(Tiamat::LocalChildWorker).f.should == 77
36
+ end
37
+
38
+ it "should handle `fun' definitions with no args" do
39
+ pure do
40
+ fun :f do
41
+ 11 + 22
42
+ end
43
+ end.compute(Tiamat::LocalChildWorker).f.should == 33
44
+ end
45
+
46
+ it "should handle `fun' definitions with args" do
47
+ pure do
48
+ fun :f => [:x, :y] do |u, v|
49
+ u*v
50
+ end
51
+
52
+ fun :x do
53
+ 4
54
+ end
55
+
56
+ def y
57
+ 5
58
+ end
59
+ end.compute(Tiamat::LocalChildWorker).f.should == 20
60
+ end
61
+
62
+ it "should be around 2x faster with 2 servers" do
63
+ mod = pure do
64
+ def total(left, right)
65
+ left + right
66
+ end
67
+
68
+ def left
69
+ (1..250_000).inject(0) { |acc, n| acc + n }
70
+ end
71
+
72
+ def right
73
+ (1..250_000).inject(0) { |acc, n| acc + n }
74
+ end
75
+ end
76
+
77
+ default_result = nil
78
+ default_time = mod.compute(2) { |result|
79
+ Benchmark.measure {
80
+ default_result = result.total
81
+ }.real
82
+ }
83
+
84
+ tiamat_result = nil
85
+ tiamat_time = mod.compute(Tiamat::LocalChildWorker) { |result|
86
+ Benchmark.measure {
87
+ tiamat_result = result.total
88
+ }.real
89
+ }
90
+
91
+ expected = 250_000*(250_000 + 1)
92
+ default_result.should eql(expected)
93
+ tiamat_result.should eql(expected)
94
+
95
+ # jruby is slow
96
+ epsilon = 0.65 + (RUBY_PLATFORM == "java" ? 1.0 : 0)
97
+ if ARGV.include? "--bench"
98
+ puts
99
+ puts "-----------"
100
+ puts "tiamat #{tiamat_time}"
101
+ puts "default #{default_time}"
102
+ puts
103
+ puts "ratio #{tiamat_time/default_time}"
104
+ puts "-----------"
105
+ end
106
+ end
107
+
108
+ it "should propagate exceptions from root function" do
109
+ mod = pure do
110
+ def f
111
+ raise "zz"
112
+ end
113
+ end
114
+ result = mod.compute(4)
115
+ lambda {
116
+ result.f
117
+ }.should raise_error(RuntimeError, "zz")
118
+ end
119
+
120
+ it "should propagate exceptions from child functions" do
121
+ mod = pure do
122
+ def f(x)
123
+ 33
124
+ end
125
+
126
+ def x(y)
127
+ 44
128
+ end
129
+
130
+ def y
131
+ raise "foo"
132
+ end
133
+ end
134
+ result = mod.compute(4)
135
+ lambda {
136
+ result.f
137
+ }.should raise_error(RuntimeError, "foo")
138
+ end
139
+ end
140
+
data/spec/pure_spec.rb ADDED
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe Pure do
4
+ before :all do
5
+ border = pure do
6
+ def border
7
+ 2
8
+ end
9
+ end
10
+
11
+ @geometry = pure do
12
+ include border
13
+
14
+ def area(width, height)
15
+ width*height
16
+ end
17
+
18
+ def width(border)
19
+ 7 + border
20
+ end
21
+
22
+ def height(border)
23
+ 5 + border
24
+ end
25
+ end
26
+ end
27
+
28
+ it "should use the custom worker assigned to Pure.worker" do
29
+ expected = {
30
+ :area => [:width, :height],
31
+ :width => [:border],
32
+ :height => [:border],
33
+ :border => [],
34
+ }
35
+
36
+ actual = Hash.new
37
+
38
+ worker = Class.new do
39
+ def num_parallel
40
+ 2
41
+ end
42
+
43
+ def define_function_begin(*args)
44
+ end
45
+
46
+ def define_function_end(*args)
47
+ end
48
+
49
+ define_method :define_function do |spec|
50
+ lambda { |*a|
51
+ actual[spec[:name]] = spec[:args]
52
+ }
53
+ end
54
+ end
55
+
56
+ @geometry.compute(worker).area
57
+ actual.should == expected
58
+ end
59
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ require "jumpstart"
4
+
5
+ readme = "README.rdoc"
6
+
7
+ Jumpstart.doc_to_spec(readme, "Synopsis") {
8
+ |expected_str, actual_str, index|
9
+
10
+ expected, actual = [expected_str, actual_str].map { |expr|
11
+ expr.should match(%r!\A\d+\.\d+\n\d+\.\d+\Z!)
12
+ expr.split.map { |s| s.to_f }
13
+ }.map { |pair|
14
+ {
15
+ :one_cpu => pair[0],
16
+ :two_cpu => pair[1],
17
+ }
18
+ }
19
+
20
+ [expected, actual].each { |result|
21
+ epsilon = 0.15 + TiamatSpecBase.slow_platform_epsilon
22
+ (result[:two_cpu]/result[:one_cpu]).should be_close(0.5, epsilon)
23
+ }
24
+ }
25
+
26
+ Jumpstart.doc_to_spec(readme, "Adding +require+ Paths to Local Servers")
27
+
28
+ Jumpstart.doc_to_spec(readme, "About DRbConnError")
29
+
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/tiamat_spec_base'
2
+
3
+ describe Tiamat::RemoteFarm do
4
+ before :all do
5
+ uris = (47055..47060).map { |n|
6
+ "druby://localhost:#{n}"
7
+ }
8
+ @servers = uris.map { |uri|
9
+ Tiamat::LocalChildServer.new(uri, *Tiamat.compiler.reverse)
10
+ }
11
+ @farm = Tiamat::RemoteFarm.new(*uris)
12
+ Tiamat::Worker.open(@farm)
13
+ end
14
+
15
+ after :all do
16
+ Tiamat::Worker.close
17
+ @farm.close
18
+ @servers.each { |s| s.close }
19
+ end
20
+
21
+ it "should be useable by a worker" do
22
+ pure(Pure::Parser::RubyParser) do
23
+ def f(x, y)
24
+ x + y
25
+ end
26
+
27
+ def x
28
+ 33
29
+ end
30
+
31
+ def y
32
+ 44
33
+ end
34
+ end.compute(Tiamat::Worker).f.should == 77
35
+ end
36
+ end