github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/sys/cpu_linux.go (about)

     1  // Package sys provides methods to read system information
     2  /*
     3   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package sys
     6  
     7  import (
     8  	"errors"
     9  	"io"
    10  	"runtime"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/NVIDIA/aistore/cmn/cos"
    15  	"github.com/NVIDIA/aistore/cmn/nlog"
    16  )
    17  
    18  // isContainerized returns true if the application is running
    19  // inside a container(docker/lxc/k8s)
    20  //
    21  // How to detect being inside a container:
    22  // https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker
    23  func isContainerized() (yes bool) {
    24  	err := cos.ReadLines(rootProcess, func(line string) error {
    25  		if strings.Contains(line, "docker") || strings.Contains(line, "lxc") || strings.Contains(line, "kube") {
    26  			yes = true
    27  			return io.EOF
    28  		}
    29  		return nil
    30  	})
    31  	if err != nil {
    32  		nlog.Errorf("Failed to read system info: %v", err)
    33  	}
    34  	return
    35  }
    36  
    37  // Returns an approximate number of CPUs allocated for the container.
    38  // By default, container runs without limits and its cfs_quota_us is
    39  // negative (-1). When a container starts with limited CPU usage its quota
    40  // is between 0.01 CPU and the number of CPUs on the host machine.
    41  // The function rounds up the calculated number.
    42  func containerNumCPU() (int, error) {
    43  	var quota, period uint64
    44  
    45  	quotaInt, err := cos.ReadOneInt64(contCPULimit)
    46  	if err != nil {
    47  		return 0, err
    48  	}
    49  	// negative quota means 'unlimited' - all hardware CPUs are used
    50  	if quotaInt <= 0 {
    51  		return runtime.NumCPU(), nil
    52  	}
    53  	quota = uint64(quotaInt)
    54  	period, err = cos.ReadOneUint64(contCPUPeriod)
    55  	if err != nil {
    56  		return 0, err
    57  	}
    58  
    59  	if period == 0 {
    60  		return 0, errors.New("failed to read container CPU info")
    61  	}
    62  
    63  	approx := (quota + period - 1) / period
    64  	return int(max(approx, 1)), nil
    65  }
    66  
    67  // LoadAverage returns the system load average
    68  func LoadAverage() (avg LoadAvg, err error) {
    69  	avg = LoadAvg{}
    70  
    71  	line, err := cos.ReadOneLine(hostLoadAvgPath)
    72  	if err != nil {
    73  		return avg, err
    74  	}
    75  
    76  	fields := strings.Fields(line)
    77  	avg.One, err = strconv.ParseFloat(fields[0], 64)
    78  	if err == nil {
    79  		avg.Five, err = strconv.ParseFloat(fields[1], 64)
    80  	}
    81  	if err == nil {
    82  		avg.Fifteen, err = strconv.ParseFloat(fields[2], 64)
    83  	}
    84  
    85  	return avg, err
    86  }