cpu.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // +build linux
  2. package fs
  3. import (
  4. "bufio"
  5. "os"
  6. "path/filepath"
  7. "strconv"
  8. "github.com/opencontainers/runc/libcontainer/cgroups"
  9. "github.com/opencontainers/runc/libcontainer/configs"
  10. )
  11. type CpuGroup struct {
  12. }
  13. func (s *CpuGroup) Name() string {
  14. return "cpu"
  15. }
  16. func (s *CpuGroup) Apply(d *cgroupData) error {
  17. // We always want to join the cpu group, to allow fair cpu scheduling
  18. // on a container basis
  19. path, err := d.path("cpu")
  20. if err != nil && !cgroups.IsNotFound(err) {
  21. return err
  22. }
  23. return s.ApplyDir(path, d.config, d.pid)
  24. }
  25. func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error {
  26. // This might happen if we have no cpu cgroup mounted.
  27. // Just do nothing and don't fail.
  28. if path == "" {
  29. return nil
  30. }
  31. if err := os.MkdirAll(path, 0755); err != nil {
  32. return err
  33. }
  34. // We should set the real-Time group scheduling settings before moving
  35. // in the process because if the process is already in SCHED_RR mode
  36. // and no RT bandwidth is set, adding it will fail.
  37. if err := s.SetRtSched(path, cgroup); err != nil {
  38. return err
  39. }
  40. // because we are not using d.join we need to place the pid into the procs file
  41. // unlike the other subsystems
  42. return cgroups.WriteCgroupProc(path, pid)
  43. }
  44. func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error {
  45. if cgroup.Resources.CpuRtPeriod != 0 {
  46. if err := writeFile(path, "cpu.rt_period_us", strconv.FormatUint(cgroup.Resources.CpuRtPeriod, 10)); err != nil {
  47. return err
  48. }
  49. }
  50. if cgroup.Resources.CpuRtRuntime != 0 {
  51. if err := writeFile(path, "cpu.rt_runtime_us", strconv.FormatInt(cgroup.Resources.CpuRtRuntime, 10)); err != nil {
  52. return err
  53. }
  54. }
  55. return nil
  56. }
  57. func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error {
  58. if cgroup.Resources.CpuShares != 0 {
  59. if err := writeFile(path, "cpu.shares", strconv.FormatUint(cgroup.Resources.CpuShares, 10)); err != nil {
  60. return err
  61. }
  62. }
  63. if cgroup.Resources.CpuPeriod != 0 {
  64. if err := writeFile(path, "cpu.cfs_period_us", strconv.FormatUint(cgroup.Resources.CpuPeriod, 10)); err != nil {
  65. return err
  66. }
  67. }
  68. if cgroup.Resources.CpuQuota != 0 {
  69. if err := writeFile(path, "cpu.cfs_quota_us", strconv.FormatInt(cgroup.Resources.CpuQuota, 10)); err != nil {
  70. return err
  71. }
  72. }
  73. return s.SetRtSched(path, cgroup)
  74. }
  75. func (s *CpuGroup) Remove(d *cgroupData) error {
  76. return removePath(d.path("cpu"))
  77. }
  78. func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error {
  79. f, err := os.Open(filepath.Join(path, "cpu.stat"))
  80. if err != nil {
  81. if os.IsNotExist(err) {
  82. return nil
  83. }
  84. return err
  85. }
  86. defer f.Close()
  87. sc := bufio.NewScanner(f)
  88. for sc.Scan() {
  89. t, v, err := getCgroupParamKeyValue(sc.Text())
  90. if err != nil {
  91. return err
  92. }
  93. switch t {
  94. case "nr_periods":
  95. stats.CpuStats.ThrottlingData.Periods = v
  96. case "nr_throttled":
  97. stats.CpuStats.ThrottlingData.ThrottledPeriods = v
  98. case "throttled_time":
  99. stats.CpuStats.ThrottlingData.ThrottledTime = v
  100. }
  101. }
  102. return nil
  103. }