diff --git a/containers/container.go b/containers/container.go index 0dbaa79..4ae85b2 100644 --- a/containers/container.go +++ b/containers/container.go @@ -485,12 +485,12 @@ func (c *Container) ensureProcess(pid uint32) *Process { func (c *Container) onProcessStart(pid uint32) *Process { c.lock.Lock() defer c.lock.Unlock() - stats, err := TaskstatsPID(pid) - if err != nil { + startedAt := proc.GetStartTime(pid) + if startedAt.IsZero() { return nil } c.zombieAt = time.Time{} - p := NewProcess(pid, stats, c.registry.tracer) + p := NewProcess(pid, startedAt, c.registry.tracer) if p == nil { return nil @@ -498,9 +498,9 @@ func (c *Container) onProcessStart(pid uint32) *Process { c.processes[pid] = p if c.startedAt.IsZero() { - c.startedAt = stats.BeginTime + c.startedAt = startedAt } else { - min := stats.BeginTime + min := startedAt for _, p := range c.processes { if p.StartedAt.Before(min) { min = p.StartedAt diff --git a/containers/process.go b/containers/process.go index 1ad79eb..bb22151 100644 --- a/containers/process.go +++ b/containers/process.go @@ -14,7 +14,6 @@ import ( "github.com/coroot/coroot-node-agent/gpu" "github.com/coroot/coroot-node-agent/proc" "github.com/jpillora/backoff" - "github.com/mdlayher/taskstats" ) type GpuUsage struct { @@ -66,8 +65,8 @@ type inboundHttp2State struct { connTimestamp uint64 } -func NewProcess(pid uint32, stats *taskstats.Stats, tracer *ebpftracer.Tracer) *Process { - p := &Process{Pid: pid, StartedAt: stats.BeginTime, tracer: tracer, instrumentDone: make(chan struct{})} +func NewProcess(pid uint32, startedAt time.Time, tracer *ebpftracer.Tracer) *Process { + p := &Process{Pid: pid, StartedAt: startedAt, tracer: tracer, instrumentDone: make(chan struct{})} p.Flags, _ = proc.GetFlags(pid) p.ctx, p.cancelFunc = context.WithCancel(context.Background()) go p.instrument(tracer) diff --git a/containers/taskstats.go b/containers/taskstats.go index 25a645f..3ea9dff 100644 --- a/containers/taskstats.go +++ b/containers/taskstats.go @@ -33,16 +33,3 @@ func TaskstatsTGID(pid uint32) (*taskstats.Stats, error) { } return s, nil } - -func TaskstatsPID(pid uint32) (*taskstats.Stats, error) { - if taskstatsClient == nil { - return nil, fmt.Errorf("taskstats client not initialized") - } - taskstatsLock.Lock() - defer taskstatsLock.Unlock() - s, err := taskstatsClient.PID(int(pid)) - if err != nil { - return nil, err - } - return s, nil -} diff --git a/proc/proc.go b/proc/proc.go index c51348b..df00a6b 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -8,11 +8,28 @@ import ( "path" "strconv" "strings" + "time" "github.com/coroot/coroot-node-agent/cgroup" ) -var root = "/proc" +var ( + root = "/proc" + bootTime int64 +) + +func init() { + data, err := os.ReadFile(root + "/stat") + if err != nil { + return + } + for _, line := range strings.Split(string(data), "\n") { + if fields := strings.Fields(line); len(fields) == 2 && fields[0] == "btime" { + bootTime, _ = strconv.ParseInt(fields[1], 10, 64) + return + } + } +} func Path(pid uint32, subpath ...string) string { return path.Join(append([]string{root, strconv.Itoa(int(pid))}, subpath...)...) @@ -64,6 +81,27 @@ func ReadCgroup(pid uint32) (*cgroup.Cgroup, error) { return cgroup.NewFromProcessCgroupFile(Path(pid, "cgroup")) } +func GetStartTime(pid uint32) time.Time { + data, err := os.ReadFile(Path(pid, "stat")) + if err != nil { + return time.Time{} + } + s := string(data) + idx := strings.LastIndex(s, ")") + if idx < 0 { + return time.Time{} + } + fields := strings.Fields(s[idx+1:]) + if len(fields) < 20 { + return time.Time{} + } + startTicks, err := strconv.ParseUint(fields[19], 10, 64) + if err != nil || bootTime == 0 { + return time.Time{} + } + return time.Unix(bootTime+int64(float64(startTicks)/100), 0) +} + func ListPids() ([]uint32, error) { root, err := os.Open(root) if err != nil {