Skip to content

Commit 823d341

Browse files
committed
Reduce memory allocations when rendering diff flamegraphs
1 parent 86b86b8 commit 823d341

File tree

1 file changed

+38
-8
lines changed

1 file changed

+38
-8
lines changed

pkg/model/flamegraph_diff.go

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"bytes"
55
"fmt"
66

7-
"github.com/grafana/pyroscope/pkg/og/structs/cappedarr"
7+
"github.com/grafana/pyroscope/pkg/util/minheap"
88

99
querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
1010
)
@@ -95,7 +95,8 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph
9595
int64(i),
9696
}
9797

98-
res.Levels[level].Values = append(values, res.Levels[level].Values...)
98+
// We need to prepend values here, but this is expensive. We'll reverse the order later.
99+
res.Levels[level].Values = append(res.Levels[level].Values, values...)
99100
xLeftOffset += left.self
100101
xRghtOffset += rght.self
101102
otherLeftTotal, otherRghtTotal := int64(0), int64(0)
@@ -140,6 +141,11 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph
140141
}
141142
}
142143

144+
// reverse each level's values since we appended values instead of prepending them
145+
for _, level := range res.Levels {
146+
reverseSliceInChunks(level.Values, 7)
147+
}
148+
143149
deltaEncoding(res.Levels, 0, 7)
144150
deltaEncoding(res.Levels, 3, 7)
145151

@@ -259,18 +265,29 @@ func combineMinValues(leftTree, rightTree *Tree, maxNodes int) uint64 {
259265
if maxNodes < 1 {
260266
return 0
261267
}
262-
// Trees are combined, meaning that their structures are
263-
// identical, therefore the resulting tree can not have
264-
// more nodes than any of them.
265268
treeSize := leftTree.size(make([]*node, 0, defaultDFSSize))
266269
if treeSize <= int64(maxNodes) {
267270
return 0
268271
}
269-
c := cappedarr.New(maxNodes)
272+
273+
h := make([]int64, 0, maxNodes)
270274
combineIterateWithTotal(leftTree, rightTree, func(left uint64, right uint64) bool {
271-
return c.Push(max(left, right))
275+
maxVal := int64(max(left, right))
276+
if len(h) >= maxNodes {
277+
if maxVal > h[0] {
278+
h = minheap.Pop(h)
279+
h = minheap.Push(h, maxVal)
280+
}
281+
} else {
282+
h = minheap.Push(h, maxVal)
283+
}
284+
return true
272285
})
273-
return c.MinValue()
286+
287+
if len(h) < maxNodes {
288+
return 0
289+
}
290+
return uint64(h[0])
274291
}
275292

276293
// iterate both trees, both trees must be returned from combineTree
@@ -364,3 +381,16 @@ func prependTreeNode(s []*node, x *node) []*node {
364381
s[0] = x
365382
return s
366383
}
384+
385+
// reverseSliceInChunks reverses a slice in chunks of the given size
386+
func reverseSliceInChunks(slice []int64, chunkSize int) {
387+
if len(slice) < chunkSize {
388+
return
389+
}
390+
391+
for i, j := 0, len(slice)-chunkSize; i < j; i, j = i+chunkSize, j-chunkSize {
392+
for k := 0; k < chunkSize; k++ {
393+
slice[i+k], slice[j+k] = slice[j+k], slice[i+k]
394+
}
395+
}
396+
}

0 commit comments

Comments
 (0)