mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* benchmark/gc/redblack.rb: import red black tree benchmark from
https://github.com/jruby/rubybench/blob/master/time/bench_red_black.rb * benchmark/gc/ring.rb: add a benchmark. This benchmark create many old objects. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41475 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ae39bfc5dc
commit
2802afffd6
3 changed files with 403 additions and 0 deletions
|
@ -1,3 +1,11 @@
|
|||
Thu Jun 20 15:32:56 2013 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* benchmark/gc/redblack.rb: import red black tree benchmark from
|
||||
https://github.com/jruby/rubybench/blob/master/time/bench_red_black.rb
|
||||
|
||||
* benchmark/gc/ring.rb: add a benchmark. This benchmark create many
|
||||
old objects.
|
||||
|
||||
Thu Jun 20 15:14:00 2013 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* benchmark/gc: create a directory to store GC related benchmark.
|
||||
|
|
366
benchmark/gc/redblack.rb
Normal file
366
benchmark/gc/redblack.rb
Normal file
|
@ -0,0 +1,366 @@
|
|||
# This benchmark is imported from https://github.com/jruby/rubybench/blob/master/time/bench_red_black.rb
|
||||
# License is License is Apache-2
|
||||
|
||||
require 'benchmark'
|
||||
|
||||
# Algorithm based on "Introduction to Algorithms" by Cormen and others
|
||||
class RedBlackTree
|
||||
class Node
|
||||
attr_accessor :color
|
||||
attr_accessor :key
|
||||
attr_accessor :left
|
||||
attr_accessor :right
|
||||
attr_accessor :parent
|
||||
|
||||
RED = :red
|
||||
BLACK = :black
|
||||
COLORS = [RED, BLACK].freeze
|
||||
|
||||
def initialize(key, color = RED)
|
||||
raise ArgumentError, "Bad value for color parameter" unless COLORS.include?(color)
|
||||
@color = color
|
||||
@key = key
|
||||
@left = @right = @parent = NilNode.instance
|
||||
end
|
||||
|
||||
def black?
|
||||
return color == BLACK
|
||||
end
|
||||
|
||||
def red?
|
||||
return color == RED
|
||||
end
|
||||
end
|
||||
|
||||
class NilNode < Node
|
||||
class << self
|
||||
private :new
|
||||
|
||||
# it's not thread safe
|
||||
def instance
|
||||
@instance ||= begin
|
||||
def instance
|
||||
return @instance
|
||||
end
|
||||
|
||||
new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize
|
||||
self.color = BLACK
|
||||
self.key = 0
|
||||
self.left = nil
|
||||
self.right = nil
|
||||
self.parent = nil
|
||||
end
|
||||
|
||||
def nil?
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
include Enumerable
|
||||
|
||||
attr_accessor :root
|
||||
attr_accessor :size
|
||||
|
||||
def initialize
|
||||
self.root = NilNode.instance
|
||||
self.size = 0
|
||||
end
|
||||
|
||||
def add(key)
|
||||
insert(Node.new(key))
|
||||
end
|
||||
|
||||
def insert(x)
|
||||
insert_helper(x)
|
||||
|
||||
x.color = Node::RED
|
||||
while x != root && x.parent.color == Node::RED
|
||||
if x.parent == x.parent.parent.left
|
||||
y = x.parent.parent.right
|
||||
if !y.nil? && y.color == Node::RED
|
||||
x.parent.color = Node::BLACK
|
||||
y.color = Node::BLACK
|
||||
x.parent.parent.color = Node::RED
|
||||
x = x.parent.parent
|
||||
else
|
||||
if x == x.parent.right
|
||||
x = x.parent
|
||||
left_rotate(x)
|
||||
end
|
||||
x.parent.color = Node::BLACK
|
||||
x.parent.parent.color = Node::RED
|
||||
right_rotate(x.parent.parent)
|
||||
end
|
||||
else
|
||||
y = x.parent.parent.left
|
||||
if !y.nil? && y.color == Node::RED
|
||||
x.parent.color = Node::BLACK
|
||||
y.color = Node::BLACK
|
||||
x.parent.parent.color = Node::RED
|
||||
x = x.parent.parent
|
||||
else
|
||||
if x == x.parent.left
|
||||
x = x.parent
|
||||
right_rotate(x)
|
||||
end
|
||||
x.parent.color = Node::BLACK
|
||||
x.parent.parent.color = Node::RED
|
||||
left_rotate(x.parent.parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
root.color = Node::BLACK
|
||||
end
|
||||
|
||||
alias << insert
|
||||
|
||||
def delete(z)
|
||||
y = (z.left.nil? || z.right.nil?) ? z : successor(z)
|
||||
x = y.left.nil? ? y.right : y.left
|
||||
x.parent = y.parent
|
||||
|
||||
if y.parent.nil?
|
||||
self.root = x
|
||||
else
|
||||
if y == y.parent.left
|
||||
y.parent.left = x
|
||||
else
|
||||
y.parent.right = x
|
||||
end
|
||||
end
|
||||
|
||||
z.key = y.key if y != z
|
||||
|
||||
if y.color == Node::BLACK
|
||||
delete_fixup(x)
|
||||
end
|
||||
|
||||
self.size -= 1
|
||||
return y
|
||||
end
|
||||
|
||||
def minimum(x = root)
|
||||
while !x.left.nil?
|
||||
x = x.left
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
def maximum(x = root)
|
||||
while !x.right.nil?
|
||||
x = x.right
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
def successor(x)
|
||||
if !x.right.nil?
|
||||
return minimum(x.right)
|
||||
end
|
||||
y = x.parent
|
||||
while !y.nil? && x == y.right
|
||||
x = y
|
||||
y = y.parent
|
||||
end
|
||||
return y
|
||||
end
|
||||
|
||||
def predecessor(x)
|
||||
if !x.left.nil?
|
||||
return maximum(x.left)
|
||||
end
|
||||
y = x.parent
|
||||
while !y.nil? && x == y.left
|
||||
x = y
|
||||
y = y.parent
|
||||
end
|
||||
return y
|
||||
end
|
||||
|
||||
def inorder_walk(x = root)
|
||||
x = self.minimum
|
||||
while !x.nil?
|
||||
yield x.key
|
||||
x = successor(x)
|
||||
end
|
||||
end
|
||||
|
||||
alias each inorder_walk
|
||||
|
||||
def reverse_inorder_walk(x = root)
|
||||
x = self.maximum
|
||||
while !x.nil?
|
||||
yield x.key
|
||||
x = predecessor(x)
|
||||
end
|
||||
end
|
||||
|
||||
alias reverse_each reverse_inorder_walk
|
||||
|
||||
def search(key, x = root)
|
||||
while !x.nil? && x.key != key
|
||||
key < x.key ? x = x.left : x = x.right
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
def empty?
|
||||
return self.root.nil?
|
||||
end
|
||||
|
||||
def black_height(x = root)
|
||||
height = 0
|
||||
while !x.nil?
|
||||
x = x.left
|
||||
height +=1 if x.nil? || x.black?
|
||||
end
|
||||
return height
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def left_rotate(x)
|
||||
raise "x.right is nil!" if x.right.nil?
|
||||
y = x.right
|
||||
x.right = y.left
|
||||
y.left.parent = x if !y.left.nil?
|
||||
y.parent = x.parent
|
||||
if x.parent.nil?
|
||||
self.root = y
|
||||
else
|
||||
if x == x.parent.left
|
||||
x.parent.left = y
|
||||
else
|
||||
x.parent.right = y
|
||||
end
|
||||
end
|
||||
y.left = x
|
||||
x.parent = y
|
||||
end
|
||||
|
||||
def right_rotate(x)
|
||||
raise "x.left is nil!" if x.left.nil?
|
||||
y = x.left
|
||||
x.left = y.right
|
||||
y.right.parent = x if !y.right.nil?
|
||||
y.parent = x.parent
|
||||
if x.parent.nil?
|
||||
self.root = y
|
||||
else
|
||||
if x == x.parent.left
|
||||
x.parent.left = y
|
||||
else
|
||||
x.parent.right = y
|
||||
end
|
||||
end
|
||||
y.right = x
|
||||
x.parent = y
|
||||
end
|
||||
|
||||
def insert_helper(z)
|
||||
y = NilNode.instance
|
||||
x = root
|
||||
while !x.nil?
|
||||
y = x
|
||||
z.key < x.key ? x = x.left : x = x.right
|
||||
end
|
||||
z.parent = y
|
||||
if y.nil?
|
||||
self.root = z
|
||||
else
|
||||
z.key < y.key ? y.left = z : y.right = z
|
||||
end
|
||||
self.size += 1
|
||||
end
|
||||
|
||||
def delete_fixup(x)
|
||||
while x != root && x.color == Node::BLACK
|
||||
if x == x.parent.left
|
||||
w = x.parent.right
|
||||
if w.color == Node::RED
|
||||
w.color = Node::BLACK
|
||||
x.parent.color = Node::RED
|
||||
left_rotate(x.parent)
|
||||
w = x.parent.right
|
||||
end
|
||||
if w.left.color == Node::BLACK && w.right.color == Node::BLACK
|
||||
w.color = Node::RED
|
||||
x = x.parent
|
||||
else
|
||||
if w.right.color == Node::BLACK
|
||||
w.left.color = Node::BLACK
|
||||
w.color = Node::RED
|
||||
right_rotate(w)
|
||||
w = x.parent.right
|
||||
end
|
||||
w.color = x.parent.color
|
||||
x.parent.color = Node::BLACK
|
||||
w.right.color = Node::BLACK
|
||||
left_rotate(x.parent)
|
||||
x = root
|
||||
end
|
||||
else
|
||||
w = x.parent.left
|
||||
if w.color == Node::RED
|
||||
w.color = Node::BLACK
|
||||
x.parent.color = Node::RED
|
||||
right_rotate(x.parent)
|
||||
w = x.parent.left
|
||||
end
|
||||
if w.right.color == Node::BLACK && w.left.color == Node::BLACK
|
||||
w.color = Node::RED
|
||||
x = x.parent
|
||||
else
|
||||
if w.left.color == Node::BLACK
|
||||
w.right.color = Node::BLACK
|
||||
w.color = Node::RED
|
||||
left_rotate(w)
|
||||
w = x.parent.left
|
||||
end
|
||||
w.color = x.parent.color
|
||||
x.parent.color = Node::BLACK
|
||||
w.left.color = Node::BLACK
|
||||
right_rotate(x.parent)
|
||||
x = root
|
||||
end
|
||||
end
|
||||
end
|
||||
x.color = Node::BLACK
|
||||
end
|
||||
end
|
||||
|
||||
def rbt_bm
|
||||
n = 100_000
|
||||
a1 = []; n.times { a1 << rand(999_999) }
|
||||
a2 = []; n.times { a2 << rand(999_999) }
|
||||
|
||||
start = Time.now
|
||||
|
||||
tree = RedBlackTree.new
|
||||
|
||||
n.times {|i| tree.add(i) }
|
||||
n.times { tree.delete(tree.root) }
|
||||
|
||||
tree = RedBlackTree.new
|
||||
a1.each {|e| tree.add(e) }
|
||||
a2.each {|e| tree.search(e) }
|
||||
tree.inorder_walk {|key| key + 1 }
|
||||
tree.reverse_inorder_walk {|key| key + 1 }
|
||||
n.times { tree.minimum }
|
||||
n.times { tree.maximum }
|
||||
|
||||
return Time.now - start
|
||||
end
|
||||
|
||||
N = (ARGV[0] || 10).to_i
|
||||
|
||||
N.times do
|
||||
# puts rbt_bm.to_f
|
||||
rbt_bm.to_f
|
||||
# puts "GC.count = #{GC.count}" if GC.respond_to?(:count)
|
||||
end
|
29
benchmark/gc/ring.rb
Normal file
29
benchmark/gc/ring.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# create many old objects
|
||||
|
||||
max = 30_000_000
|
||||
|
||||
class Ring
|
||||
attr_reader :next_ring
|
||||
def initialize n = nil
|
||||
@next_ring = n
|
||||
end
|
||||
|
||||
|
||||
def size
|
||||
s = 1
|
||||
ring = self
|
||||
while ring.next_ring
|
||||
s += 1
|
||||
ring = ring.next_ring
|
||||
end
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
ring = Ring.new
|
||||
|
||||
max.times{
|
||||
ring = Ring.new(ring)
|
||||
}
|
||||
|
||||
# p ring.size
|
Loading…
Reference in a new issue