github.com/grafana/pyroscope@v1.18.0/pkg/model/flamegraph_test.go (about) 1 package model 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" 10 11 querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" 12 typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" 13 ) 14 15 func Test_ExportToFlamebearer(t *testing.T) { 16 pType := &typesv1.ProfileType{ 17 ID: "memory:inuse_space:bytes:space:bytes", 18 Name: "memory", 19 SampleType: "inuse_space", 20 SampleUnit: "bytes", 21 PeriodType: "space", 22 PeriodUnit: "bytes", 23 } 24 expected := &flamebearer.FlamebearerProfile{ 25 Version: 1, 26 FlamebearerProfileV1: flamebearer.FlamebearerProfileV1{ 27 Metadata: flamebearer.FlamebearerMetadataV1{ 28 Format: "single", 29 Units: "bytes", 30 Name: "inuse_space", 31 SampleRate: 100, 32 }, 33 Flamebearer: flamebearer.FlamebearerV1{ 34 Names: []string{"total", "a", "c", "d", "b", "e"}, 35 Levels: [][]int{ 36 {0, 4, 0, 0}, 37 {0, 4, 0, 1}, 38 {0, 1, 0, 4, 0, 3, 2, 2}, 39 {0, 1, 1, 5, 2, 1, 1, 3}, 40 }, 41 NumTicks: 4, 42 MaxSelf: 2, 43 }, 44 }, 45 } 46 actual := ExportToFlamebearer( 47 NewFlameGraph( 48 newTree([]stacktraces{ 49 { 50 locations: []string{"e", "b", "a"}, 51 value: 1, 52 }, 53 { 54 locations: []string{"c", "a"}, 55 value: 2, 56 }, 57 { 58 locations: []string{"d", "c", "a"}, 59 value: 1, 60 }, 61 }), 62 -1, 63 ), pType) 64 require.Equal(t, expected, actual) 65 66 t.Run("nil", func(t *testing.T) { 67 require.Equal(t, &flamebearer.FlamebearerProfile{ 68 Version: 1, 69 FlamebearerProfileV1: flamebearer.FlamebearerProfileV1{ 70 Metadata: flamebearer.FlamebearerMetadataV1{ 71 Format: "single", 72 SampleRate: 100, 73 Units: "bytes", 74 Name: "inuse_space", 75 }, 76 Flamebearer: flamebearer.FlamebearerV1{ 77 Levels: [][]int{}, 78 }, 79 }, 80 }, ExportToFlamebearer(nil, pType)) 81 }) 82 } 83 84 var f *querierv1.FlameGraph 85 86 func BenchmarkFlamegraph(b *testing.B) { 87 stacks := make([]stacktraces, 2000) 88 for i := range stacks { 89 stacks[i] = stacktraces{ 90 locations: []string{"a", "b", "c", "d", "e", fmt.Sprintf("%d", i)}, 91 value: 1, 92 } 93 } 94 tr := newTree(stacks) 95 b.ResetTimer() 96 b.ReportAllocs() 97 for i := 0; i < b.N; i++ { 98 f = NewFlameGraph(tr, -1) 99 } 100 } 101 102 func Test_FlameGraphMerger(t *testing.T) { 103 t.Run("two non-empty flamegraphs", func(t *testing.T) { 104 m := NewFlameGraphMerger() 105 s := new(Tree) 106 s.InsertStack(1, "foo", "bar") 107 s.InsertStack(1, "foo", "bar", "baz") 108 s.InsertStack(2, "foo", "qux") 109 s.InsertStack(1, "fred", "zoo") 110 s.InsertStack(1, "fred", "other") 111 m.MergeFlameGraph(NewFlameGraph(s, -1)) 112 113 s = new(Tree) 114 s.InsertStack(1, "foo", "bar", "baz") 115 s.InsertStack(1, "fred", "zoo") 116 s.InsertStack(1, "fred", "zoo", "ward") 117 s.InsertStack(1, "func", "other") 118 s.InsertStack(1, "func") 119 s.InsertStack(1, "other") 120 m.MergeFlameGraph(NewFlameGraph(s, -1)) 121 122 expected := new(Tree) 123 expected.InsertStack(1, "foo", "bar") 124 expected.InsertStack(1, "foo", "bar", "baz") 125 expected.InsertStack(2, "foo", "qux") 126 expected.InsertStack(1, "fred", "zoo") 127 expected.InsertStack(1, "fred", "other") 128 expected.InsertStack(1, "foo", "bar", "baz") 129 expected.InsertStack(1, "fred", "zoo") 130 expected.InsertStack(1, "fred", "zoo", "ward") 131 expected.InsertStack(1, "func", "other") 132 expected.InsertStack(1, "func") 133 expected.InsertStack(1, "other") 134 135 require.Equal(t, expected.String(), m.Tree().String()) 136 }) 137 138 t.Run("non-empty flamegraph result truncation", func(t *testing.T) { 139 m := NewFlameGraphMerger() 140 s := new(Tree) 141 s.InsertStack(1, "foo", "bar") 142 s.InsertStack(1, "foo", "bar", "baz") 143 s.InsertStack(2, "foo", "qux") 144 s.InsertStack(1, "fred", "zoo") 145 s.InsertStack(1, "fred", "other") 146 m.MergeFlameGraph(NewFlameGraph(s, -1)) 147 148 fg := m.FlameGraph(4) 149 m = NewFlameGraphMerger() 150 m.MergeFlameGraph(fg) 151 152 expected := new(Tree) 153 expected.InsertStack(1, "foo", "bar") 154 expected.InsertStack(1, "foo", "bar", "other") 155 expected.InsertStack(2, "foo", "qux") 156 expected.InsertStack(2, "fred", "other") 157 158 require.Equal(t, expected.String(), m.Tree().String()) 159 }) 160 161 t.Run("empty flamegraph", func(t *testing.T) { 162 m := NewFlameGraphMerger() 163 m.MergeFlameGraph(NewFlameGraph(new(Tree), -1)) 164 require.Equal(t, new(Tree).String(), m.Tree().String()) 165 }) 166 167 t.Run("no flamegraphs", func(t *testing.T) { 168 m := NewFlameGraphMerger() 169 require.Equal(t, new(Tree).String(), m.Tree().String()) 170 }) 171 }