collector_unix.go 1.8 KB

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