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
|