atomic 0.0.6-java → 0.0.7-java
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.
- data/atomic.gemspec +1 -1
- data/examples/bench_atomic_1.rb +138 -0
- data/examples/graph_atomic_bench.rb +68 -0
- data/lib/atomic_reference.jar +0 -0
- metadata +4 -3
- data/README.txt +0 -33
data/atomic.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{atomic}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.7"
|
6
6
|
s.authors = ["Charles Oliver Nutter", "MenTaLguY"]
|
7
7
|
s.date = Time.now.strftime('%Y-%m-%d')
|
8
8
|
s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls"
|
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'thread'
|
7
|
+
require 'benchmark'
|
8
|
+
|
9
|
+
require 'atomic'
|
10
|
+
|
11
|
+
Thread.abort_on_exception = true
|
12
|
+
|
13
|
+
$conf = {
|
14
|
+
:lock => "atomic",
|
15
|
+
:num_threads => 100,
|
16
|
+
:count => 100_000,
|
17
|
+
:count_per_thread => nil,
|
18
|
+
:slow => nil,
|
19
|
+
}
|
20
|
+
|
21
|
+
OptionParser.new do |opts|
|
22
|
+
opts.on("-c", "--count NUM") do |n|
|
23
|
+
$conf[:count] = n.to_i
|
24
|
+
end
|
25
|
+
opts.on("-p", "--count-per-thread") do |n|
|
26
|
+
$conf[:count_per_thread] = n.to_i
|
27
|
+
end
|
28
|
+
opts.on("-t", "--num-threads NUM") do |n|
|
29
|
+
$conf[:num_threads] = n.to_i
|
30
|
+
end
|
31
|
+
opts.on("-s", "--slow NUM") do |n|
|
32
|
+
$conf[:slow] = n.to_i
|
33
|
+
end
|
34
|
+
opts.on("-l", "--lock atomic|mutex") do |x|
|
35
|
+
$conf[:lock] = x
|
36
|
+
end
|
37
|
+
opts.on("-h", "--help"){ puts opts; exit }
|
38
|
+
end.parse!(ARGV)
|
39
|
+
|
40
|
+
unless $conf[:count_per_thread]
|
41
|
+
$conf[:count_per_thread] = $conf[:count] / $conf[:num_threads]
|
42
|
+
end
|
43
|
+
$conf.delete(:count)
|
44
|
+
|
45
|
+
if $conf[:slow].to_i > 0
|
46
|
+
require 'digest/md5'
|
47
|
+
def slow_down
|
48
|
+
$conf[:slow].times do |i|
|
49
|
+
Digest::MD5.hexdigest(i.to_s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ret = []
|
54
|
+
10.times do
|
55
|
+
m = Benchmark.measure{ slow_down }
|
56
|
+
ret << m.real
|
57
|
+
end
|
58
|
+
|
59
|
+
$conf[:slow_time] = [ret.min, ret.max]
|
60
|
+
else
|
61
|
+
def slow_down; end
|
62
|
+
end
|
63
|
+
|
64
|
+
$stderr.puts $conf.inspect
|
65
|
+
|
66
|
+
def para_prepare(&block)
|
67
|
+
num_threads = $conf[:num_threads]
|
68
|
+
count = $conf[:count_per_thread]
|
69
|
+
|
70
|
+
if num_threads % 2 > 0
|
71
|
+
raise ArgumentError, "num_threads must be a multiple of two"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Keep those threads together
|
75
|
+
tg = ThreadGroup.new
|
76
|
+
|
77
|
+
num_threads.times do |i|
|
78
|
+
diff = (i % 2 == 0) ? 1 : -1
|
79
|
+
|
80
|
+
t = Thread.new do
|
81
|
+
nil until $go
|
82
|
+
count.times do
|
83
|
+
yield diff
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
tg.add(t)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Make sure all threads are started
|
91
|
+
while tg.list.find{|t| t.status != "run"}
|
92
|
+
Thread.pass
|
93
|
+
end
|
94
|
+
|
95
|
+
# For good measure
|
96
|
+
GC.start
|
97
|
+
|
98
|
+
$go = false
|
99
|
+
|
100
|
+
tg
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
$tg = nil
|
106
|
+
if $conf[:lock] == "atomic"
|
107
|
+
$atom = Atomic.new(0)
|
108
|
+
$tg = para_prepare do |diff|
|
109
|
+
$atom.update do |x|
|
110
|
+
slow_down
|
111
|
+
x + diff
|
112
|
+
end
|
113
|
+
end
|
114
|
+
else
|
115
|
+
$lock = Mutex.new
|
116
|
+
$value = 0
|
117
|
+
$tg = para_prepare do |diff|
|
118
|
+
$lock.synchronize do
|
119
|
+
slow_down
|
120
|
+
$value += diff
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
# Run !
|
127
|
+
#
|
128
|
+
# NOTE: It seems to me that this measurement method
|
129
|
+
# is sensible to how the system dispatches his resources.
|
130
|
+
#
|
131
|
+
# More precise caluclation could be done using
|
132
|
+
# getrusage's times
|
133
|
+
ret = Benchmark.measure do
|
134
|
+
$go = true
|
135
|
+
$tg.list.each{|t| t.join}
|
136
|
+
$go = false
|
137
|
+
end
|
138
|
+
puts ret.real
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
conf = {
|
5
|
+
:vary => "threads",
|
6
|
+
:lock => "atomic"
|
7
|
+
}
|
8
|
+
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.on("-l", "--lock atomic|mutex") do |l|
|
11
|
+
conf[:lock] = l
|
12
|
+
end
|
13
|
+
opts.on("-v", "--vary threads|speed") do |v|
|
14
|
+
conf[:vary] = v
|
15
|
+
end
|
16
|
+
opts.on("-h", "--help"){ puts opts; exit }
|
17
|
+
end.parse!(ARGV)
|
18
|
+
|
19
|
+
result = File.open("results_#{conf[:lock]}_#{conf[:vary]}.csv", "w")
|
20
|
+
|
21
|
+
|
22
|
+
if conf[:vary] == "threads"
|
23
|
+
# Vary the number of concurrent threads that update the value.
|
24
|
+
#
|
25
|
+
# There is a total count of 1mio updates that is distributed
|
26
|
+
# between the number of threads.
|
27
|
+
#
|
28
|
+
# A pair number of threads is used so that even add and odd substract 1.
|
29
|
+
# This avoid creating instances for Bignum since the number should
|
30
|
+
# stay in the Fixnum range.
|
31
|
+
#
|
32
|
+
(1..100).each do |i|
|
33
|
+
i = i * 2
|
34
|
+
|
35
|
+
ret = []
|
36
|
+
10.times do
|
37
|
+
ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -t #{i}`.to_f
|
38
|
+
end
|
39
|
+
|
40
|
+
line = ([i] + ret).join(', ')
|
41
|
+
|
42
|
+
puts line
|
43
|
+
result.puts line
|
44
|
+
end
|
45
|
+
elsif conf[:vary] == "speed"
|
46
|
+
# Varies the execution time of the update block
|
47
|
+
# by using long calulation (MD5)
|
48
|
+
#
|
49
|
+
# NOTE: Thread.pass and sleep() are not usable by the atomic
|
50
|
+
# lock. It needs to run the whole block without hitting
|
51
|
+
# another atomic update otherwise it has to retry
|
52
|
+
#
|
53
|
+
# The expected result is that the atomic lock's performance
|
54
|
+
# will hit a certain threshold where it will be worse than mutexes.
|
55
|
+
#
|
56
|
+
(1..30).each do |i|
|
57
|
+
|
58
|
+
ret = []
|
59
|
+
10.times do
|
60
|
+
ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -s #{i}`.to_f
|
61
|
+
end
|
62
|
+
|
63
|
+
line = ([i] + ret).join(', ')
|
64
|
+
|
65
|
+
puts line
|
66
|
+
result.puts line
|
67
|
+
end
|
68
|
+
end
|
data/lib/atomic_reference.jar
CHANGED
Binary file
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: atomic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.7
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- Charles Oliver Nutter
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-
|
14
|
+
date: 2011-11-28 00:00:00 Z
|
15
15
|
dependencies: []
|
16
16
|
|
17
17
|
description: An atomic reference implementation for JRuby and green or GIL-threaded impls
|
@@ -29,8 +29,9 @@ files:
|
|
29
29
|
- lib/atomic_reference.jar
|
30
30
|
- examples/atomic_example.rb
|
31
31
|
- examples/bench_atomic.rb
|
32
|
+
- examples/bench_atomic_1.rb
|
33
|
+
- examples/graph_atomic_bench.rb
|
32
34
|
- test/test_atomic.rb
|
33
|
-
- README.txt
|
34
35
|
- atomic.gemspec
|
35
36
|
- Rakefile
|
36
37
|
homepage: http://github.com/headius/ruby-atomic
|
data/README.txt
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
atomic: An atomic reference implementation for JRuby and green or GIL-threaded
|
2
|
-
Ruby implementations (MRI 1.8/1.9, Rubinius)
|
3
|
-
|
4
|
-
== Summary ==
|
5
|
-
|
6
|
-
This library provides:
|
7
|
-
|
8
|
-
* an Atomic class that guarantees atomic updates to its contained value
|
9
|
-
|
10
|
-
The Atomic class provides accessors for the contained "value" plus two update
|
11
|
-
methods:
|
12
|
-
|
13
|
-
* update will run the provided block, passing the current value and replacing
|
14
|
-
it with the block result iff the value has not been changed in the mean time.
|
15
|
-
It may run the block repeatedly if there are other concurrent updates in
|
16
|
-
progress.
|
17
|
-
* try_update will run the provided block, passing the current value and
|
18
|
-
replacing it with the block result. If the value changes before the update
|
19
|
-
can happen, it will throw Atomic::ConcurrentUpdateError.
|
20
|
-
|
21
|
-
The atomic repository is at http://github.com/headius/ruby-atomic.
|
22
|
-
|
23
|
-
== Usage ==
|
24
|
-
|
25
|
-
require 'atomic'
|
26
|
-
|
27
|
-
my_atomic = Atomic.new(0)
|
28
|
-
my_atomic.update {|v| v + 1}
|
29
|
-
begin
|
30
|
-
my_atomic.try_update {|v| v + 1}
|
31
|
-
rescue Atomic::ConcurrentUpdateError => cue
|
32
|
-
# deal with it (retry, propagate, etc)
|
33
|
-
end
|