diff options
| author | Paul Buetow <paul@buetow.org> | 2025-03-11 09:52:30 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-03-11 09:52:30 +0200 |
| commit | f9d8d2d9a107204fddf13b8f60845e817076d1f8 (patch) | |
| tree | b38437d816f589dc18246290c95124fe25962e5e /internal | |
| parent | a7f6f047de1e0ae56a0ef3a4c74e86f4f8f6eeb7 (diff) | |
refactor and initial tree
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/event.go | 96 | ||||
| -rw-r--r-- | internal/event/event.go | 97 | ||||
| -rw-r--r-- | internal/eventfilter.go | 42 | ||||
| -rw-r--r-- | internal/eventloop.go | 98 | ||||
| -rw-r--r-- | internal/file.go | 84 | ||||
| -rw-r--r-- | internal/file/file.go | 84 | ||||
| -rw-r--r-- | internal/flags/flags.go | 2 | ||||
| -rw-r--r-- | internal/ior.go | 2 | ||||
| -rw-r--r-- | internal/tree/tree.go | 12 |
9 files changed, 271 insertions, 246 deletions
diff --git a/internal/event.go b/internal/event.go deleted file mode 100644 index e638223..0000000 --- a/internal/event.go +++ /dev/null @@ -1,96 +0,0 @@ -package internal - -import ( - "fmt" - . "ior/internal/generated/types" - "strconv" - "strings" - "sync" -) - -var poolOfEventPairs = sync.Pool{ - New: func() interface{} { return &eventPair{} }, -} - -type event interface { - String() string - GetTraceId() TraceId - GetPid() uint32 - GetTid() uint32 - GetTime() uint64 - Recycle() -} - -// Represents a pair of enter and exit events (e.g. entering the syscall + exiting it) -type eventPair struct { - enterEv, exitEv event - file file - comm string - duration uint64 - tracepointMismatch bool - - // To calculate the time difference from the previoud event. - prevPair *eventPair - durationToPrev uint64 -} - -func newEventPair(enterEv event) *eventPair { - e := poolOfEventPairs.Get().(*eventPair) - e.enterEv = enterEv - return e -} - -func (e *eventPair) calculateDurations() { - e.duration = e.exitEv.GetTime() - e.enterEv.GetTime() - - if e.prevPair != nil { - e.durationToPrev = e.enterEv.GetTime() - e.prevPair.exitEv.GetTime() - } -} - -func (e *eventPair) is(id TraceId) bool { - return e.enterEv.GetTraceId() == id -} - -const eventStreamHeader = "durationToPrevNs,durationNs,comm,pid.tid,name,ret,notice,file" - -func (e *eventPair) String() string { - var sb strings.Builder - - sb.WriteString(fmt.Sprintf("%08d,%08d", e.durationToPrev, e.duration)) - - sb.WriteString(",") - sb.WriteString(e.comm) - - sb.WriteString(",") - sb.WriteString(strconv.FormatInt(int64(e.enterEv.GetPid()), 10)) - sb.WriteString(".") - sb.WriteString(strconv.FormatInt(int64(e.enterEv.GetTid()), 10)) - - sb.WriteString(",") - sb.WriteString(e.enterEv.GetTraceId().Name()) - - sb.WriteString(",") - if retEv, ok := e.exitEv.(*RetEvent); ok { - sb.WriteString(strconv.FormatInt(int64(retEv.Ret), 10)) - } - - sb.WriteString(",") - sb.WriteString(e.file.String()) - - if e.tracepointMismatch { - sb.WriteString(",MISMATCH") - } - return sb.String() -} - -func (e *eventPair) dump() string { - return fmt.Sprintf("%v with enterEv(%v) and exitEv(%v)", e, e.enterEv, e.exitEv) -} - -func (e *eventPair) recycle() { - e.enterEv.Recycle() - e.exitEv.Recycle() - e.prevPair = nil - poolOfEventPairs.Put(e) -} diff --git a/internal/event/event.go b/internal/event/event.go new file mode 100644 index 0000000..db8028c --- /dev/null +++ b/internal/event/event.go @@ -0,0 +1,97 @@ +package event + +import ( + "fmt" + "ior/internal/file" + . "ior/internal/generated/types" + "strconv" + "strings" + "sync" +) + +var poolOfEventPairs = sync.Pool{ + New: func() interface{} { return &Pair{} }, +} + +type Event interface { + String() string + GetTraceId() TraceId + GetPid() uint32 + GetTid() uint32 + GetTime() uint64 + Recycle() +} + +// Represents a pair of enter and exit events (e.g. entering the syscall + exiting it) +type Pair struct { + EnterEv, ExitEv Event + File file.File + Comm string + duration uint64 + TracepointMismatch bool + + // To calculate the time difference from the previoud event. + PrevPair *Pair + durationToPrev uint64 +} + +func NewPair(enterEv Event) *Pair { + e := poolOfEventPairs.Get().(*Pair) + e.EnterEv = enterEv + return e +} + +func (e *Pair) CalculateDurations() { + e.duration = e.ExitEv.GetTime() - e.EnterEv.GetTime() + + if e.PrevPair != nil { + e.durationToPrev = e.EnterEv.GetTime() - e.PrevPair.ExitEv.GetTime() + } +} + +func (e *Pair) Is(id TraceId) bool { + return e.EnterEv.GetTraceId() == id +} + +const EventStreamHeader = "durationToPrevNs,durationNs,comm,pid.tid,name,ret,notice,file" + +func (e *Pair) String() string { + var sb strings.Builder + + sb.WriteString(fmt.Sprintf("%08d,%08d", e.durationToPrev, e.duration)) + + sb.WriteString(",") + sb.WriteString(e.Comm) + + sb.WriteString(",") + sb.WriteString(strconv.FormatInt(int64(e.EnterEv.GetPid()), 10)) + sb.WriteString(".") + sb.WriteString(strconv.FormatInt(int64(e.EnterEv.GetTid()), 10)) + + sb.WriteString(",") + sb.WriteString(e.EnterEv.GetTraceId().Name()) + + sb.WriteString(",") + if retEv, ok := e.ExitEv.(*RetEvent); ok { + sb.WriteString(strconv.FormatInt(int64(retEv.Ret), 10)) + } + + sb.WriteString(",") + sb.WriteString(e.File.String()) + + if e.TracepointMismatch { + sb.WriteString(",MISMATCH") + } + return sb.String() +} + +func (e *Pair) Dump() string { + return fmt.Sprintf("%v with enterEv(%v) and exitEv(%v)", e, e.EnterEv, e.ExitEv) +} + +func (e *Pair) Recycle() { + e.EnterEv.Recycle() + e.ExitEv.Recycle() + e.PrevPair = nil + poolOfEventPairs.Put(e) +} diff --git a/internal/eventfilter.go b/internal/eventfilter.go index 6975836..d53202f 100644 --- a/internal/eventfilter.go +++ b/internal/eventfilter.go @@ -1,11 +1,15 @@ package internal import ( + "bytes" "fmt" + "ior/internal/event" "ior/internal/flags" "ior/internal/generated/types" + "strings" ) +// TODO: Move to event package type eventFilter struct { commFilterEnable bool commFilterBytes [types.MAX_PROGNAME_LENGTH]byte @@ -39,36 +43,36 @@ func newEventFilter(flags flags.Flags) *eventFilter { return &ef } -func (ef *eventFilter) eventPair(ev *eventPair) bool { - // if ef.commFilterEnable && !strings.Contains(ev.comm, ef.commFilter) { - // return false - // } - // if ef.pathFilterEnable && !strings.Contains(ev.file.Name(), ef.pathFilter) { - // return false - // } +func (ef *eventFilter) eventPair(ev *event.Pair) bool { + if ef.commFilterEnable && !strings.Contains(ev.Comm, ef.commFilter) { + return false + } + if ef.pathFilterEnable && !strings.Contains(ev.File.Name(), ef.pathFilter) { + return false + } return true } func (ef *eventFilter) openEvent(ev *types.OpenEvent) (*types.OpenEvent, bool) { - // if ef.commFilterEnable && !bytes.Contains(ev.Comm[:], ef.commFilterBytes[:]) { - // return ev, false - // } - // if ef.pathFilterEnable && !bytes.Contains(ev.Filename[:], ef.pathFilterBytes[:]) { - // return ev, false - // } + if ef.commFilterEnable && !bytes.Contains(ev.Comm[:], ef.commFilterBytes[:]) { + return ev, false + } + if ef.pathFilterEnable && !bytes.Contains(ev.Filename[:], ef.pathFilterBytes[:]) { + return ev, false + } return ev, true } func (ef *eventFilter) pathEvent(ev *types.PathEvent) (*types.PathEvent, bool) { - // if ef.pathFilterEnable { - // return ev, bytes.Contains(ev.Pathname[:], ef.pathFilterBytes[:]) - // } + if ef.pathFilterEnable { + return ev, bytes.Contains(ev.Pathname[:], ef.pathFilterBytes[:]) + } return ev, true } func (ef *eventFilter) nameEvent(ev *types.NameEvent) (*types.NameEvent, bool) { - // if ef.pathFilterEnable { - // return ev, bytes.Contains(ev.Oldname[:], ef.pathFilterBytes[:]) || bytes.Contains(ev.Newname[:], ef.pathFilterBytes[:]) - // } + if ef.pathFilterEnable { + return ev, bytes.Contains(ev.Oldname[:], ef.pathFilterBytes[:]) || bytes.Contains(ev.Newname[:], ef.pathFilterBytes[:]) + } return ev, true } diff --git a/internal/eventloop.go b/internal/eventloop.go index f94ed6d..7a322a7 100644 --- a/internal/eventloop.go +++ b/internal/eventloop.go @@ -8,6 +8,8 @@ import ( "path/filepath" "time" + "ior/internal/event" + "ior/internal/file" "ior/internal/flags" . "ior/internal/generated/types" "ior/internal/tree" @@ -17,11 +19,11 @@ import ( type eventLoop struct { flags flags.Flags filter *eventFilter - enterEvs map[uint32]*eventPair // Temp. store of sys_enter tracepoints per Tid. - files map[int32]file // Track all open files by file descriptor. - comms map[uint32]string // Program or thread name of the current Tid. - prevPairs map[uint32]*eventPair // Previous event (to calculate time differences between two events) - tree tree.Tree // Storing all paths in a tree structure for analysis + enterEvs map[uint32]*event.Pair // Temp. store of sys_enter tracepoints per Tid. + files map[int32]file.File // Track all open files by file descriptor.. + comms map[uint32]string // Program or thread name of the current Tid. + prevPairs map[uint32]*event.Pair // Previous event (to calculate time differences between two events) + tree tree.Tree // Storing all paths in a tree structure for analysis // Statistics numTracepoints uint @@ -35,10 +37,10 @@ func newEventLoop(flags flags.Flags) *eventLoop { return &eventLoop{ flags: flags, filter: newEventFilter(flags), - enterEvs: make(map[uint32]*eventPair), - files: make(map[int32]file), + enterEvs: make(map[uint32]*event.Pair), + files: make(map[int32]file.File), comms: make(map[uint32]string), - prevPairs: make(map[uint32]*eventPair), + prevPairs: make(map[uint32]*event.Pair), tree: tree.New(), // TODO: Implement } } @@ -60,23 +62,27 @@ func (e *eventLoop) run(rawCh <-chan []byte) { e.startTime = time.Now() if e.flags.PprofEnable { fmt.Println("Profiling, press Ctrl+C to stop") - fmt.Println(eventStreamHeader) + fmt.Println(event.EventStreamHeader) } for ev := range e.events(rawCh) { - if !e.flags.PprofEnable { + switch { + case e.flags.TreeEnable: + // e.tree.Add(ev) + case e.flags.PprofEnable: + default: fmt.Println(ev.String()) } - if ev.prevPair != nil { + if ev.PrevPair != nil { // Only recycle the previous event, as the current event is the previous event of the next event! - ev.prevPair.recycle() + ev.PrevPair.Recycle() continue } e.numSyscallsAfterFilter++ } } -func (e *eventLoop) events(rawCh <-chan []byte) <-chan *eventPair { - ch := make(chan *eventPair) +func (e *eventLoop) events(rawCh <-chan []byte) <-chan *event.Pair { + ch := make(chan *event.Pair) go func() { defer close(ch) @@ -114,87 +120,87 @@ func (e *eventLoop) events(rawCh <-chan []byte) <-chan *eventPair { return ch } -func (e *eventLoop) syscallEnter(enterEv event) { +func (e *eventLoop) syscallEnter(enterEv event.Event) { tid := enterEv.GetTid() if !e.filter.commFilterEnable { - e.enterEvs[tid] = newEventPair(enterEv) + e.enterEvs[tid] = event.NewPair(enterEv) return } switch enterEv.(type) { case *OpenEvent: - e.enterEvs[tid] = newEventPair(enterEv) + e.enterEvs[tid] = event.NewPair(enterEv) default: // Only, when we have a comm name if _, ok := e.comms[tid]; ok { - e.enterEvs[tid] = newEventPair(enterEv) + e.enterEvs[tid] = event.NewPair(enterEv) } } } -func (e *eventLoop) syscallExit(exitEv event, ch chan<- *eventPair) { +func (e *eventLoop) syscallExit(exitEv event.Event, ch chan<- *event.Pair) { ev, ok := e.enterEvs[exitEv.GetTid()] if !ok { exitEv.Recycle() return } delete(e.enterEvs, exitEv.GetTid()) - ev.exitEv = exitEv + ev.ExitEv = exitEv // Expect ID one lower, otherwise, enter and exit tracepoints // don't match up. E.g.: // enterEv:SYS_ENTER_OPEN => exitEv:SYS_EXIT_OPEN - if ev.enterEv.GetTraceId()-1 != ev.exitEv.GetTraceId() { - ev.tracepointMismatch = true + if ev.EnterEv.GetTraceId()-1 != ev.ExitEv.GetTraceId() { + ev.TracepointMismatch = true e.numTracepointMismatches++ } else { e.numSyscalls++ } - switch v := ev.enterEv.(type) { + switch v := ev.EnterEv.(type) { case *OpenEvent: - openEv := ev.enterEv.(*OpenEvent) + openEv := ev.EnterEv.(*OpenEvent) - fd := int32(ev.exitEv.(*RetEvent).Ret) - file := newFdFile(fd, string(openEv.Filename[:])) + fd := int32(ev.ExitEv.(*RetEvent).Ret) + file := file.NewFd(fd, string(openEv.Filename[:])) if fd >= 0 { e.files[fd] = file } - ev.file = file + ev.File = file e.comms[openEv.Tid] = string(openEv.Comm[:]) case *NameEvent: - nameEvent := ev.enterEv.(*NameEvent) - ev.file = oldnameNewnameFile{ - oldname: string(nameEvent.Oldname[:]), - newname: string(nameEvent.Newname[:]), + nameEvent := ev.EnterEv.(*NameEvent) + ev.File = file.OldnameNewnameFile{ + Oldname: string(nameEvent.Oldname[:]), + Newname: string(nameEvent.Newname[:]), } - ev.comm = e.comm(ev.enterEv.GetTid()) + ev.Comm = e.comm(ev.EnterEv.GetTid()) case *PathEvent: - nameEvent := ev.enterEv.(*PathEvent) - ev.file = pathnameFile{string(nameEvent.Pathname[:])} - ev.comm = e.comm(ev.enterEv.GetTid()) + nameEvent := ev.EnterEv.(*PathEvent) + ev.File = file.PathnameFile{string(nameEvent.Pathname[:])} + ev.Comm = e.comm(ev.EnterEv.GetTid()) case *FdEvent: - fd := ev.enterEv.(*FdEvent).Fd + fd := ev.EnterEv.(*FdEvent).Fd if file_, ok := e.files[fd]; ok { - ev.file = file_ - if ev.is(SYS_ENTER_CLOSE) { + ev.File = file_ + if ev.Is(SYS_ENTER_CLOSE) { delete(e.files, fd) } } else { - ev.file = newFdFileWithPid(fd, ev.enterEv.(*FdEvent).Pid) + ev.File = file.NewFdWithPid(fd, ev.EnterEv.(*FdEvent).Pid) } - ev.comm = e.comm(ev.enterEv.GetTid()) + ev.Comm = e.comm(ev.EnterEv.GetTid()) if !e.filter.eventPair(ev) { - ev.recycle() + ev.Recycle() return } case *NullEvent: - ev.comm = e.comm(ev.enterEv.GetTid()) + ev.Comm = e.comm(ev.EnterEv.GetTid()) if !e.filter.eventPair(ev) { - ev.recycle() + ev.Recycle() return } @@ -202,9 +208,9 @@ func (e *eventLoop) syscallExit(exitEv event, ch chan<- *eventPair) { panic(fmt.Sprintf("unknown type: %v", v)) } - ev.prevPair, _ = e.prevPairs[ev.enterEv.GetTid()] - ev.calculateDurations() - e.prevPairs[ev.enterEv.GetTid()] = ev + ev.PrevPair, _ = e.prevPairs[ev.EnterEv.GetTid()] + ev.CalculateDurations() + e.prevPairs[ev.EnterEv.GetTid()] = ev ch <- ev } diff --git a/internal/file.go b/internal/file.go deleted file mode 100644 index fe519ba..0000000 --- a/internal/file.go +++ /dev/null @@ -1,84 +0,0 @@ -package internal - -import ( - "fmt" - "os" - "strconv" - "strings" -) - -type file interface { - String() string - Name() string -} - -type fdFile struct { - fd int32 - name string -} - -func newFdFile(fd int32, name string) fdFile { - return fdFile{fd, name} -} - -func newFdFileWithPid(fd int32, pid uint32) fdFile { - if linkName, err := os.Readlink(fmt.Sprintf("/proc/%d/fd/%d", pid, fd)); err == nil { - return fdFile{fd, linkName} - } - return fdFile{fd, "?"} -} - -func (f fdFile) Name() string { - return f.name -} - -func (f fdFile) String() string { - var sb strings.Builder - - if len(f.name) == 0 { - sb.WriteString("?") - } else { - sb.WriteString(f.name) - sb.WriteString(" (") - sb.WriteString(strconv.FormatInt(int64(f.fd), 10)) - sb.WriteString(")") - } - - return sb.String() -} - -type oldnameNewnameFile struct { - oldname, newname string -} - -func (f oldnameNewnameFile) Name() string { - return f.newname -} - -func (f oldnameNewnameFile) String() string { - var sb strings.Builder - - sb.WriteString("old:") - sb.WriteString(f.oldname) - sb.WriteString(" ->new:") - sb.WriteString(f.newname) - - return sb.String() -} - -type pathnameFile struct { - pathname string -} - -func (f pathnameFile) Name() string { - return f.pathname -} - -func (f pathnameFile) String() string { - var sb strings.Builder - - sb.WriteString("pathname:") - sb.WriteString(f.pathname) - - return sb.String() -} diff --git a/internal/file/file.go b/internal/file/file.go new file mode 100644 index 0000000..4d9afab --- /dev/null +++ b/internal/file/file.go @@ -0,0 +1,84 @@ +package file + +import ( + "fmt" + "os" + "strconv" + "strings" +) + +type File interface { + String() string + Name() string +} + +type FdFile struct { + fd int32 + name string +} + +func NewFd(fd int32, name string) FdFile { + return FdFile{fd, name} +} + +func NewFdWithPid(fd int32, pid uint32) FdFile { + if linkName, err := os.Readlink(fmt.Sprintf("/proc/%d/fd/%d", pid, fd)); err == nil { + return FdFile{fd, linkName} + } + return FdFile{fd, "?"} +} + +func (f FdFile) Name() string { + return f.name +} + +func (f FdFile) String() string { + var sb strings.Builder + + if len(f.name) == 0 { + sb.WriteString("?") + } else { + sb.WriteString(f.name) + sb.WriteString(" (") + sb.WriteString(strconv.FormatInt(int64(f.fd), 10)) + sb.WriteString(")") + } + + return sb.String() +} + +type OldnameNewnameFile struct { + Oldname, Newname string +} + +func (f OldnameNewnameFile) Name() string { + return f.Newname +} + +func (f OldnameNewnameFile) String() string { + var sb strings.Builder + + sb.WriteString("old:") + sb.WriteString(f.Oldname) + sb.WriteString(" ->new:") + sb.WriteString(f.Newname) + + return sb.String() +} + +type PathnameFile struct { + Pathname string +} + +func (f PathnameFile) Name() string { + return f.Pathname +} + +func (f PathnameFile) String() string { + var sb strings.Builder + + sb.WriteString("pathname:") + sb.WriteString(f.Pathname) + + return sb.String() +} diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 51bca07..29e4372 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -14,6 +14,7 @@ type Flags struct { CommFilter string PathFilter string PprofEnable bool + TreeEnable bool } func New() (flags Flags) { @@ -23,6 +24,7 @@ func New() (flags Flags) { flag.StringVar(&flags.CommFilter, "comm", "", "Command to filter for") flag.StringVar(&flags.PathFilter, "path", "", "Path to filter for") flag.BoolVar(&flags.PprofEnable, "pprof", false, "Enable profiling") + flag.BoolVar(&flags.TreeEnable, "tree", false, "Enable tree builder") flag.Parse() return flags diff --git a/internal/ior.go b/internal/ior.go index 1f62eea..6d73011 100644 --- a/internal/ior.go +++ b/internal/ior.go @@ -83,12 +83,12 @@ func Run(flags flags.Flags) { go func() { <-c fmt.Println(loop.stats()) - fmt.Println("Good bye...") if flags.PprofEnable { fmt.Println("Stoppig profiling, writing ior.cpuprofile and ior.memprofile") pprof.StopCPUProfile() pprof.WriteHeapProfile(memProfile) } + fmt.Println("Good bye... (unloading BPF tracepoints will take a few seconds...)") os.Exit(0) }() diff --git a/internal/tree/tree.go b/internal/tree/tree.go new file mode 100644 index 0000000..462ba19 --- /dev/null +++ b/internal/tree/tree.go @@ -0,0 +1,12 @@ +package tree + +type Tree struct { +} + +func New() Tree { + return Tree{} +} + +// func (t Tree) Add(ev *) { + +// } |
