tiamat 0.1.0

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