diff --git a/Gemfile b/Gemfile index 5bb33d0..a000450 100644 --- a/Gemfile +++ b/Gemfile @@ -5,4 +5,5 @@ gemspec # both are optional, depending on platform gem 'fast_stack' -gem 'stackprof', platform: :mri_21 +gem 'stackprof', platform: [:mri_21, :mri_22, :mri_23] + diff --git a/lib/flamegraph/renderer.rb b/lib/flamegraph/renderer.rb index 3d6dffe..5ca4c69 100644 --- a/lib/flamegraph/renderer.rb +++ b/lib/flamegraph/renderer.rb @@ -24,6 +24,7 @@ def graph_html(embed_resources) def graph_data table = [] prev = [] + prev_parent = [] # a 2d array makes collapsing easy @stacks.each_with_index do |stack, pos| @@ -31,19 +32,28 @@ def graph_data next unless stack col = [] + new_col = false - stack.reverse.map{|r| r.to_s}.each_with_index do |frame, i| + reversed_stack = stack.reverse + reversed_stack.map{|r| r.to_s}.each_with_index do |frame, i| + parent_frame = i > 0 ? reversed_stack[i - 1] : nil - if !prev[i].nil? + if !prev[i].nil? && !new_col last_col = prev[i] - if last_col[0] == frame + frame_match = last_col[0] == frame + parent_match = parent_frame.nil? || prev_parent[i].nil? || parent_frame == prev_parent[i] + + if frame_match && parent_match last_col[1] += 1 col << nil next + else + new_col = true end end prev[i] = [frame, 1] + prev_parent[i] = parent_frame col << prev[i] end prev = prev[0..col.length-1].to_a diff --git a/test/test_renderer.rb b/test/test_renderer.rb index b419973..b772d55 100644 --- a/test/test_renderer.rb +++ b/test/test_renderer.rb @@ -10,8 +10,24 @@ def test_builds_table_correctly {:x => 1, :y => 1, :frame => "1", :width => 2}, {:x => 1, :y => 2, :frame => "2", :width => 1}, {:x => 1, :y => 3, :frame => "3", :width => 1}, - {:x => 2, :y => 2, :frame => "4", :width => 2}, - {:x => 3, :y => 1, :frame => "5", :width => 1} + {:x => 2, :y => 2, :frame => "4", :width => 1}, + {:x => 3, :y => 1, :frame => "5", :width => 1}, + {:x => 3, :y => 2, :frame => "4", :width => 1} + ], g.graph_data) + + end + + def test_builds_table_correctly_for_different_grandparents + stacks = [["method4","method3","method1"],["method4","method3","method1"],["method4","method3","method2"]] + + g = Flamegraph::Renderer.new(stacks) + assert_equal([ + {:x => 1, :y => 1, :frame => "method1", :width => 2}, + {:x => 1, :y => 2, :frame => "method3", :width => 2}, + {:x => 1, :y => 3, :frame => "method4", :width => 2}, + {:x => 3, :y => 1, :frame => "method2", :width => 1}, + {:x => 3, :y => 2, :frame => "method3", :width => 1}, + {:x => 3, :y => 3, :frame => "method4", :width => 1} ], g.graph_data) end @@ -25,8 +41,9 @@ def test_avoids_bridges {:x => 1, :y => 1, :frame => "1", :width => 2}, {:x => 1, :y => 2, :frame => "2", :width => 1}, {:x => 1, :y => 3, :frame => "3", :width => 1}, - {:x => 2, :y => 2, :frame => "4", :width => 2}, - {:x => 3, :y => 1, :frame => "5", :width => 1} + {:x => 2, :y => 2, :frame => "4", :width => 1}, + {:x => 3, :y => 1, :frame => "5", :width => 1}, + {:x => 3, :y => 2, :frame => "4", :width => 1} ], g.graph_data)