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