github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/stats/collector_unix.go (about)

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