123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- // +build !windows
- package stats // import "github.com/docker/docker/daemon/stats"
- import (
- "fmt"
- "os"
- "strconv"
- "strings"
- "golang.org/x/sys/unix"
- )
- const (
- // The value comes from `C.sysconf(C._SC_CLK_TCK)`, and
- // on Linux it's a constant which is safe to be hard coded,
- // so we can avoid using cgo here. For details, see:
- // https://github.com/containerd/cgroups/pull/12
- clockTicksPerSecond = 100
- nanoSecondsPerSecond = 1e9
- )
- // getSystemCPUUsage returns the host system's cpu usage in
- // nanoseconds. An error is returned if the format of the underlying
- // file does not match.
- //
- // Uses /proc/stat defined by POSIX. Looks for the cpu
- // statistics line and then sums up the first seven fields
- // provided. See `man 5 proc` for details on specific field
- // information.
- func (s *Collector) getSystemCPUUsage() (uint64, error) {
- f, err := os.Open("/proc/stat")
- if err != nil {
- return 0, err
- }
- defer func() {
- s.bufReader.Reset(nil)
- f.Close()
- }()
- s.bufReader.Reset(f)
- for {
- line, err := s.bufReader.ReadString('\n')
- if err != nil {
- break
- }
- parts := strings.Fields(line)
- switch parts[0] {
- case "cpu":
- if len(parts) < 8 {
- return 0, fmt.Errorf("invalid number of cpu fields")
- }
- var totalClockTicks uint64
- for _, i := range parts[1:8] {
- v, err := strconv.ParseUint(i, 10, 64)
- if err != nil {
- return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
- }
- totalClockTicks += v
- }
- return (totalClockTicks * nanoSecondsPerSecond) /
- clockTicksPerSecond, nil
- }
- }
- return 0, fmt.Errorf("invalid stat format. Error trying to parse the '/proc/stat' file")
- }
- func (s *Collector) getNumberOnlineCPUs() (uint32, error) {
- var cpuset unix.CPUSet
- err := unix.SchedGetaffinity(0, &cpuset)
- if err != nil {
- return 0, err
- }
- return uint32(cpuset.Count()), nil
- }
|