summaryrefslogtreecommitdiff
path: root/internal/flamegraph/trie.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-24 20:16:52 +0200
committerPaul Buetow <paul@buetow.org>2026-02-24 20:16:52 +0200
commitb8e683e41364fcfd9edda05c4e35a8af3a21835d (patch)
tree9124fae6e596143313dac712b4214c262a0b3c82 /internal/flamegraph/trie.go
parent85eb1ab91fc388d05530bc48e54da10a9457c201 (diff)
flamegraph: add trie aggregation and unit tests
Diffstat (limited to 'internal/flamegraph/trie.go')
-rw-r--r--internal/flamegraph/trie.go65
1 files changed, 65 insertions, 0 deletions
diff --git a/internal/flamegraph/trie.go b/internal/flamegraph/trie.go
new file mode 100644
index 0000000..dbd3de6
--- /dev/null
+++ b/internal/flamegraph/trie.go
@@ -0,0 +1,65 @@
+package flamegraph
+
+import "sort"
+
+type trieNode struct {
+ name string
+ value uint64
+ total uint64
+ children []*trieNode
+ childMap map[string]*trieNode
+}
+
+type trie struct {
+ root *trieNode
+ maxDepth int
+}
+
+func newTrie() *trie {
+ return &trie{
+ root: &trieNode{
+ childMap: make(map[string]*trieNode),
+ },
+ }
+}
+
+func (t *trie) add(frames []string, value uint64) {
+ node := t.root
+ for _, frame := range frames {
+ child, ok := node.childMap[frame]
+ if !ok {
+ child = &trieNode{
+ name: frame,
+ childMap: make(map[string]*trieNode),
+ }
+ node.children = append(node.children, child)
+ node.childMap[frame] = child
+ }
+ node = child
+ }
+ node.value += value
+}
+
+func (t *trie) computeTotals() {
+ t.maxDepth = 0
+ var walk func(node *trieNode, depth int) uint64
+ walk = func(node *trieNode, depth int) uint64 {
+ if depth > t.maxDepth {
+ t.maxDepth = depth
+ }
+
+ sort.Slice(node.children, func(i, j int) bool {
+ return node.children[i].name < node.children[j].name
+ })
+
+ total := node.value
+ for _, child := range node.children {
+ total += walk(child, depth+1)
+ }
+ node.total = total
+ node.childMap = nil
+ return total
+ }
+
+ walk(t.root, 0)
+}