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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
# frozen_string_literal: true
require 'test/unit'
require 'fiddle'
require 'etc'
if RUBY_PLATFORM =~ /s390x/
warn "Currently, it is known that the compaction does not work well on s390x; contribution is welcome https://github.com/ruby/ruby/pull/5077"
return
end
class TestGCCompact < Test::Unit::TestCase
module SupportsCompact
def setup
skip "autocompact not supported on this platform" unless supports_auto_compact?
super
end
private
def supports_auto_compact?
return true unless defined?(Etc::SC_PAGE_SIZE)
begin
return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0
rescue NotImplementedError
rescue ArgumentError
end
true
end
end
include SupportsCompact
class AutoCompact < Test::Unit::TestCase
include SupportsCompact
def test_enable_autocompact
before = GC.auto_compact
GC.auto_compact = true
assert GC.auto_compact
ensure
GC.auto_compact = before
end
def test_disable_autocompact
before = GC.auto_compact
GC.auto_compact = false
refute GC.auto_compact
ensure
GC.auto_compact = before
end
def test_major_compacts
before = GC.auto_compact
GC.auto_compact = true
compact = GC.stat :compact_count
GC.start
assert_operator GC.stat(:compact_count), :>, compact
ensure
GC.auto_compact = before
end
def test_implicit_compaction_does_something
before = GC.auto_compact
list = []
list2 = []
# Try to make some fragmentation
500.times {
list << Object.new
Object.new
Object.new
}
count = GC.stat :compact_count
GC.auto_compact = true
n = 1_000_000
n.times do
break if count < GC.stat(:compact_count)
list2 << Object.new
end and skip "implicit compaction didn't happen within #{n} objects"
compact_stats = GC.latest_compact_info
refute_predicate compact_stats[:considered], :empty?
refute_predicate compact_stats[:moved], :empty?
ensure
GC.auto_compact = before
end
end
def os_page_size
return true unless defined?(Etc::SC_PAGE_SIZE)
end
def setup
skip "autocompact not supported on this platform" unless supports_auto_compact?
super
end
def test_gc_compact_stats
list = []
# Try to make some fragmentation
500.times {
list << Object.new
Object.new
Object.new
}
compact_stats = GC.compact
refute_predicate compact_stats[:considered], :empty?
refute_predicate compact_stats[:moved], :empty?
end
def memory_location(obj)
(Fiddle.dlwrap(obj) >> 1)
end
def big_list(level = 10)
if level > 0
big_list(level - 1)
else
1000.times.map {
# try to make some empty slots by allocating an object and discarding
Object.new
Object.new
} # likely next to each other
end
end
# Find an object that's allocated in a slot that had a previous
# tenant, and that tenant moved and is still alive
def find_object_in_recycled_slot(addresses)
new_object = nil
100_000.times do
new_object = Object.new
if addresses.index memory_location(new_object)
break
end
end
new_object
end
def test_complex_hash_keys
list_of_objects = big_list
hash = list_of_objects.hash
GC.verify_compaction_references(toward: :empty)
assert_equal hash, list_of_objects.hash
GC.verify_compaction_references(double_heap: false)
assert_equal hash, list_of_objects.hash
end
def test_ast_compacts
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV)
begin;
def walk_ast ast
children = ast.children.grep(RubyVM::AbstractSyntaxTree::Node)
children.each do |child|
assert child.type
walk_ast child
end
end
ast = RubyVM::AbstractSyntaxTree.parse_file #{__FILE__.dump}
assert GC.compact
walk_ast ast
end;
end
def test_compact_count
count = GC.stat(:compact_count)
GC.compact
assert_equal count + 1, GC.stat(:compact_count)
end
end
|