atomic 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -9,6 +9,11 @@ Rake::TestTask.new :test do |t|
9
9
  t.test_files = FileList["test/**/*.rb"]
10
10
  end
11
11
 
12
+ desc "Run benchmarks"
13
+ task :bench do
14
+ exec "ruby -Ilib -Iext test/bench_atomic.rb"
15
+ end
16
+
12
17
  if defined?(JRUBY_VERSION)
13
18
  require 'ant'
14
19
 
@@ -2,15 +2,20 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{atomic}
5
- s.version = "0.0.5"
5
+ s.version = "0.0.6"
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"
9
9
  s.email = ["headius@headius.com", "mental@rydia.net"]
10
- s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
11
10
  s.homepage = "http://github.com/headius/ruby-atomic"
12
11
  s.require_paths = ["lib"]
13
12
  s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls"
14
13
  s.test_files = Dir["test/test*.rb"]
15
- s.extensions = 'ext/extconf.rb'
14
+ if defined?(JRUBY_VERSION)
15
+ s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
16
+ s.platform = 'java'
17
+ else
18
+ s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
19
+ s.extensions = 'ext/extconf.rb'
20
+ end
16
21
  end
@@ -0,0 +1,109 @@
1
+ require 'benchmark'
2
+ require 'atomic'
3
+ require 'thread'
4
+ Thread.abort_on_exception = true
5
+
6
+ $go = false # for synchronizing parallel threads
7
+
8
+ # number of updates on the value
9
+ N = ARGV[1] ? ARGV[1].to_i : 100_000
10
+
11
+ # number of threads for parallel test
12
+ M = ARGV[0] ? ARGV[0].to_i : 100
13
+
14
+
15
+ puts "*** Sequential updates ***"
16
+ Benchmark.bm(10) do |x|
17
+ value = 0
18
+ x.report "no lock" do
19
+ N.times do
20
+ value += 1
21
+ end
22
+ end
23
+
24
+ @lock = Mutex.new
25
+ x.report "mutex" do
26
+ value = 0
27
+ N.times do
28
+ @lock.synchronize do
29
+ value += 1
30
+ end
31
+ end
32
+ end
33
+
34
+ @atom = Atomic.new(0)
35
+ x.report "atomic" do
36
+ N.times do
37
+ @atom.update{|x| x += 1}
38
+ end
39
+ end
40
+ end
41
+
42
+ def para_setup(num_threads, count, &block)
43
+ if num_threads % 2 > 0
44
+ raise ArgumentError, "num_threads must be a multiple of two"
45
+ end
46
+ raise ArgumentError, "need block" unless block_given?
47
+
48
+ # Keep those threads together
49
+ tg = ThreadGroup.new
50
+
51
+ num_threads.times do |i|
52
+ diff = (i % 2 == 0) ? 1 : -1
53
+
54
+ t = Thread.new do
55
+ nil until $go
56
+ count.times do
57
+ yield diff
58
+ end
59
+ end
60
+
61
+ tg.add(t)
62
+ end
63
+
64
+ # Make sure all threads are started
65
+ while tg.list.find{|t| t.status != "run"}
66
+ Thread.pass
67
+ end
68
+
69
+ # For good measure
70
+ GC.start
71
+
72
+ tg
73
+ end
74
+
75
+ def para_run(tg)
76
+ $go = true
77
+ tg.list.each{|t| t.join}
78
+ $go = false
79
+ end
80
+
81
+ puts "*** Parallel updates ***"
82
+ Benchmark.bm(10) do |bm|
83
+ # This is not secure
84
+ value = 0
85
+ tg = para_setup(M, N/M) do |diff|
86
+ value += diff
87
+ end
88
+ bm.report("no lock"){ para_run(tg) }
89
+
90
+
91
+ value = 0
92
+ @lock = Mutex.new
93
+ tg = para_setup(M, N/M) do |diff|
94
+ @lock.synchronize do
95
+ value += diff
96
+ end
97
+ end
98
+ bm.report("mutex"){ para_run(tg) }
99
+ raise unless value == 0
100
+
101
+
102
+ @atom = Atomic.new(0)
103
+ tg = para_setup(M, N/M) do |diff|
104
+ @atom.update{|x| x + diff}
105
+ end
106
+ bm.report("atomic"){ para_run(tg) }
107
+ raise unless @atom.value == 0
108
+
109
+ end
@@ -11,32 +11,44 @@ class Atomic
11
11
  def value
12
12
  @ref.get
13
13
  end
14
+ alias get value
14
15
 
15
16
  def value=(new_value)
16
17
  @ref.set(new_value)
17
18
  new_value
18
19
  end
20
+ alias set value=
19
21
 
20
22
  def swap(new_value)
21
23
  @ref.get_and_set(new_value)
22
24
  end
25
+ alias get_and_set swap
26
+
27
+ def compare_and_swap(old_value, new_value)
28
+ @ref.compare_and_set(old_value, new_value)
29
+ end
30
+ alias compare_and_set compare_and_swap
23
31
 
24
32
  # Pass the current value to the given block, replacing it
25
33
  # with the block's result. May retry if the value changes
26
34
  # during the block's execution.
27
35
  def update
28
- begin
29
- try_update { |v| yield v }
30
- rescue ConcurrentUpdateError
31
- retry
32
- end
36
+ true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value))
37
+ new_value
33
38
  end
39
+
40
+ # frozen pre-allocated backtrace to speed ConcurrentUpdateError
41
+ CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
34
42
 
35
43
  def try_update
36
44
  old_value = @ref.get
37
45
  new_value = yield old_value
38
46
  unless @ref.compare_and_set(old_value, new_value)
39
- raise ConcurrentUpdateError, "Update failed"
47
+ if $VERBOSE
48
+ raise ConcurrentUpdateError, "Update failed"
49
+ else
50
+ raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE
51
+ end
40
52
  end
41
53
  new_value
42
54
  end
Binary file
metadata CHANGED
@@ -1,43 +1,47 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atomic
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 19
4
5
  prerelease:
5
- version: 0.0.5
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 6
10
+ version: 0.0.6
6
11
  platform: ruby
7
12
  authors:
8
- - Charles Oliver Nutter
9
- - MenTaLguY
13
+ - Charles Oliver Nutter
14
+ - MenTaLguY
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
18
 
14
- date: 2011-07-05 00:00:00 -05:00
15
- default_executable:
19
+ date: 2011-09-06 00:00:00 Z
16
20
  dependencies: []
17
21
 
18
22
  description: An atomic reference implementation for JRuby and green or GIL-threaded impls
19
23
  email:
20
- - headius@headius.com
21
- - mental@rydia.net
24
+ - headius@headius.com
25
+ - mental@rydia.net
22
26
  executables: []
23
27
 
24
28
  extensions:
25
- - ext/extconf.rb
29
+ - ext/extconf.rb
26
30
  extra_rdoc_files: []
27
31
 
28
32
  files:
29
- - lib/atomic.rb
30
- - lib/atomic_reference.jar
31
- - examples/atomic_example.rb
32
- - test/test_atomic.rb
33
- - ext/atomic_reference.c
34
- - ext/AtomicReferenceService.java
35
- - ext/extconf.rb
36
- - ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java
37
- - README.txt
38
- - atomic.gemspec
39
- - Rakefile
40
- has_rdoc: true
33
+ - lib/atomic.rb
34
+ - lib/atomic_reference.jar
35
+ - examples/atomic_example.rb
36
+ - examples/bench_atomic.rb
37
+ - test/test_atomic.rb
38
+ - ext/atomic_reference.c
39
+ - ext/AtomicReferenceService.java
40
+ - ext/extconf.rb
41
+ - ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java
42
+ - README.txt
43
+ - atomic.gemspec
44
+ - Rakefile
41
45
  homepage: http://github.com/headius/ruby-atomic
42
46
  licenses: []
43
47
 
@@ -45,25 +49,31 @@ post_install_message:
45
49
  rdoc_options: []
46
50
 
47
51
  require_paths:
48
- - lib
52
+ - lib
49
53
  required_ruby_version: !ruby/object:Gem::Requirement
50
54
  none: false
51
55
  requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: "0"
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
55
62
  required_rubygems_version: !ruby/object:Gem::Requirement
56
63
  none: false
57
64
  requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: "0"
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
61
71
  requirements: []
62
72
 
63
73
  rubyforge_project:
64
- rubygems_version: 1.5.1
74
+ rubygems_version: 1.8.10
65
75
  signing_key:
66
76
  specification_version: 3
67
77
  summary: An atomic reference implementation for JRuby and green or GIL-threaded impls
68
78
  test_files:
69
- - test/test_atomic.rb
79
+ - test/test_atomic.rb