Read number of running processes from /proc/loadavg.

Fallback to using sysinfo syscall if failed.

Fix kubernetes#107107
This commit is contained in:
Eric Lin 2021-12-17 16:15:28 +00:00
parent 712745cb67
commit 5fdf24baca

View File

@ -20,12 +20,14 @@ limitations under the License.
package pidlimit package pidlimit
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"strconv" "strconv"
"strings"
"syscall" "syscall"
"time" "time"
"k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
) )
@ -39,12 +41,36 @@ func Stats() (*statsapi.RlimitStats, error) {
} }
} }
// 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 var info syscall.Sysinfo_t
syscall.Sysinfo(&info) syscall.Sysinfo(&info)
procs := int64(info.Procs) procs := int64(info.Procs)
rlimit.NumOfRunningProcesses = &procs rlimit.NumOfRunningProcesses = &procs
}
rlimit.Time = v1.NewTime(time.Now()) rlimit.Time = v1.NewTime(time.Now())
return rlimit, nil 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)
}