|
4 | 4 | "bytes"
|
5 | 5 | "fmt"
|
6 | 6 |
|
7 |
| - "github.com/grafana/pyroscope/pkg/og/structs/cappedarr" |
| 7 | + "github.com/grafana/pyroscope/pkg/util/minheap" |
8 | 8 |
|
9 | 9 | querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
|
10 | 10 | )
|
@@ -95,7 +95,8 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph
|
95 | 95 | int64(i),
|
96 | 96 | }
|
97 | 97 |
|
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...) |
99 | 100 | xLeftOffset += left.self
|
100 | 101 | xRghtOffset += rght.self
|
101 | 102 | otherLeftTotal, otherRghtTotal := int64(0), int64(0)
|
@@ -140,6 +141,11 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph
|
140 | 141 | }
|
141 | 142 | }
|
142 | 143 |
|
| 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 | + |
143 | 149 | deltaEncoding(res.Levels, 0, 7)
|
144 | 150 | deltaEncoding(res.Levels, 3, 7)
|
145 | 151 |
|
@@ -259,18 +265,29 @@ func combineMinValues(leftTree, rightTree *Tree, maxNodes int) uint64 {
|
259 | 265 | if maxNodes < 1 {
|
260 | 266 | return 0
|
261 | 267 | }
|
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. |
265 | 268 | treeSize := leftTree.size(make([]*node, 0, defaultDFSSize))
|
266 | 269 | if treeSize <= int64(maxNodes) {
|
267 | 270 | return 0
|
268 | 271 | }
|
269 |
| - c := cappedarr.New(maxNodes) |
| 272 | + |
| 273 | + h := make([]int64, 0, maxNodes) |
270 | 274 | 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 |
272 | 285 | })
|
273 |
| - return c.MinValue() |
| 286 | + |
| 287 | + if len(h) < maxNodes { |
| 288 | + return 0 |
| 289 | + } |
| 290 | + return uint64(h[0]) |
274 | 291 | }
|
275 | 292 |
|
276 | 293 | // iterate both trees, both trees must be returned from combineTree
|
@@ -364,3 +381,16 @@ func prependTreeNode(s []*node, x *node) []*node {
|
364 | 381 | s[0] = x
|
365 | 382 | return s
|
366 | 383 | }
|
| 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