summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-04-06 21:27:31 +0300
committerPaul Buetow <paul@buetow.org>2025-04-06 21:27:31 +0300
commit6ca3491f421e8506fa3ff832a51b3a7d8a5c7ef6 (patch)
tree701d955b507929c8cb4b21c2fd40fe1ca12f3b0c
parent70d0c28c24dd7b69b3d711574574f8b2a1d8ad0c (diff)
initial dumping in new ior data format
-rw-r--r--cmd/ior/main.go9
-rw-r--r--internal/event/event.go18
-rw-r--r--internal/flags/flags.go4
-rw-r--r--internal/flamegraph/collapsed.go97
-rw-r--r--internal/flamegraph/flamegraph.go24
-rw-r--r--internal/flamegraph/iordata.go23
-rw-r--r--internal/flamegraph/iordata_test.go4
-rw-r--r--internal/flamegraph/worker.go60
8 files changed, 45 insertions, 194 deletions
diff --git a/cmd/ior/main.go b/cmd/ior/main.go
index 0f243f7..5e82283 100644
--- a/cmd/ior/main.go
+++ b/cmd/ior/main.go
@@ -1,8 +1,8 @@
package main
import (
- "flag"
"ior/internal"
+ "ior/internal/flags"
"log"
"runtime"
)
@@ -13,13 +13,12 @@ func main() {
if runtime.GOOS != "linux" {
log.Fatal("Unsupported OS")
}
-
+
// Parse command-line flags
- flag.Parse()
-
+ flags.Parse()
+
// Run the internal logic of the application
if err := internal.Run(); err != nil {
log.Fatalf("Failed to run: %v", err)
}
}
-
diff --git a/internal/event/event.go b/internal/event/event.go
index f835aaf..684761a 100644
--- a/internal/event/event.go
+++ b/internal/event/event.go
@@ -28,9 +28,7 @@ type Pair struct {
File file.File
Comm string
Duration uint64
-
- // To calculate the time difference from the previoud event.
- DurationToPrev uint64
+ DurationToPrev uint64
}
func NewPair(enterEv Event) *Pair {
@@ -83,6 +81,20 @@ func (e *Pair) String() string {
return sb.String()
}
+func (e *Pair) FlagsString() string {
+ if e.File == nil {
+ return "N:flags"
+ }
+ return e.File.FlagsString()
+}
+
+func (e *Pair) FileName() string {
+ if e.File == nil {
+ return "N:file"
+ }
+ return e.File.Name()
+}
+
func (e *Pair) Dump() string {
return fmt.Sprintf("%v with enterEv(%v) and exitEv(%v)", e, e.EnterEv, e.ExitEv)
}
diff --git a/internal/flags/flags.go b/internal/flags/flags.go
index c971335..91bceb3 100644
--- a/internal/flags/flags.go
+++ b/internal/flags/flags.go
@@ -33,7 +33,7 @@ type Flags struct {
// Flamegraph flags
FlamegraphEnable bool
- FlamegraphName string // If set, enables new style iorData output, TODO: remove comment once old style collapsed format is retired
+ FlamegraphName string
}
func Parse() {
@@ -57,7 +57,7 @@ func parse() {
tracepointsToExclude := flag.String("tpsExclude", "", "Comma separated list regexes for tracepoints to exclude")
flag.BoolVar(&singleton.FlamegraphEnable, "flamegraph", false, "Enable flamegraph builder")
- flag.StringVar(&singleton.FlamegraphName, "name", "", "Name of the flamegraph data output")
+ flag.StringVar(&singleton.FlamegraphName, "name", "foo", "Name of the flamegraph data output")
flag.Parse()
singleton.TracepointsToAttach = extractTracepointFlags(*tracepointsToAttach)
diff --git a/internal/flamegraph/collapsed.go b/internal/flamegraph/collapsed.go
deleted file mode 100644
index 60c0b7f..0000000
--- a/internal/flamegraph/collapsed.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package flamegraph
-
-import (
- "fmt"
- "ior/internal/types"
- "os"
- "strings"
- "sync"
-)
-
-type collapsedCounter struct {
- count uint64
- duration uint64
-}
-
-func (c *collapsedCounter) add(other collapsedCounter) {
- c.count += other.count
- c.duration += other.duration
-}
-
-// TODO: Clean up all code commented with COLLAPSED once collapsed here retired.
-type collapsed map[string]map[types.TraceId]collapsedCounter
-
-func (c collapsed) merge(other collapsed) (merged int) {
- for k, v := range other {
- if _, ok := c[k]; !ok {
- c[k] = make(map[types.TraceId]collapsedCounter)
- }
- for traceId, cnt := range v {
- if existingCnt, ok := c[k][traceId]; ok {
- existingCnt.add(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 collapsedCounter) uint64 {
- return cnt.count
- })
- go c.dumpBy(&wg, "ior-by-path-duration-flamegraph.collapsed", true, func(cnt collapsedCounter) uint64 {
- return cnt.duration
- })
- go c.dumpBy(&wg, "ior-by-syscall-count-flamegraph.collapsed", false, func(cnt collapsedCounter) uint64 {
- return cnt.count
- })
- go c.dumpBy(&wg, "ior-by-syscall-duration-flamegraph.collapsed", false, func(cnt collapsedCounter) uint64 {
- return cnt.duration
- })
-
- wg.Wait()
-}
-
-func (c collapsed) dumpBy(wg *sync.WaitGroup, outfile string, syscallAtTop bool, by func(collapsedCounter) uint64) {
- defer wg.Done()
-
- defer fmt.Println("Dumping 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)
- }
- }
- }
-}
diff --git a/internal/flamegraph/flamegraph.go b/internal/flamegraph/flamegraph.go
index aeb5143..9772f0c 100644
--- a/internal/flamegraph/flamegraph.go
+++ b/internal/flamegraph/flamegraph.go
@@ -5,6 +5,7 @@ import (
"fmt"
"ior/internal/event"
"ior/internal/flags"
+ "log"
"runtime"
"sync"
)
@@ -41,24 +42,19 @@ func (f Flamegraph) Start(ctx context.Context) {
for i, worker := range f.workers {
fmt.Println("Starting flamegraph worker", i)
- if flags.Get().FlamegraphName == "" { // Empty string means: old style collapsed
- go worker.runCollapsed(ctx, &wg, f.Ch)
- } else {
- go worker.run(ctx, &wg, f.Ch)
- }
+ go worker.run(ctx, &wg, f.Ch)
}
wg.Wait()
- // COLLAPSED: Will be removed, once migrated to iorData
- if f.flags.FlamegraphName == "" { // Empty string means: old style collapsed
- collapsed := f.workers[0].collapsed
- if len(f.workers) > 1 {
- for i, c := range f.workers[1:] {
- fmt.Println("Worker", i+1, "merged", collapsed.merge(c.collapsed),
- "counters =>", len(collapsed), "total counters")
- }
+ iod := f.workers[0].iod
+ if len(f.workers) > 1 {
+ for i, w := range f.workers[1:] {
+ iod = iod.merge(w.iod)
+ fmt.Println("Worker", i+1, "merged")
}
- collapsed.dump()
+ }
+ if err := iod.commit(); err != nil {
+ log.Fatal(err)
}
}()
}
diff --git a/internal/flamegraph/iordata.go b/internal/flamegraph/iordata.go
index 77b03aa..1cf1f0a 100644
--- a/internal/flamegraph/iordata.go
+++ b/internal/flamegraph/iordata.go
@@ -24,7 +24,6 @@ type iorData struct {
paths pathMap
}
-// TODO: Flag to enable iorData
// TODO: Name flag for iorData (outfile format: hostname-name-timestamp.ior.zst)
// TODO: Output path for iorData flag
// TODO: Add helper to convert .ior data file to collapsed format
@@ -32,25 +31,10 @@ func newIorData() iorData {
return iorData{paths: make(pathMap)}
}
-// TODO: Unit test
func (iod iorData) add(ev *event.Pair) {
- // type Pair struct {
- // EnterEv, ExitEv Event
- // File file.File
- // Comm string
- // Duration uint64
-
- // // To calculate the time difference from the previoud event.
- // PrevPair *Pair
- // durationToPrev uint64
- // }
- cnt := counter{
- count: 1,
- duration: ev.Duration,
- durationToPrev: ev.DurationToPrev,
- }
- iod.addPath(ev.File.Name(), ev.EnterEv.GetTraceId(), ev.Comm,
- ev.EnterEv.GetPid(), ev.EnterEv.GetTid(), ev.File.FlagsString(), cnt)
+ cnt := counter{count: 1, duration: ev.Duration, durationToPrev: ev.DurationToPrev}
+ iod.addPath(ev.FileName(), ev.EnterEv.GetTraceId(), ev.Comm, ev.EnterEv.GetPid(),
+ ev.EnterEv.GetTid(), ev.FlagsString(), cnt)
}
func (iod iorData) addPath(path pathType, traceId traceIdType, comm commType,
@@ -129,6 +113,7 @@ func (iod iorData) commit() error {
filename := fmt.Sprintf("%s-%s-%s.ior.zst", hostname, flags.Get().FlamegraphName,
time.Now().Format("2006-01-02_15:04:05"))
+
file, err := os.Create(filename)
if err != nil {
return err
diff --git a/internal/flamegraph/iordata_test.go b/internal/flamegraph/iordata_test.go
index 8a6c5e0..f938a49 100644
--- a/internal/flamegraph/iordata_test.go
+++ b/internal/flamegraph/iordata_test.go
@@ -4,6 +4,10 @@ import (
"testing"
)
+func TestAdd(t *testring.T) {
+
+}
+
func TestAddPath(t *testing.T) {
iod := newIorData()
path := pathType("testPath")
diff --git a/internal/flamegraph/worker.go b/internal/flamegraph/worker.go
index e47329e..a24be6d 100644
--- a/internal/flamegraph/worker.go
+++ b/internal/flamegraph/worker.go
@@ -2,23 +2,19 @@ package flamegraph
import (
"context"
+ "fmt"
"ior/internal/event"
- "ior/internal/types"
"sync"
"time"
)
type worker struct {
- collapsed collapsed
- iod iorData
- done chan struct{}
+ iod iorData
+ done chan struct{}
}
func newWorker() worker {
- return worker{
- collapsed: make(collapsed), // COLLAPSED: Retire ocne newIorData implemented
- iod: newIorData(), // TODO: make flags global, so i don't have to pass them through the whole code base
- }
+ return worker{iod: newIorData()}
}
func (w worker) run(ctx context.Context, wg *sync.WaitGroup, ch <-chan *event.Pair) {
@@ -27,12 +23,8 @@ func (w worker) run(ctx context.Context, wg *sync.WaitGroup, ch <-chan *event.Pa
for {
select {
case ev := <-ch:
- // var filePath string
- // if ev.File == nil {
- // filePath = "N:file"
- // } else {
- // filePath = ev.File.Name()
- // }
+ fmt.Println("worker got event", ev)
+ w.iod.add(ev)
ev.Recycle()
default:
@@ -45,43 +37,3 @@ func (w worker) run(ctx context.Context, wg *sync.WaitGroup, ch <-chan *event.Pa
}
}
}
-
-// TODO: Retire collapsed
-func (w worker) runCollapsed(ctx context.Context, wg *sync.WaitGroup, ch <-chan *event.Pair) {
- {
- defer wg.Done()
-
- for {
- select {
- case ev := <-ch:
- var filePath string
- if ev.File == nil {
- filePath = "N:file"
- } else {
- filePath = ev.File.Name()
- }
- pathMap, ok := w.collapsed[filePath]
- if !ok {
- pathMap = make(map[types.TraceId]collapsedCounter)
- }
-
- traceId := ev.EnterEv.GetTraceId()
- cnt := pathMap[traceId]
- cnt.count++
- cnt.duration += ev.Duration
- pathMap[traceId] = cnt
-
- w.collapsed[filePath] = pathMap
- ev.Recycle()
-
- default:
- select {
- case <-ctx.Done():
- return
- default:
- time.Sleep(time.Millisecond * 10)
- }
- }
- }
- }
-}