io.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package cgroup
  2. import (
  3. "io/ioutil"
  4. "path"
  5. "strconv"
  6. "strings"
  7. "k8s.io/klog/v2"
  8. )
  9. type IOStat struct {
  10. ReadOps uint64
  11. WriteOps uint64
  12. ReadBytes uint64
  13. WrittenBytes uint64
  14. }
  15. func (cg *Cgroup) IOStat() (map[string]IOStat, error) {
  16. if cg.Version == V1 {
  17. return cg.ioStatV1()
  18. }
  19. return cg.ioStatV2()
  20. }
  21. func (cg *Cgroup) ioStatV1() (map[string]IOStat, error) {
  22. ops, err := readBlkioStatFile(path.Join(cgRoot, "blkio", cg.subsystems["blkio"], "blkio.throttle.io_serviced"))
  23. if err != nil {
  24. return nil, err
  25. }
  26. bytes, err := readBlkioStatFile(path.Join(cgRoot, "blkio", cg.subsystems["blkio"], "blkio.throttle.io_service_bytes"))
  27. if err != nil {
  28. return nil, err
  29. }
  30. res := map[string]IOStat{}
  31. for _, v := range ops {
  32. stat := res[v.majorMinor]
  33. switch v.name {
  34. case "Read":
  35. stat.ReadOps = v.value
  36. case "Write":
  37. stat.WriteOps = v.value
  38. }
  39. res[v.majorMinor] = stat
  40. }
  41. for _, v := range bytes {
  42. stat := res[v.majorMinor]
  43. switch v.name {
  44. case "Read":
  45. stat.ReadBytes = v.value
  46. case "Write":
  47. stat.WrittenBytes = v.value
  48. }
  49. res[v.majorMinor] = stat
  50. }
  51. return res, nil
  52. }
  53. func (cg *Cgroup) ioStatV2() (map[string]IOStat, error) {
  54. payload, err := ioutil.ReadFile(path.Join(cgRoot, cg.subsystems[""], "io.stat"))
  55. if err != nil {
  56. return nil, err
  57. }
  58. res := map[string]IOStat{}
  59. for _, line := range strings.Split(string(payload), "\n") {
  60. parts := strings.Fields(line)
  61. if len(parts) < 5 {
  62. continue
  63. }
  64. s := IOStat{}
  65. for _, value := range parts[1:] {
  66. if kv := strings.SplitN(value, "=", 2); len(kv) == 2 {
  67. v, err := strconv.ParseUint(kv[1], 10, 64)
  68. if err != nil {
  69. continue
  70. }
  71. switch kv[0] {
  72. case "rbytes":
  73. s.ReadBytes = v
  74. case "wbytes":
  75. s.WrittenBytes = v
  76. case "rios":
  77. s.ReadOps = v
  78. case "wios":
  79. s.WriteOps = v
  80. }
  81. }
  82. }
  83. res[parts[0]] = s
  84. }
  85. return res, nil
  86. }
  87. type blkioVariable struct {
  88. majorMinor string
  89. name string
  90. value uint64
  91. }
  92. func readBlkioStatFile(filePath string) ([]blkioVariable, error) {
  93. data, err := ioutil.ReadFile(filePath)
  94. if err != nil {
  95. return nil, err
  96. }
  97. var res []blkioVariable
  98. for _, line := range strings.Split(string(data), "\n") {
  99. parts := strings.Fields(line)
  100. if len(parts) != 3 {
  101. continue
  102. }
  103. v, err := strconv.ParseUint(parts[2], 10, 64)
  104. if err != nil {
  105. klog.Warningf(`failed to parse blkio stat line "%s": %s`, line, err)
  106. continue
  107. }
  108. res = append(res, blkioVariable{
  109. majorMinor: parts[0],
  110. name: parts[1],
  111. value: v,
  112. })
  113. }
  114. return res, nil
  115. }