Skip to content

Commit

Permalink
feature(proctree): add name to processes and threads
Browse files Browse the repository at this point in the history
- Also: avoid duplicate entries in changelog
  • Loading branch information
rafaeldtinoco committed Sep 13, 2023
1 parent 45e337d commit ab5e285
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 31 deletions.
17 changes: 16 additions & 1 deletion pkg/changelog/changelog.go
Expand Up @@ -15,7 +15,16 @@ type item[T any] struct {
// the outside world as it is not thread-safe.

type Changelog[T any] struct {
changes []item[T] // list of changes
changes []item[T] // list of changes
timestamps map[time.Time]struct{} // set of timestamps (used to avoid duplicates)
}

// NewChangelog creates a new changelog.
func NewChangelog[T any]() *Changelog[T] {
return &Changelog[T]{
changes: []item[T]{},
timestamps: map[time.Time]struct{}{},
}
}

// Getters
Expand Down Expand Up @@ -89,6 +98,10 @@ func (clv *Changelog[T]) Set(value T, targetTime time.Time) {

// setAt sets the value of the changelog at the given time.
func (clv *Changelog[T]) setAt(value T, targetTime time.Time) {
if _, ok := clv.timestamps[targetTime]; ok {
return // already set
}

entry := item[T]{
timestamp: targetTime,
value: value,
Expand All @@ -98,6 +111,8 @@ func (clv *Changelog[T]) setAt(value T, targetTime time.Time) {
clv.changes = append(clv.changes, item[T]{})
copy(clv.changes[idx+1:], clv.changes[idx:])
clv.changes[idx] = entry

clv.timestamps[targetTime] = struct{}{} // mark timestamp as set
}

// findIndex returns the index of the first item in the changelog that is after the given time.
Expand Down
8 changes: 4 additions & 4 deletions pkg/changelog/changelog_test.go
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestChangelog(t *testing.T) {
cl := &Changelog[int]{}
cl := NewChangelog[int]()

// Test GetCurrent on an empty changelog
if cl.GetCurrent() != 0 {
Expand All @@ -22,15 +22,15 @@ func TestChangelog(t *testing.T) {

// Test Get on an empty changelog

cl = &Changelog[int]{}
cl = NewChangelog[int]()

if cl.Get(time.Now()) != 0 {
t.Errorf("Get on empty changelog should return 0")
}

// Test 1 second interval among changes

cl = &Changelog[int]{}
cl = NewChangelog[int]()

cl.SetCurrent(1)
time.Sleep(2 * time.Second)
Expand All @@ -53,7 +53,7 @@ func TestChangelog(t *testing.T) {
// Test 100 milliseconds interval among changes
// NOTE: If this test becomes flaky we can change/remove it.

cl = &Changelog[int]{}
cl = NewChangelog[int]()

cl.SetCurrent(1)
time.Sleep(100 * time.Millisecond)
Expand Down
14 changes: 6 additions & 8 deletions pkg/proctree/fileinfo.go
Expand Up @@ -18,16 +18,14 @@ type FileInfoFeed struct {
// File Info
//

// TODO: Add Changelog to the file info variables (just like Task Info).

// FileInfo represents a file.
type FileInfo struct {
name string
path string
dev int
ctime int
inode int
inodeMode int
name string // file name
path string // file path
dev int // device number of the file
ctime int // creation time of the file
inode int // inode number of the file
inodeMode int // inode mode of the file
mutex *sync.RWMutex
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/proctree/proctree_feed.go
Expand Up @@ -86,6 +86,7 @@ func (pt *ProcessTree) FeedFromFork(feed ForkFeed) error {
leader = pt.GetOrCreateProcessByHash(feed.LeaderHash)
leader.GetInfo().SetFeedAt(
TaskInfoFeed{
Name: parent.GetInfo().GetName(),
Tid: int(feed.LeaderTid),
Pid: int(feed.LeaderPid),
NsTid: int(feed.LeaderNsTid),
Expand Down Expand Up @@ -115,6 +116,7 @@ func (pt *ProcessTree) FeedFromFork(feed ForkFeed) error {
thread := pt.GetOrCreateThreadByHash(feed.ChildHash)
thread.GetInfo().SetFeedAt(
TaskInfoFeed{
Name: leader.GetInfo().GetName(),
Tid: int(feed.ChildTid),
Pid: int(feed.ChildPid),
NsTid: int(feed.ChildNsTid),
Expand Down Expand Up @@ -199,6 +201,7 @@ func (pt *ProcessTree) FeedFromExec(feed ExecFeed) error {
return nil
}

process.GetInfo().SetNameAt(feed.CmdPath, utils.NsSinceBootTimeToTime(feed.TimeStamp))
process.GetExecutable().SetFeed(
FileInfoFeed{
Name: feed.CmdPath,
Expand Down
4 changes: 2 additions & 2 deletions pkg/proctree/proctree_output.go
Expand Up @@ -79,7 +79,7 @@ func (pt *ProcessTree) String() string {
// Use tablewriter to print the tree in a table
newTable := func() *tablewriter.Table {
table := tablewriter.NewWriter(buffer)
table.SetHeader([]string{"Ppid", "Tid", "Pid", "Date", "CMD", "Children", "Threads"})
table.SetHeader([]string{"Ppid", "Tid", "Pid", "Date", "Comm", "Children", "Threads"})
// If debug() is enabled:
// table.SetHeader([]string{"Ppid", "Tid", "Pid", "StartTime", "Hash", "CMD", "Children", "Threads"})
table.SetAutoWrapText(false)
Expand Down Expand Up @@ -107,7 +107,7 @@ func (pt *ProcessTree) String() string {

// create a row for the table
processFeed := process.GetInfo().GetFeed()
execName := process.GetExecutable().GetName()
execName := processFeed.Name
if len(execName) > 25 {
execName = execName[:20] + "..."
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/proctree/proctree_procfs.go
Expand Up @@ -73,6 +73,7 @@ func (pt *ProcessTree) FeedFromProcFS(givenPid int) error {
procInfo := process.GetInfo()
procInfo.SetFeed(
TaskInfoFeed{
Name: status.GetName(),
Tid: int(status.GetPid()), // status: pid == tid
Pid: int(status.GetTgid()), // status: tgid == pid
PPid: int(status.GetPPid()), // status: ppid == ppid
Expand All @@ -84,7 +85,6 @@ func (pt *ProcessTree) FeedFromProcFS(givenPid int) error {
StartTimeNS: startTimeNs,
},
)
process.GetExecutable().SetName(status.GetName())

// update given process parent (if exists)
parent, err := getProcessByPID(status.GetPPid())
Expand Down
64 changes: 49 additions & 15 deletions pkg/proctree/taskinfo.go
Expand Up @@ -10,6 +10,7 @@ import (

// TaskInfoFeed allows external packages to set/get multiple values of a task at once.
type TaskInfoFeed struct {
Name string
Tid int
Pid int
PPid int
Expand All @@ -28,27 +29,28 @@ type TaskInfoFeed struct {

// TaskInfo represents a task.
type TaskInfo struct {
// TODO: Put Comm in here and not inside the file info.
tid int // immutable
pid int // immutable
pPid *ch.Changelog[int] // variable (process can be reparented)
nsTid int // immutable
nsPid int // immutable
nsPPid *ch.Changelog[int] // variable (process can be reparented)
uid *ch.Changelog[int] // variable (process uid can be changed)
gid *ch.Changelog[int] // variable (process gid can be changed)
startTimeNS uint64 // this is a duration, in ns, since boot (immutable)
exitTimeNS uint64 // this is a duration, in ns, since boot (immutable)
name *ch.Changelog[string] // variable (process name can be changed)
tid int // immutable
pid int // immutable
pPid *ch.Changelog[int] // variable (process can be reparented)
nsTid int // immutable
nsPid int // immutable
nsPPid *ch.Changelog[int] // variable (process can be reparented)
uid *ch.Changelog[int] // variable (process uid can be changed)
gid *ch.Changelog[int] // variable (process gid can be changed)
startTimeNS uint64 // this is a duration, in ns, since boot (immutable)
exitTimeNS uint64 // this is a duration, in ns, since boot (immutable)
mutex *sync.RWMutex
}

// NewTaskInfo creates a new task.
func NewTaskInfo() *TaskInfo {
return &TaskInfo{
pPid: &ch.Changelog[int]{},
nsPPid: &ch.Changelog[int]{},
uid: &ch.Changelog[int]{},
gid: &ch.Changelog[int]{},
name: ch.NewChangelog[string](),
pPid: ch.NewChangelog[int](),
nsPPid: ch.NewChangelog[int](),
uid: ch.NewChangelog[int](),
gid: ch.NewChangelog[int](),
mutex: &sync.RWMutex{},
}
}
Expand Down Expand Up @@ -78,6 +80,9 @@ func (ti *TaskInfo) SetFeedAt(feed TaskInfoFeed, targetTime time.Time) {

// setFeedAt sets the values of the task from the given feed at the given time.
func (ti *TaskInfo) setFeedAt(feed TaskInfoFeed, targetTime time.Time) {
if feed.Name != "" {
ti.name.Set(feed.Name, targetTime)
}
if feed.Tid > 0 {
ti.tid = feed.Tid
}
Expand Down Expand Up @@ -126,6 +131,7 @@ func (ti *TaskInfo) GetFeedAt(targetTime time.Time) TaskInfoFeed {

func (ti *TaskInfo) getFeedAt(targetTime time.Time) TaskInfoFeed {
return TaskInfoFeed{
Name: ti.name.Get(targetTime),
Tid: ti.tid,
Pid: ti.pid,
PPid: ti.pPid.Get(targetTime),
Expand All @@ -141,6 +147,20 @@ func (ti *TaskInfo) getFeedAt(targetTime time.Time) TaskInfoFeed {

// Setters

// SetName sets the name of the task.
func (ti *TaskInfo) SetName(name string) {
ti.mutex.Lock()
defer ti.mutex.Unlock()
ti.name.Set(name, time.Now())
}

// SetNameAt sets the name of the task at the given time.
func (ti *TaskInfo) SetNameAt(name string, targetTime time.Time) {
ti.mutex.Lock()
defer ti.mutex.Unlock()
ti.name.Set(name, targetTime)
}

// SetTid sets the tid of the task.
func (ti *TaskInfo) SetTid(tid int) {
ti.mutex.Lock()
Expand Down Expand Up @@ -241,6 +261,20 @@ func (ti *TaskInfo) SetGidAt(gid int, targetTime time.Time) {

// Getters

// GetName returns the name of the task.
func (ti *TaskInfo) GetName() string {
ti.mutex.RLock()
defer ti.mutex.RUnlock()
return ti.name.GetCurrent()
}

// GetNameAt returns the name of the task at the given time.
func (ti *TaskInfo) GetNameAt(targetTime time.Time) string {
ti.mutex.RLock()
defer ti.mutex.RUnlock()
return ti.name.Get(targetTime)
}

// GetTid returns the tid of the task.
func (ti *TaskInfo) GetTid() int {
ti.mutex.RLock()
Expand Down

0 comments on commit ab5e285

Please sign in to comment.