github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/stats/collector_unix.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package stats // import "github.com/docker/docker/daemon/stats"
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  const (
    16  	// The value comes from `C.sysconf(C._SC_CLK_TCK)`, and
    17  	// on Linux it's a constant which is safe to be hard coded,
    18  	// so we can avoid using cgo here. For details, see:
    19  	// https://github.com/containerd/cgroups/pull/12
    20  	clockTicksPerSecond  = 100
    21  	nanoSecondsPerSecond = 1e9
    22  )
    23  
    24  // getSystemCPUUsage returns the host system's cpu usage in
    25  // nanoseconds. An error is returned if the format of the underlying
    26  // file does not match.
    27  //
    28  // Uses /proc/stat defined by POSIX. Looks for the cpu
    29  // statistics line and then sums up the first seven fields
    30  // provided. See `man 5 proc` for details on specific field
    31  // information.
    32  func (s *Collector) getSystemCPUUsage() (uint64, error) {
    33  	f, err := os.Open("/proc/stat")
    34  	if err != nil {
    35  		return 0, err
    36  	}
    37  	defer func() {
    38  		s.bufReader.Reset(nil)
    39  		f.Close()
    40  	}()
    41  	s.bufReader.Reset(f)
    42  
    43  	for {
    44  		line, err := s.bufReader.ReadString('\n')
    45  		if err != nil {
    46  			break
    47  		}
    48  		parts := strings.Fields(line)
    49  		switch parts[0] {
    50  		case "cpu":
    51  			if len(parts) < 8 {
    52  				return 0, fmt.Errorf("invalid number of cpu fields")
    53  			}
    54  			var totalClockTicks uint64
    55  			for _, i := range parts[1:8] {
    56  				v, err := strconv.ParseUint(i, 10, 64)
    57  				if err != nil {
    58  					return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
    59  				}
    60  				totalClockTicks += v
    61  			}
    62  			return (totalClockTicks * nanoSecondsPerSecond) /
    63  				clockTicksPerSecond, nil
    64  		}
    65  	}
    66  	return 0, fmt.Errorf("invalid stat format. Error trying to parse the '/proc/stat' file")
    67  }
    68  
    69  func (s *Collector) getNumberOnlineCPUs() (uint32, error) {
    70  	var cpuset unix.CPUSet
    71  	err := unix.SchedGetaffinity(0, &cpuset)
    72  	if err != nil {
    73  		return 0, err
    74  	}
    75  	return uint32(cpuset.Count()), nil
    76  }