in metric/system/process/process_linux_common.go [380:421]
func getCPUTime(hostfs resolve.Resolver, pid int) (ProcCPUInfo, error) {
state := ProcCPUInfo{}
pathCPU := hostfs.Join("proc", strconv.Itoa(pid), "stat")
data, err := os.ReadFile(pathCPU)
if err != nil {
return state, fmt.Errorf("error opening file %s: %w", pathCPU, err)
}
fields := strings.Fields(string(data))
user, err := strconv.ParseUint(fields[13], 10, 64)
if err != nil {
return state, fmt.Errorf("error parsing user CPU times for pid %d: %w", pid, err)
}
sys, err := strconv.ParseUint(fields[14], 10, 64)
if err != nil {
return state, fmt.Errorf("error parsing system CPU times for pid %d: %w", pid, err)
}
btime, err := getLinuxBootTime(hostfs)
if err != nil {
return state, fmt.Errorf("error feting boot time for pid %d: %w", pid, err)
}
// convert to milliseconds from USER_HZ
// This effectively means our definition of "ticks" throughout the process code is a millisecond
state.User.Ticks = opt.UintWith(user * (1000 / ticks))
state.System.Ticks = opt.UintWith(sys * (1000 / ticks))
state.Total.Ticks = opt.UintWith(opt.SumOptUint(state.User.Ticks, state.System.Ticks))
startTime, err := strconv.ParseUint(fields[21], 10, 64)
if err != nil {
return state, fmt.Errorf("error parsing start time value %s for pid %d: %w", fields[21], pid, err)
}
startTime /= ticks
startTime += btime
startTime *= 1000
state.StartTime = unixTimeMsToTime(startTime)
return state, nil
}