cpu.go 3.0 KB

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