Skip to content

Commit 1238a28

Browse files
committed
Moved actor stress test from spec to script in examples.
1 parent 1447a38 commit 1238a28

File tree

2 files changed

+154
-62
lines changed

2 files changed

+154
-62
lines changed

examples/actor_stress_test.rb

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/env ruby
2+
3+
$: << File.expand_path('../../lib', __FILE__)
4+
5+
require 'benchmark'
6+
require 'optparse'
7+
require 'thread'
8+
require 'rspec/expectations'
9+
10+
require 'concurrent/actor'
11+
12+
class ActorStressTester
13+
include ::RSpec::Matchers
14+
15+
TESTS_PER_RUN = 5
16+
THREADS_PER_TEST = 10
17+
LOOPS_PER_THREAD = 25
18+
19+
class Ping < Concurrent::Actor::Context
20+
def initialize(queue)
21+
@queue = queue
22+
end
23+
24+
def on_message(message)
25+
case message
26+
when :child
27+
Concurrent::Actor::Utils::AdHoc.spawn(:pong, @queue) do |queue|
28+
-> m { queue << m }
29+
end
30+
else
31+
@queue << message
32+
message
33+
end
34+
end
35+
end
36+
37+
def initialize(opts = {})
38+
@tests = opts.fetch(:tests, TESTS_PER_RUN)
39+
@threads = opts.fetch(:threads, THREADS_PER_TEST)
40+
@loops = opts.fetch(:loops, LOOPS_PER_THREAD)
41+
end
42+
43+
def run
44+
plural = ->(number){ number == 1 ? '' : 's' }
45+
46+
puts "Running #{@tests} test#{plural.call(@tests)} " +
47+
"with #{@threads} thread#{plural.call(@threads)} each " +
48+
"and #{@loops} loop#{plural.call(@loops)} per thread..."
49+
50+
Benchmark.bm do |bm|
51+
@tests.times do
52+
bm.report do
53+
test(@threads, @loops)
54+
end
55+
end
56+
end
57+
end
58+
59+
def test(threads, loops)
60+
(1..threads).collect do
61+
Thread.new do
62+
loops.times do
63+
64+
queue = Queue.new
65+
actor = Ping.spawn(:ping, queue)
66+
67+
core = Concurrent::Actor.root.send(:core)
68+
children = core.instance_variable_get(:@children)
69+
expect(children).to include(actor)
70+
71+
actor << 'a' << 1
72+
expect(queue.pop).to eq 'a'
73+
expect(actor.ask(2).value).to eq 2
74+
75+
expect(actor.parent).to eq Concurrent::Actor.root
76+
expect(Concurrent::Actor.root.path).to eq '/'
77+
expect(actor.path).to eq '/ping'
78+
79+
child = actor.ask(:child).value
80+
expect(child.path).to eq '/ping/pong'
81+
82+
queue.clear
83+
child.ask(3)
84+
expect(queue.pop).to eq 3
85+
86+
actor << :terminate!
87+
expect(actor.ask(:blow_up).wait).to be_rejected
88+
terminate_actors(actor, child)
89+
end
90+
end
91+
end.each(&:join)
92+
end
93+
94+
def terminate_actors(*actors)
95+
actors.each do |actor|
96+
unless actor.ask!(:terminated?)
97+
actor.ask!(:terminate!)
98+
end
99+
end
100+
end
101+
end
102+
103+
# def trace!
104+
# set_trace_func proc { |event, file, line, id, binding, classname|
105+
# # thread = eval('Thread.current', binding).object_id.to_s(16)
106+
# printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line
107+
# }
108+
# yield
109+
# ensure
110+
# set_trace_func nil
111+
# end
112+
113+
if $0 == __FILE__
114+
115+
options = {}
116+
117+
OptionParser.new do |opts|
118+
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
119+
120+
opts.on("--tests=TESTS", "Number of tests per run") do |value|
121+
options[:tests] = value.to_i
122+
end
123+
124+
opts.on("--threads=THREADS", "Number of threads per test") do |value|
125+
options[:threads] = value.to_i
126+
end
127+
128+
opts.on("--loops=LOOPS", "Number of loops per thread") do |value|
129+
options[:loops] = value.to_i
130+
end
131+
132+
opts.on("-h", "--help", "Prints this help") do
133+
puts opts
134+
exit
135+
end
136+
end.parse!
137+
138+
ActorStressTester.new(options).run
139+
end

spec/concurrent/actor_spec.rb

Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -43,57 +43,10 @@ def on_message(message)
4343
end
4444
end
4545

46-
# def trace!
47-
# set_trace_func proc { |event, file, line, id, binding, classname|
48-
# # thread = eval('Thread.current', binding).object_id.to_s(16)
49-
# printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line
50-
# }
51-
# yield
52-
# ensure
53-
# set_trace_func nil
54-
# end
55-
5646
it 'forbids Immediate executor' do
5747
expect { Utils::AdHoc.spawn name: 'test', executor: ImmediateExecutor.new }.to raise_error
5848
end
5949

60-
#describe 'stress test' do
61-
#1.times do |i|
62-
#it format('run %3d', i) do
63-
## puts format('run %3d', i)
64-
#Array.new(10).map do
65-
#Thread.new do
66-
#10.times do
67-
## trace! do
68-
#queue = Queue.new
69-
#actor = Ping.spawn :ping, queue
70-
71-
## when spawn returns children are set
72-
#expect(Concurrent::Actor.root.send(:core).instance_variable_get(:@children)).to include(actor)
73-
74-
#actor << 'a' << 1
75-
#expect(queue.pop).to eq 'a'
76-
#expect(actor.ask(2).value).to eq 2
77-
78-
#expect(actor.parent).to eq Concurrent::Actor.root
79-
#expect(Concurrent::Actor.root.path).to eq '/'
80-
#expect(actor.path).to eq '/ping'
81-
#child = actor.ask(:child).value
82-
#expect(child.path).to eq '/ping/pong'
83-
#queue.clear
84-
#child.ask(3)
85-
#expect(queue.pop).to eq 3
86-
87-
#actor << :terminate!
88-
#expect(actor.ask(:blow_up).wait).to be_rejected
89-
#terminate_actors actor, child
90-
#end
91-
#end
92-
#end.each(&:join)
93-
#end
94-
#end
95-
#end
96-
9750
describe 'spawning' do
9851
describe 'Actor#spawn' do
9952
behaviour = -> v { -> _ { v } }
@@ -292,7 +245,7 @@ def on_message(message)
292245

293246
test = AdHoc.spawn name: :tester, behaviour_definition: resuming_behaviour do
294247
actor = AdHoc.spawn name: :pausing,
295-
behaviour_definition: Behaviour.restarting_behaviour_definition do
248+
behaviour_definition: Behaviour.restarting_behaviour_definition do
296249
queue << :init
297250
-> m { m == :add ? 1 : pass }
298251
end
@@ -314,22 +267,22 @@ def on_message(message)
314267
terminate_actors test
315268

316269
test = AdHoc.spawn name: :tester,
317-
behaviour_definition: Behaviour.restarting_behaviour_definition do
270+
behaviour_definition: Behaviour.restarting_behaviour_definition do
318271
actor = AdHoc.spawn name: :pausing,
319-
supervise: true,
320-
behaviour_definition: Behaviour.restarting_behaviour_definition do
321-
queue << :init
322-
-> m { m == :object_id ? self.object_id : pass }
323-
end
272+
supervise: true,
273+
behaviour_definition: Behaviour.restarting_behaviour_definition do
274+
queue << :init
275+
-> m { m == :object_id ? self.object_id : pass }
276+
end
324277

325-
queue << actor.ask!(:supervisor)
326-
queue << actor.ask!(:object_id)
327-
actor << nil
328-
queue << actor.ask(:object_id)
278+
queue << actor.ask!(:supervisor)
279+
queue << actor.ask!(:object_id)
280+
actor << nil
281+
queue << actor.ask(:object_id)
329282

330-
-> m do
331-
queue << m
332-
end
283+
-> m do
284+
queue << m
285+
end
333286
end
334287

335288
expect(queue.pop).to eq :init
@@ -352,7 +305,7 @@ def on_message(message)
352305

353306
test = AdHoc.spawn name: :tester, behaviour_definition: resuming_behaviour do
354307
actor = AdHoc.spawn name: :pausing,
355-
behaviour_definition: Behaviour.restarting_behaviour_definition do
308+
behaviour_definition: Behaviour.restarting_behaviour_definition do
356309
queue << :init
357310
-> m { m == :add ? 1 : pass }
358311
end

0 commit comments

Comments
 (0)