This PR attempts to support stackprof's object mode which tracks the number of allocated objects. This differs from the other modes (cpu and wall) by taking samples every time a Ruby object is allocated using Ruby's [`NEWOBJ` tracepoint](https://github.com/tmm1/stackprof/blob/df24b85953bb45d3abff58d9c82169a3003a60f1/ext/stackprof/stackprof.c#L198-L199). When importing an object mode profile into speedscope today it still works but what you see is a profile using time units. The profile will only have samples for when an object was allocated which means even if time is reported, the profile is not really meaningful when looking at time. To address this I've done three things when `mode` is `object`: + adjusted the total size of the `StackListProfileBuilder` to use the number of samples (since each sample is one allocation) + adjusted the weight of each sample to be `nSamples` (which I believe is always `1` but I'm not positive) + do not set the value formatter to a time formatter Here's what it looks like before and after my changes (note the units and weight of samples): wall (before) | object (before) | object (after) -- | -- | -- <img width="1624" alt="Screen Shot 2022-05-11 at 4 51 31 PM" src="https://user-images.githubusercontent.com/898172/167945635-2401ca73-4de7-4559-b884-cf8947ca9738.png"> | <img width="1624" alt="Screen Shot 2022-05-11 at 4 51 34 PM" src="https://user-images.githubusercontent.com/898172/167945641-ef302a60-730b-4afd-8e44-5f02e54b3cb7.png"> | <img width="1624" alt="Screen Shot 2022-05-11 at 4 51 42 PM" src="https://user-images.githubusercontent.com/898172/167945643-5611b267-f8b2-4227-a2bf-7145c4030aa2.png"> <details> <summary>Test code</summary> ```ruby require 'stackprof' require 'json' def do_test 5.times do make_a_word end end def make_a_word ('a'..'z').to_a.shuffle.map(&:upcase).join end StackProf.start(mode: :object, interval: 1, raw: true) do_test StackProf.stop File.write('tmp/object_profile.json', JSON.generate(StackProf.results)) StackProf.start(mode: :wall, interval: 1, raw: true) do_test StackProf.stop File.write('tmp/wall_profile.json', JSON.generate(StackProf.results)) ``` </details>
26 lines
263 B
Ruby
26 lines
263 B
Ruby
require 'json'
|
|
require 'stackprof'
|
|
|
|
def a
|
|
for i in 0..2 do
|
|
b
|
|
c
|
|
end
|
|
end
|
|
|
|
def b
|
|
Object.new
|
|
end
|
|
|
|
def c
|
|
for i in 0..5
|
|
(1..10).to_a.sample(3).sort
|
|
end
|
|
end
|
|
|
|
profile = StackProf.run(mode: :object, raw: true) do
|
|
a
|
|
end
|
|
|
|
puts JSON.generate(profile)
|