Skip to content

Commit d63684a

Browse files
committed
[GR-19220] Fix tracing of allocations from C and store allocation tracing information directly on RubyDynamicObject (#2403)
PullRequest: truffleruby/2804
2 parents e99c63b + a35e547 commit d63684a

File tree

16 files changed

+414
-160
lines changed

16 files changed

+414
-160
lines changed

lib/truffle/objspace.rb

Lines changed: 35 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -8,60 +8,52 @@
88
# GNU General Public License version 2, or
99
# GNU Lesser General Public License version 2.1.
1010

11-
require 'json'
12-
require 'tempfile'
13-
require 'weakref'
11+
module Truffle::ObjSpace
12+
def self.count_nodes_method(method, nodes)
13+
node_stack = [Truffle.ast(method)]
14+
15+
until node_stack.empty?
16+
node = node_stack.pop
17+
next if node.nil?
18+
19+
name = node.first
20+
children = node.drop(1)
21+
nodes[name] ||= 0
22+
nodes[name] += 1
23+
node_stack.push(*children)
24+
end
25+
end
26+
end
1427

1528
module ObjectSpace
29+
module_function
1630

1731
def count_nodes(nodes = {})
1832
ObjectSpace.each_object(Module) do |mod|
1933
mod.methods(false).each do |name|
20-
count_nodes_method mod.method(name), nodes
34+
Truffle::ObjSpace.count_nodes_method mod.method(name), nodes
2135
end
2236

2337
mod.private_methods(false).each do |name|
24-
count_nodes_method mod.method(name), nodes
38+
Truffle::ObjSpace.count_nodes_method mod.method(name), nodes
2539
end
2640
end
2741

2842
ObjectSpace.each_object(Proc) do |proc|
29-
count_nodes_method proc, nodes
43+
Truffle::ObjSpace.count_nodes_method proc, nodes
3044
end
3145

3246
ObjectSpace.each_object(Method) do |method|
33-
count_nodes_method method, nodes
47+
Truffle::ObjSpace.count_nodes_method method, nodes
3448
end
3549

3650
ObjectSpace.each_object(UnboundMethod) do |umethod|
37-
count_nodes_method umethod, nodes
51+
Truffle::ObjSpace.count_nodes_method umethod, nodes
3852
end
3953

4054
nodes
4155
end
4256

43-
module_function :count_nodes
44-
45-
class << self
46-
47-
def count_nodes_method(method, nodes)
48-
node_stack = [Truffle.ast(method)]
49-
50-
until node_stack.empty?
51-
node = node_stack.pop
52-
next if node.nil?
53-
54-
name = node.first
55-
children = node.drop(1)
56-
nodes[name] ||= 0
57-
nodes[name] += 1
58-
node_stack.push(*children)
59-
end
60-
end
61-
private :count_nodes_method
62-
63-
end
64-
6557
def count_objects_size(hash = {})
6658
total = 0
6759
ObjectSpace.each_object(Class) do |klass|
@@ -72,7 +64,6 @@ def count_objects_size(hash = {})
7264
hash[:TOTAL] = total
7365
hash
7466
end
75-
module_function :count_objects_size
7667

7768
def count_tdata_objects(hash = {})
7869
ObjectSpace.each_object do |object|
@@ -82,11 +73,11 @@ def count_tdata_objects(hash = {})
8273
end
8374
hash
8475
end
85-
module_function :count_tdata_objects
8676

8777
def dump(object, output: :string)
8878
case output
8979
when :string
80+
require 'json'
9081
json = {
9182
address: '0x' + object.object_id.to_s(16),
9283
class: '0x' + object.class.object_id.to_s(16),
@@ -119,6 +110,7 @@ def dump(object, output: :string)
119110
end
120111
JSON.generate(json)
121112
when :file
113+
require 'tempfile'
122114
f = Tempfile.new(['rubyobj', '.json'])
123115
f.write dump(object, output: :string)
124116
f.close
@@ -128,7 +120,6 @@ def dump(object, output: :string)
128120
nil
129121
end
130122
end
131-
module_function :dump
132123

133124
def dump_all(output: :file)
134125
case output
@@ -139,6 +130,7 @@ def dump_all(output: :file)
139130
end
140131
objects.join("\n")
141132
when :file
133+
require 'tempfile'
142134
f = Tempfile.new(['ruby', '.json'])
143135
f.write dump_all(output: :string)
144136
f.close
@@ -151,7 +143,6 @@ def dump_all(output: :file)
151143
nil
152144
end
153145
end
154-
module_function :dump_all
155146

156147
def memsize_of(object)
157148
size = Truffle::ObjSpace.memsize_of(object)
@@ -163,7 +154,6 @@ def memsize_of(object)
163154
size
164155
end
165156
end
166-
module_function :memsize_of
167157

168158
def memsize_of_all(klass = BasicObject)
169159
total = 0
@@ -172,17 +162,14 @@ def memsize_of_all(klass = BasicObject)
172162
end
173163
total
174164
end
175-
module_function :memsize_of_all
176165

177166
def reachable_objects_from(object)
178167
Truffle::ObjSpace.adjacent_objects(object)
179168
end
180-
module_function :reachable_objects_from
181169

182170
def reachable_objects_from_root
183-
{'roots' => Truffle::ObjSpace.root_objects}
171+
{ 'roots' => Truffle::ObjSpace.root_objects }
184172
end
185-
module_function :reachable_objects_from_root
186173

187174
def trace_object_allocations
188175
trace_object_allocations_start
@@ -192,89 +179,40 @@ def trace_object_allocations
192179
trace_object_allocations_stop
193180
end
194181
end
195-
module_function :trace_object_allocations
196-
197-
def trace_object_allocations_clear
198-
TruffleRuby.synchronized(ALLOCATIONS) do
199-
ALLOCATIONS.clear
200-
end
201-
end
202-
module_function :trace_object_allocations_clear
203182

204183
def trace_object_allocations_debug_start
205184
trace_object_allocations_start
206185
end
207-
module_function :trace_object_allocations_debug_start
208186

209187
def trace_object_allocations_start
210188
Truffle::ObjSpace.trace_allocations_start
211189
end
212-
module_function :trace_object_allocations_start
213190

214191
def trace_object_allocations_stop
215192
Truffle::ObjSpace.trace_allocations_stop
216193
end
217-
module_function :trace_object_allocations_stop
194+
195+
def trace_object_allocations_clear
196+
Truffle::ObjSpace.trace_allocations_clear
197+
end
218198

219199
def allocation_class_path(object)
220-
allocation = TruffleRuby.synchronized(ALLOCATIONS) do
221-
ALLOCATIONS[object]
222-
end
223-
return nil if allocation.nil?
224-
allocation.class_path
200+
Primitive.allocation_class_path(object)
225201
end
226-
module_function :allocation_class_path
227202

228203
def allocation_generation(object)
229-
allocation = TruffleRuby.synchronized(ALLOCATIONS) do
230-
ALLOCATIONS[object]
231-
end
232-
return nil if allocation.nil?
233-
allocation.generation
204+
Primitive.allocation_generation(object)
234205
end
235-
module_function :allocation_generation
236206

237207
def allocation_method_id(object)
238-
allocation = TruffleRuby.synchronized(ALLOCATIONS) do
239-
ALLOCATIONS[object]
240-
end
241-
return nil if allocation.nil?
242-
243-
method_id = allocation.method_id
244-
# The allocator function is hidden in MRI
245-
method_id = :new if method_id == :__allocate__
246-
method_id
208+
Primitive.allocation_method_id(object)
247209
end
248-
module_function :allocation_method_id
249210

250211
def allocation_sourcefile(object)
251-
allocation = TruffleRuby.synchronized(ALLOCATIONS) do
252-
ALLOCATIONS[object]
253-
end
254-
return nil if allocation.nil?
255-
allocation.sourcefile
212+
Primitive.allocation_sourcefile(object)
256213
end
257-
module_function :allocation_sourcefile
258214

259215
def allocation_sourceline(object)
260-
allocation = TruffleRuby.synchronized(ALLOCATIONS) do
261-
ALLOCATIONS[object]
262-
end
263-
return nil if allocation.nil?
264-
allocation.sourceline
265-
end
266-
module_function :allocation_sourceline
267-
268-
Allocation = Struct.new(:class_path, :method_id, :sourcefile, :sourceline, :generation)
269-
270-
ALLOCATIONS = {}.compare_by_identity
271-
272-
def trace_allocation(object, class_path, method_id, sourcefile, sourceline, generation)
273-
allocation = Allocation.new(class_path, method_id, sourcefile, sourceline, generation)
274-
TruffleRuby.synchronized(ALLOCATIONS) do
275-
ALLOCATIONS[object] = allocation
276-
end
216+
Primitive.allocation_sourceline(object)
277217
end
278-
module_function :trace_allocation
279-
280218
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require_relative '../../spec_helper'
2+
require 'objspace'
3+
4+
describe "ObjectSpace.memsize_of_all" do
5+
it "returns a non-zero Integer for all objects" do
6+
ObjectSpace.memsize_of_all.should be_kind_of(Integer)
7+
ObjectSpace.memsize_of_all.should > 0
8+
end
9+
10+
it "returns a non-zero Integer for Class" do
11+
ObjectSpace.memsize_of_all(Class).should be_kind_of(Integer)
12+
ObjectSpace.memsize_of_all(Class).should > 0
13+
end
14+
15+
it "increases when a new object is allocated" do
16+
before = ObjectSpace.memsize_of_all(Class)
17+
o = Class.new
18+
after = ObjectSpace.memsize_of_all(Class)
19+
after.should > before
20+
end
21+
end

spec/ruby/library/objectspace/memsize_of_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
ObjectSpace.memsize_of(:abc).should == 0
1717
end
1818

19-
it "returns an Integer for an Object" do
19+
it "returns a positive Integer for an Object" do
2020
obj = Object.new
2121
ObjectSpace.memsize_of(obj).should be_kind_of(Integer)
2222
ObjectSpace.memsize_of(obj).should > 0

0 commit comments

Comments
 (0)