atomic 0.0.5 → 0.0.6

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/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