File: benchmark_atomic.rb

package info (click to toggle)
ruby-concurrent 1.1.6%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 30,284 kB
  • sloc: ruby: 30,875; java: 6,117; ansic: 288; makefile: 9; sh: 6
file content (136 lines) | stat: -rwxr-xr-x 2,592 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env ruby

#$: << File.expand_path('../../lib', __FILE__)

require 'benchmark'
require 'rbconfig'
require 'thread'

require 'concurrent/atomics'

if RUBY_PLATFORM != 'java' && ! defined? Concurrent::CAtomicReference
  warn "[WARN] C extensions not loaded!"
end

Thread.abort_on_exception = true

$go = false # for synchronizing parallel threads

# number of updates on the value
N = ARGV[1] ? ARGV[1].to_i : 100_000

# number of threads for parallel test
M = ARGV[0] ? ARGV[0].to_i : 10

# list of platform-specific implementations
ATOMICS = [
  'MutexAtomicReference',
  'CAtomicReference',
  'JavaAtomicReference',
  'RbxAtomicReference',
]

puts "Testing with #{RbConfig::CONFIG['ruby_install_name']} #{RUBY_VERSION}"

puts
puts '*** Sequential updates ***'
Benchmark.bm(10) do |x|
  value = 0
  x.report 'no lock' do
    N.times do
      value += 1
    end
  end

  @lock = Mutex.new
  x.report 'mutex' do
    value = 0
    N.times do
      @lock.synchronize do
        value += 1
      end
    end
  end

  ATOMICS.each do |clazz|
    if Concurrent.const_defined? clazz
      @atom = Concurrent.const_get(clazz).new(0)
      x.report clazz do
        N.times do
          @atom.update{|x| x += 1}
        end
      end
    end
  end
end

def para_setup(num_threads, count, &block)
  if num_threads % 2 > 0
    raise ArgumentError, 'num_threads must be a multiple of two'
  end
  raise ArgumentError, 'need block' unless block_given?

  # Keep those threads together
  tg = ThreadGroup.new

  num_threads.times do |i|
    diff = (i % 2 == 0) ? 1 : -1

    t = Thread.new do
      nil until $go
      count.times do
        yield diff
      end
    end

    tg.add(t)
  end

  # Make sure all threads are started
  while tg.list.find{|t| t.status != 'run'}
    Thread.pass
  end

  # For good measure
  GC.start

  tg
end

def para_run(tg)
  $go = true
  tg.list.each{|t| t.join}
  $go = false
end

puts
puts '*** Parallel updates ***'
Benchmark.bm(10) do |bm|
  # This is not secure
  value = 0
  tg = para_setup(M, N/M) do |diff|
    value += diff
  end
  bm.report('no lock'){ para_run(tg) }

  value = 0
  @lock = Mutex.new
  tg = para_setup(M, N/M) do |diff|
    @lock.synchronize do
      value += diff
    end
  end
  bm.report('mutex'){ para_run(tg) }
  raise unless value == 0

  ATOMICS.each do |clazz|
    if Concurrent.const_defined? clazz
      @atom = Concurrent.const_get(clazz).new(0)
      tg = para_setup(M, N/M) do |diff|
        @atom.update{|x| x + diff}
      end
      bm.report(clazz){ para_run(tg) }
      raise unless @atom.value == 0
    end
  end
end