cgroup_linux.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package internal
  2. import (
  3. "fmt"
  4. "os"
  5. "path"
  6. "strconv"
  7. "strings"
  8. "github.com/tal-tech/go-zero/core/iox"
  9. "github.com/tal-tech/go-zero/core/lang"
  10. )
  11. const cgroupDir = "/sys/fs/cgroup"
  12. type cgroup struct {
  13. cgroups map[string]string
  14. }
  15. func (c *cgroup) acctUsageAllCpus() (uint64, error) {
  16. data, err := iox.ReadText(path.Join(c.cgroups["cpuacct"], "cpuacct.usage"))
  17. if err != nil {
  18. return 0, err
  19. }
  20. return parseUint(string(data))
  21. }
  22. func (c *cgroup) acctUsagePerCpu() ([]uint64, error) {
  23. data, err := iox.ReadText(path.Join(c.cgroups["cpuacct"], "cpuacct.usage_percpu"))
  24. if err != nil {
  25. return nil, err
  26. }
  27. var usage []uint64
  28. for _, v := range strings.Fields(string(data)) {
  29. u, err := parseUint(v)
  30. if err != nil {
  31. return nil, err
  32. }
  33. usage = append(usage, u)
  34. }
  35. return usage, nil
  36. }
  37. func (c *cgroup) cpuQuotaUs() (int64, error) {
  38. data, err := iox.ReadText(path.Join(c.cgroups["cpu"], "cpu.cfs_quota_us"))
  39. if err != nil {
  40. return 0, err
  41. }
  42. return strconv.ParseInt(string(data), 10, 64)
  43. }
  44. func (c *cgroup) cpuPeriodUs() (uint64, error) {
  45. data, err := iox.ReadText(path.Join(c.cgroups["cpu"], "cpu.cfs_period_us"))
  46. if err != nil {
  47. return 0, err
  48. }
  49. return parseUint(string(data))
  50. }
  51. func (c *cgroup) cpus() ([]uint64, error) {
  52. data, err := iox.ReadText(path.Join(c.cgroups["cpuset"], "cpuset.cpus"))
  53. if err != nil {
  54. return nil, err
  55. }
  56. return parseUints(string(data))
  57. }
  58. func currentCgroup() (*cgroup, error) {
  59. cgroupFile := fmt.Sprintf("/proc/%d/cgroup", os.Getpid())
  60. lines, err := iox.ReadTextLines(cgroupFile, iox.WithoutBlank())
  61. if err != nil {
  62. return nil, err
  63. }
  64. cgroups := make(map[string]string)
  65. for _, line := range lines {
  66. cols := strings.Split(line, ":")
  67. if len(cols) != 3 {
  68. return nil, fmt.Errorf("invalid cgroup line: %s", line)
  69. }
  70. subsys := cols[1]
  71. // only read cpu staff
  72. if !strings.HasPrefix(subsys, "cpu") {
  73. continue
  74. }
  75. // https://man7.org/linux/man-pages/man7/cgroups.7.html
  76. // comma-separated list of controllers for cgroup version 1
  77. fields := strings.Split(subsys, ",")
  78. for _, val := range fields {
  79. cgroups[val] = path.Join(cgroupDir, val)
  80. }
  81. }
  82. return &cgroup{
  83. cgroups: cgroups,
  84. }, nil
  85. }
  86. func parseUint(s string) (uint64, error) {
  87. v, err := strconv.ParseInt(s, 10, 64)
  88. if err != nil {
  89. if err.(*strconv.NumError).Err == strconv.ErrRange {
  90. return 0, nil
  91. }
  92. return 0, fmt.Errorf("cgroup: bad int format: %s", s)
  93. }
  94. if v < 0 {
  95. return 0, nil
  96. }
  97. return uint64(v), nil
  98. }
  99. func parseUints(val string) ([]uint64, error) {
  100. if val == "" {
  101. return nil, nil
  102. }
  103. ints := make(map[uint64]lang.PlaceholderType)
  104. cols := strings.Split(val, ",")
  105. for _, r := range cols {
  106. if strings.Contains(r, "-") {
  107. fields := strings.SplitN(r, "-", 2)
  108. min, err := parseUint(fields[0])
  109. if err != nil {
  110. return nil, fmt.Errorf("cgroup: bad int list format: %s", val)
  111. }
  112. max, err := parseUint(fields[1])
  113. if err != nil {
  114. return nil, fmt.Errorf("cgroup: bad int list format: %s", val)
  115. }
  116. if max < min {
  117. return nil, fmt.Errorf("cgroup: bad int list format: %s", val)
  118. }
  119. for i := min; i <= max; i++ {
  120. ints[i] = lang.Placeholder
  121. }
  122. } else {
  123. v, err := parseUint(r)
  124. if err != nil {
  125. return nil, err
  126. }
  127. ints[v] = lang.Placeholder
  128. }
  129. }
  130. var sets []uint64
  131. for k := range ints {
  132. sets = append(sets, k)
  133. }
  134. return sets, nil
  135. }