summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-03-14 23:41:54 +0200
committerPaul Buetow <paul@buetow.org>2025-03-14 23:41:54 +0200
commit5cac6a84181a6121e27c5c763a3e34254180fa4b (patch)
tree83bf76348990052452d38d3feacc20f757b27695 /internal
parent3edde70ef17d23a3f2fcb0fac11a50e8810ab943 (diff)
parallel rite collapsed flamegraphs
Diffstat (limited to 'internal')
-rw-r--r--internal/eventloop.go12
-rw-r--r--internal/file/file.go18
-rw-r--r--internal/flamegraph/flamegraph.go21
3 files changed, 32 insertions, 19 deletions
diff --git a/internal/eventloop.go b/internal/eventloop.go
index 1e7fea6..11a184d 100644
--- a/internal/eventloop.go
+++ b/internal/eventloop.go
@@ -3,7 +3,6 @@ package internal
import "C"
import (
- "bytes"
"context"
"fmt"
"os"
@@ -181,9 +180,7 @@ func (e *eventLoop) syscallExit(exitEv event.Event, ch chan<- *event.Pair) {
fd := int32(ev.ExitEv.(*RetEvent).Ret)
// It's from an array, so only create string from array until first 0 byte
// TODO: This could speed up the path filter as well
- // TODO: Hopefully, this won't cause a panic when the filename is as long as the array itself
- filePath := string(openEv.Filename[:bytes.IndexByte(openEv.Filename[:], 0)])
- file := file.NewFd(fd, filePath)
+ file := file.NewFd(fd, openEv.Filename[:])
if fd >= 0 {
e.files[fd] = file
}
@@ -192,15 +189,12 @@ func (e *eventLoop) syscallExit(exitEv event.Event, ch chan<- *event.Pair) {
case *NameEvent:
nameEvent := ev.EnterEv.(*NameEvent)
- ev.File = file.OldnameNewnameFile{
- Oldname: string(nameEvent.Oldname[:]),
- Newname: string(nameEvent.Newname[:]),
- }
+ ev.File = file.NewOldnameNewname(nameEvent.Oldname[:], nameEvent.Newname[:])
ev.Comm = e.comm(ev.EnterEv.GetTid())
case *PathEvent:
nameEvent := ev.EnterEv.(*PathEvent)
- ev.File = file.PathnameFile{Pathname: string(nameEvent.Pathname[:])}
+ ev.File = file.NewPathname(nameEvent.Pathname[:])
ev.Comm = e.comm(ev.EnterEv.GetTid())
case *FdEvent:
diff --git a/internal/file/file.go b/internal/file/file.go
index 4d9afab..a9de8d3 100644
--- a/internal/file/file.go
+++ b/internal/file/file.go
@@ -1,6 +1,7 @@
package file
import (
+ "bytes"
"fmt"
"os"
"strconv"
@@ -17,8 +18,8 @@ type FdFile struct {
name string
}
-func NewFd(fd int32, name string) FdFile {
- return FdFile{fd, name}
+func NewFd(fd int32, name []byte) FdFile {
+ return FdFile{fd, stringValue(name)}
}
func NewFdWithPid(fd int32, pid uint32) FdFile {
@@ -51,6 +52,10 @@ type OldnameNewnameFile struct {
Oldname, Newname string
}
+func NewOldnameNewname(oldname, newname []byte) OldnameNewnameFile {
+ return OldnameNewnameFile{stringValue(oldname), stringValue(newname)}
+}
+
func (f OldnameNewnameFile) Name() string {
return f.Newname
}
@@ -70,6 +75,10 @@ type PathnameFile struct {
Pathname string
}
+func NewPathname(pathname []byte) PathnameFile {
+ return PathnameFile{stringValue(pathname)}
+}
+
func (f PathnameFile) Name() string {
return f.Pathname
}
@@ -82,3 +91,8 @@ func (f PathnameFile) String() string {
return sb.String()
}
+
+func stringValue(byteStr []byte) string {
+ // TODO: Hopefully, this won't cause a panic when the filename is as long as the array itself
+ return string(byteStr[:bytes.IndexByte(byteStr, 0)])
+}
diff --git a/internal/flamegraph/flamegraph.go b/internal/flamegraph/flamegraph.go
index 9e15889..6c5df63 100644
--- a/internal/flamegraph/flamegraph.go
+++ b/internal/flamegraph/flamegraph.go
@@ -7,6 +7,7 @@ import (
"ior/internal/generated/types"
"os"
"strings"
+ "sync"
"time"
)
@@ -18,8 +19,6 @@ type counter struct {
// TODO: Profile for CPU usage. If too slow, can fan out into multiple maps and
// then merge at the end the maps.
type Flamegraph struct {
- // TODO: Keep al lthe individual files at the leaf in a map as well.
- // And when dumped, only dump the N "highest" and summarize the other ones.
collapsed map[string]map[types.TraceId]counter
inCh chan *event.Pair
Done chan struct{}
@@ -74,21 +73,28 @@ func (f Flamegraph) Add(ev *event.Pair) {
}
func (f Flamegraph) dump() {
- f.dumpBy("ior-by-path-count-flamegraph.collapsed", true, func(cnt counter) uint64 {
+ var wg sync.WaitGroup
+ wg.Add(4)
+
+ go f.dumpBy(&wg, "ior-by-path-count-flamegraph.collapsed", true, func(cnt counter) uint64 {
return cnt.count
})
- f.dumpBy("ior-by-path-duration-flamegraph.collapsed", true, func(cnt counter) uint64 {
+ go f.dumpBy(&wg, "ior-by-path-duration-flamegraph.collapsed", true, func(cnt counter) uint64 {
return cnt.duration
})
- f.dumpBy("ior-by-syscall-count-flamegraph.collapsed", false, func(cnt counter) uint64 {
+ go f.dumpBy(&wg, "ior-by-syscall-count-flamegraph.collapsed", false, func(cnt counter) uint64 {
return cnt.count
})
- f.dumpBy("ior-by-syscall-duration-flamegraph.collapsed", false, func(cnt counter) uint64 {
+ go f.dumpBy(&wg, "ior-by-syscall-duration-flamegraph.collapsed", false, func(cnt counter) uint64 {
return cnt.duration
})
+
+ wg.Wait()
}
-func (f Flamegraph) dumpBy(outfile string, syscallAtTop bool, by func(counter) uint64) {
+func (f Flamegraph) dumpBy(wg *sync.WaitGroup, outfile string, syscallAtTop bool, by func(counter) uint64) {
+ defer wg.Done()
+
fmt.Println("Dumping", outfile)
file, err := os.Create(outfile)
if err != nil {
@@ -105,7 +111,6 @@ func (f Flamegraph) dumpBy(outfile string, syscallAtTop bool, by func(counter) u
sb.WriteString("/")
}
sb.WriteString(part)
- fmt.Println("DEBUG part", i, part, len(part))
}
for traceId, cnt := range value {