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