diff --git a/pkg/kubelet/stats/pidlimit/pidlimit_linux.go b/pkg/kubelet/stats/pidlimit/pidlimit_linux.go index d900be7f9fa..5ee620fdc83 100644 --- a/pkg/kubelet/stats/pidlimit/pidlimit_linux.go +++ b/pkg/kubelet/stats/pidlimit/pidlimit_linux.go @@ -20,8 +20,10 @@ limitations under the License. package pidlimit import ( + "fmt" "io/ioutil" "strconv" + "strings" "syscall" "time" @@ -50,12 +52,36 @@ func Stats() (*statsapi.RlimitStats, error) { rlimit.MaxPID = &taskMax } - var info syscall.Sysinfo_t - syscall.Sysinfo(&info) - procs := int64(info.Procs) - rlimit.NumOfRunningProcesses = &procs + // Prefer to read "/proc/loadavg" when possible because sysinfo(2) + // returns truncated number when greater than 65538. See + // https://github.com/kubernetes/kubernetes/issues/107107 + if procs, err := runningTaskCount(); err == nil { + rlimit.NumOfRunningProcesses = &procs + } else { + var info syscall.Sysinfo_t + syscall.Sysinfo(&info) + procs := int64(info.Procs) + rlimit.NumOfRunningProcesses = &procs + } rlimit.Time = v1.NewTime(time.Now()) return rlimit, nil } + +func runningTaskCount() (int64, error) { + // Example: 1.36 3.49 4.53 2/3518 3715089 + bytes, err := ioutil.ReadFile("/proc/loadavg") + if err != nil { + return 0, err + } + fields := strings.Fields(string(bytes)) + if len(fields) < 5 { + return 0, fmt.Errorf("not enough fields in /proc/loadavg") + } + subfields := strings.Split(fields[3], "/") + if len(subfields) != 2 { + return 0, fmt.Errorf("error parsing fourth field of /proc/loadavg") + } + return strconv.ParseInt(subfields[1], 10, 64) +}