diff options
| author | Paul Buetow <paul@buetow.org> | 2025-03-18 22:25:27 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-03-18 22:25:27 +0200 |
| commit | 6010e057e2d0593a6c6b50f4c7aee301a86a478a (patch) | |
| tree | e8018323e426477fb41e938538f25c4e7df4fce3 /internal/flamegraph/collapsed.go | |
| parent | 000891ad475c89d88874d4290728857ecbe53a7d (diff) | |
workers are parallelized now
Diffstat (limited to 'internal/flamegraph/collapsed.go')
| -rw-r--r-- | internal/flamegraph/collapsed.go | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/internal/flamegraph/collapsed.go b/internal/flamegraph/collapsed.go new file mode 100644 index 0000000..f61d917 --- /dev/null +++ b/internal/flamegraph/collapsed.go @@ -0,0 +1,95 @@ +package flamegraph + +import ( + "fmt" + "ior/internal/types" + "os" + "strings" + "sync" +) + +type counter struct { + count uint64 + duration uint64 +} + +func (c *counter) merge(other counter) { + c.count += other.count + c.duration += other.duration +} + +type collapsed map[string]map[types.TraceId]counter + +// TODO: Unit test this +func (c collapsed) merge(other collapsed) (merged int) { + for k, v := range other { + if _, ok := c[k]; !ok { + c[k] = make(map[types.TraceId]counter) + } + for traceId, cnt := range v { + if existingCnt, ok := c[k][traceId]; ok { + existingCnt.merge(cnt) + merged++ + c[k][traceId] = existingCnt + continue + } + c[k][traceId] = cnt + } + } + return +} + +func (c collapsed) dump() { + var wg sync.WaitGroup + wg.Add(4) + + go c.dumpBy(&wg, "ior-by-path-count-flamegraph.collapsed", true, func(cnt counter) uint64 { + return cnt.count + }) + go c.dumpBy(&wg, "ior-by-path-duration-flamegraph.collapsed", true, func(cnt counter) uint64 { + return cnt.duration + }) + go c.dumpBy(&wg, "ior-by-syscall-count-flamegraph.collapsed", false, func(cnt counter) uint64 { + return cnt.count + }) + go c.dumpBy(&wg, "ior-by-syscall-duration-flamegraph.collapsed", false, func(cnt counter) uint64 { + return cnt.duration + }) + + wg.Wait() +} + +func (c collapsed) 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 { + panic(err) + } + defer file.Close() + + for path, value := range c { + 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 { + var err error + if syscallAtTop { + _, err = fmt.Fprintf(file, "%s;syscall`%s %v\n", sb.String(), traceId.Name(), by(cnt)) + } else { + _, err = fmt.Fprintf(file, "syscall`%s;%s %v\n", traceId.Name(), sb.String(), by(cnt)) + } + if err != nil { + panic(err) + } + } + } +} |
