collector_unix.go 1.8 KB

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