collector_unix.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. // +build !windows,!solaris
  2. package stats
  3. import (
  4. "fmt"
  5. "os"
  6. "strconv"
  7. "strings"
  8. "github.com/opencontainers/runc/libcontainer/system"
  9. )
  10. // platformNewStatsCollector performs platform specific initialisation of the
  11. // Collector structure.
  12. func platformNewStatsCollector(s *Collector) {
  13. s.clockTicksPerSecond = uint64(system.GetClockTicks())
  14. }
  15. const nanoSecondsPerSecond = 1e9
  16. // getSystemCPUUsage returns the host system's cpu usage in
  17. // nanoseconds. An error is returned if the format of the underlying
  18. // file does not match.
  19. //
  20. // Uses /proc/stat defined by POSIX. Looks for the cpu
  21. // statistics line and then sums up the first seven fields
  22. // provided. See `man 5 proc` for details on specific field
  23. // information.
  24. func (s *Collector) getSystemCPUUsage() (uint64, error) {
  25. var line string
  26. f, err := os.Open("/proc/stat")
  27. if err != nil {
  28. return 0, err
  29. }
  30. defer func() {
  31. s.bufReader.Reset(nil)
  32. f.Close()
  33. }()
  34. s.bufReader.Reset(f)
  35. err = nil
  36. for err == nil {
  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. s.clockTicksPerSecond, nil
  57. }
  58. }
  59. return 0, fmt.Errorf("invalid stat format. Error trying to parse the '/proc/stat' file")
  60. }