summaryrefslogtreecommitdiff
path: root/internal/flamegraph
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-03-12 22:58:13 +0200
committerPaul Buetow <paul@buetow.org>2025-03-12 22:58:13 +0200
commit0cbf594b5646ec7b020894d918c522be825aacc4 (patch)
treeacebbd79c31a1c1a0efb1400e664c55f52fd4211 /internal/flamegraph
parentac7ebea0920819a14e981da7e3297a8e2e256559 (diff)
refactor
Diffstat (limited to 'internal/flamegraph')
-rw-r--r--internal/flamegraph/flamegraph.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/internal/flamegraph/flamegraph.go b/internal/flamegraph/flamegraph.go
new file mode 100644
index 0000000..f73bf49
--- /dev/null
+++ b/internal/flamegraph/flamegraph.go
@@ -0,0 +1,106 @@
+package flamegraph
+
+import (
+ "context"
+ "fmt"
+ "ior/internal/event"
+ "ior/internal/generated/types"
+ "os"
+ "path"
+ "strings"
+)
+
+type counter struct {
+ count uint64
+ duration uint64
+}
+
+// Rename to Flamegraph
+type Flamegraph struct {
+ // Collapsed flamegraph stats collector
+ collapsed map[string]map[types.TraceId]counter
+ inCh chan *event.Pair
+ Done chan struct{}
+}
+
+func New() Flamegraph {
+ return Flamegraph{
+ collapsed: make(map[string]map[types.TraceId]counter),
+ inCh: make(chan *event.Pair, 4096),
+ Done: make(chan struct{}),
+ }
+}
+
+func (f Flamegraph) Start(ctx context.Context) {
+ go func() {
+ for {
+ select {
+ case ev := <-f.inCh:
+ pathname := path.Dir(ev.File.Name())
+ pathMap, ok := f.collapsed[pathname]
+ if !ok {
+ pathMap = make(map[types.TraceId]counter)
+ }
+
+ traceId := ev.EnterEv.GetTraceId()
+ cnt := pathMap[traceId]
+ cnt.count++
+ cnt.duration += ev.Duration
+ pathMap[traceId] = cnt
+
+ f.collapsed[pathname] = pathMap
+ ev.RecyclePrev()
+ default:
+ select {
+ case <-ctx.Done():
+ fmt.Println("Flamegraph processed last event")
+ f.dump()
+ close(f.Done)
+ return
+ default:
+ }
+ }
+ }
+ }()
+}
+
+func (f Flamegraph) Add(ev *event.Pair) {
+ f.inCh <- ev
+}
+
+func (f Flamegraph) dump() {
+ f.dumpBy("ior-by-count-collapsed.flamegraph", func(cnt counter) uint64 {
+ return cnt.count
+ })
+ f.dumpBy("ior-by-duration-collapsed.flamegraph", func(cnt counter) uint64 {
+ return cnt.duration
+ })
+}
+
+func (f Flamegraph) dumpBy(outfile string, by func(counter) uint64) {
+ fmt.Println("Dumping", outfile)
+ file, err := os.Create(outfile)
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ for path, value := range f.collapsed {
+ var sb strings.Builder
+
+ for i, part := range strings.Split(path, "/") {
+ if i > 1 {
+ sb.WriteString(";")
+ sb.WriteString("/")
+ }
+ sb.WriteString(part)
+ }
+
+ for traceId, cnt := range value {
+ _, err := fmt.Fprintf(file, "%s;syscall`%s %v\n", sb.String(), traceId, by(cnt))
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+}