summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/event.go96
-rw-r--r--internal/event/event.go97
-rw-r--r--internal/eventfilter.go42
-rw-r--r--internal/eventloop.go98
-rw-r--r--internal/file.go84
-rw-r--r--internal/file/file.go84
-rw-r--r--internal/flags/flags.go2
-rw-r--r--internal/ior.go2
-rw-r--r--internal/tree/tree.go12
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 *) {
+
+// }