...

Source file src/k8s.io/kubernetes/pkg/kubelet/stats/pidlimit/pidlimit_linux.go

Documentation: k8s.io/kubernetes/pkg/kubelet/stats/pidlimit

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2017 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package pidlimit
    21  
    22  import (
    23  	"fmt"
    24  	"os"
    25  	"strconv"
    26  	"strings"
    27  	"syscall"
    28  	"time"
    29  
    30  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
    32  )
    33  
    34  // Stats provides basic information about max and current process count
    35  func Stats() (*statsapi.RlimitStats, error) {
    36  	rlimit := &statsapi.RlimitStats{}
    37  
    38  	taskMax := int64(-1)
    39  	// Calculate the minimum of kernel.pid_max and kernel.threads-max as they both specify the
    40  	// system-wide limit on the number of tasks.
    41  	for _, file := range []string{"/proc/sys/kernel/pid_max", "/proc/sys/kernel/threads-max"} {
    42  		if content, err := os.ReadFile(file); err == nil {
    43  			if limit, err := strconv.ParseInt(string(content[:len(content)-1]), 10, 64); err == nil {
    44  				if taskMax == -1 || taskMax > limit {
    45  					taskMax = limit
    46  				}
    47  			}
    48  		}
    49  	}
    50  	// Both reads did not fail.
    51  	if taskMax >= 0 {
    52  		rlimit.MaxPID = &taskMax
    53  	}
    54  
    55  	// Prefer to read "/proc/loadavg" when possible because sysinfo(2)
    56  	// returns truncated number when greater than 65538. See
    57  	// https://github.com/kubernetes/kubernetes/issues/107107
    58  	if procs, err := runningTaskCount(); err == nil {
    59  		rlimit.NumOfRunningProcesses = &procs
    60  	} else {
    61  		var info syscall.Sysinfo_t
    62  		syscall.Sysinfo(&info)
    63  		procs := int64(info.Procs)
    64  		rlimit.NumOfRunningProcesses = &procs
    65  	}
    66  
    67  	rlimit.Time = v1.NewTime(time.Now())
    68  
    69  	return rlimit, nil
    70  }
    71  
    72  func runningTaskCount() (int64, error) {
    73  	// Example: 1.36 3.49 4.53 2/3518 3715089
    74  	bytes, err := os.ReadFile("/proc/loadavg")
    75  	if err != nil {
    76  		return 0, err
    77  	}
    78  	fields := strings.Fields(string(bytes))
    79  	if len(fields) < 5 {
    80  		return 0, fmt.Errorf("not enough fields in /proc/loadavg")
    81  	}
    82  	subfields := strings.Split(fields[3], "/")
    83  	if len(subfields) != 2 {
    84  		return 0, fmt.Errorf("error parsing fourth field of /proc/loadavg")
    85  	}
    86  	return strconv.ParseInt(subfields[1], 10, 64)
    87  }
    88  

View as plain text