-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* bench_atomic_1 is used to measure 1 combination * graph_atomic is used to run series, using bench_atomic_1 The idea is to calculate series by varying one parameter which gives much more meaninful results.
- Loading branch information
Jonas Pfenniger
committed
Sep 9, 2011
1 parent
8171865
commit 3477f07
Showing
2 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,138 @@ | |||
#!/usr/bin/env ruby | |||
|
|||
$: << File.expand_path('../../lib', __FILE__) | |||
|
|||
require 'optparse' | |||
require 'thread' | |||
require 'benchmark' | |||
|
|||
require 'atomic' | |||
|
|||
Thread.abort_on_exception = true | |||
|
|||
$conf = { | |||
:lock => "atomic", | |||
:num_threads => 100, | |||
:count => 100_000, | |||
:count_per_thread => nil, | |||
:slow => nil, | |||
} | |||
|
|||
OptionParser.new do |opts| | |||
opts.on("-c", "--count NUM") do |n| | |||
$conf[:count] = n.to_i | |||
end | |||
opts.on("-p", "--count-per-thread") do |n| | |||
$conf[:count_per_thread] = n.to_i | |||
end | |||
opts.on("-t", "--num-threads NUM") do |n| | |||
$conf[:num_threads] = n.to_i | |||
end | |||
opts.on("-s", "--slow NUM") do |n| | |||
$conf[:slow] = n.to_i | |||
end | |||
opts.on("-l", "--lock atomic|mutex") do |x| | |||
$conf[:lock] = x | |||
end | |||
opts.on("-h", "--help"){ puts opts; exit } | |||
end.parse!(ARGV) | |||
|
|||
unless $conf[:count_per_thread] | |||
$conf[:count_per_thread] = $conf[:count] / $conf[:num_threads] | |||
end | |||
$conf.delete(:count) | |||
|
|||
if $conf[:slow].to_i > 0 | |||
require 'digest/md5' | |||
def slow_down | |||
$conf[:slow].times do |i| | |||
Digest::MD5.hexdigest(i.to_s) | |||
end | |||
end | |||
|
|||
ret = [] | |||
10.times do | |||
m = Benchmark.measure{ slow_down } | |||
ret << m.real | |||
end | |||
|
|||
$conf[:slow_time] = [ret.min, ret.max] | |||
else | |||
def slow_down; end | |||
end | |||
|
|||
$stderr.puts $conf.inspect | |||
|
|||
def para_prepare(&block) | |||
num_threads = $conf[:num_threads] | |||
count = $conf[:count_per_thread] | |||
|
|||
if num_threads % 2 > 0 | |||
raise ArgumentError, "num_threads must be a multiple of two" | |||
end | |||
|
|||
# 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 | |||
|
|||
$go = false | |||
|
|||
tg | |||
end | |||
|
|||
|
|||
|
|||
$tg = nil | |||
if $conf[:lock] == "atomic" | |||
$atom = Atomic.new(0) | |||
$tg = para_prepare do |diff| | |||
$atom.update do |x| | |||
slow_down | |||
x + diff | |||
end | |||
end | |||
else | |||
$lock = Mutex.new | |||
$value = 0 | |||
$tg = para_prepare do |diff| | |||
$lock.synchronize do | |||
slow_down | |||
$value += diff | |||
end | |||
end | |||
end | |||
|
|||
|
|||
# Run ! | |||
# | |||
# NOTE: It seems to me that this measurement method | |||
# is sensible to how the system dispatches his resources. | |||
# | |||
# More precise caluclation could be done using | |||
# getrusage's times | |||
ret = Benchmark.measure do | |||
$go = true | |||
$tg.list.each{|t| t.join} | |||
$go = false | |||
end | |||
puts ret.real |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,68 @@ | |||
#!/usr/bin/env ruby | |||
require 'optparse' | |||
|
|||
conf = { | |||
:vary => "threads", | |||
:lock => "atomic" | |||
} | |||
|
|||
OptionParser.new do |opts| | |||
opts.on("-l", "--lock atomic|mutex") do |l| | |||
conf[:lock] = l | |||
end | |||
opts.on("-v", "--vary threads|speed") do |v| | |||
conf[:vary] = v | |||
end | |||
opts.on("-h", "--help"){ puts opts; exit } | |||
end.parse!(ARGV) | |||
|
|||
result = File.open("results_#{conf[:lock]}_#{conf[:vary]}.csv", "w") | |||
|
|||
|
|||
if conf[:vary] == "threads" | |||
# Vary the number of concurrent threads that update the value. | |||
# | |||
# There is a total count of 1mio updates that is distributed | |||
# between the number of threads. | |||
# | |||
# A pair number of threads is used so that even add and odd substract 1. | |||
# This avoid creating instances for Bignum since the number should | |||
# stay in the Fixnum range. | |||
# | |||
(1..100).each do |i| | |||
i = i * 2 | |||
|
|||
ret = [] | |||
10.times do | |||
ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -t #{i}`.to_f | |||
end | |||
|
|||
line = ([i] + ret).join(', ') | |||
|
|||
puts line | |||
result.puts line | |||
end | |||
elsif conf[:vary] == "speed" | |||
# Varies the execution time of the update block | |||
# by using long calulation (MD5) | |||
# | |||
# NOTE: Thread.pass and sleep() are not usable by the atomic | |||
# lock. It needs to run the whole block without hitting | |||
# another atomic update otherwise it has to retry | |||
# | |||
# The expected result is that the atomic lock's performance | |||
# will hit a certain threshold where it will be worse than mutexes. | |||
# | |||
(1..30).each do |i| | |||
|
|||
ret = [] | |||
10.times do | |||
ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -s #{i}`.to_f | |||
end | |||
|
|||
line = ([i] + ret).join(', ') | |||
|
|||
puts line | |||
result.puts line | |||
end | |||
end |