123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package internal
- import (
- "fmt"
- "os"
- "path"
- "strconv"
- "strings"
- "github.com/tal-tech/go-zero/core/iox"
- "github.com/tal-tech/go-zero/core/lang"
- )
- const cgroupDir = "/sys/fs/cgroup"
- type cgroup struct {
- cgroups map[string]string
- }
- func (c *cgroup) acctUsageAllCpus() (uint64, error) {
- data, err := iox.ReadText(path.Join(c.cgroups["cpuacct"], "cpuacct.usage"))
- if err != nil {
- return 0, err
- }
- return parseUint(string(data))
- }
- func (c *cgroup) acctUsagePerCpu() ([]uint64, error) {
- data, err := iox.ReadText(path.Join(c.cgroups["cpuacct"], "cpuacct.usage_percpu"))
- if err != nil {
- return nil, err
- }
- var usage []uint64
- for _, v := range strings.Fields(string(data)) {
- u, err := parseUint(v)
- if err != nil {
- return nil, err
- }
- usage = append(usage, u)
- }
- return usage, nil
- }
- func (c *cgroup) cpuQuotaUs() (int64, error) {
- data, err := iox.ReadText(path.Join(c.cgroups["cpu"], "cpu.cfs_quota_us"))
- if err != nil {
- return 0, err
- }
- return strconv.ParseInt(string(data), 10, 64)
- }
- func (c *cgroup) cpuPeriodUs() (uint64, error) {
- data, err := iox.ReadText(path.Join(c.cgroups["cpu"], "cpu.cfs_period_us"))
- if err != nil {
- return 0, err
- }
- return parseUint(string(data))
- }
- func (c *cgroup) cpus() ([]uint64, error) {
- data, err := iox.ReadText(path.Join(c.cgroups["cpuset"], "cpuset.cpus"))
- if err != nil {
- return nil, err
- }
- return parseUints(string(data))
- }
- func currentCgroup() (*cgroup, error) {
- cgroupFile := fmt.Sprintf("/proc/%d/cgroup", os.Getpid())
- lines, err := iox.ReadTextLines(cgroupFile, iox.WithoutBlank())
- if err != nil {
- return nil, err
- }
- cgroups := make(map[string]string)
- for _, line := range lines {
- cols := strings.Split(line, ":")
- if len(cols) != 3 {
- return nil, fmt.Errorf("invalid cgroup line: %s", line)
- }
- subsys := cols[1]
- // only read cpu staff
- if !strings.HasPrefix(subsys, "cpu") {
- continue
- }
- // https://man7.org/linux/man-pages/man7/cgroups.7.html
- // comma-separated list of controllers for cgroup version 1
- fields := strings.Split(subsys, ",")
- for _, val := range fields {
- cgroups[val] = path.Join(cgroupDir, val)
- }
- }
- return &cgroup{
- cgroups: cgroups,
- }, nil
- }
- func parseUint(s string) (uint64, error) {
- v, err := strconv.ParseInt(s, 10, 64)
- if err != nil {
- if err.(*strconv.NumError).Err == strconv.ErrRange {
- return 0, nil
- } else {
- return 0, fmt.Errorf("cgroup: bad int format: %s", s)
- }
- } else {
- if v < 0 {
- return 0, nil
- } else {
- return uint64(v), nil
- }
- }
- }
- func parseUints(val string) ([]uint64, error) {
- if val == "" {
- return nil, nil
- }
- ints := make(map[uint64]lang.PlaceholderType)
- cols := strings.Split(val, ",")
- for _, r := range cols {
- if strings.Contains(r, "-") {
- fields := strings.SplitN(r, "-", 2)
- min, err := parseUint(fields[0])
- if err != nil {
- return nil, fmt.Errorf("cgroup: bad int list format: %s", val)
- }
- max, err := parseUint(fields[1])
- if err != nil {
- return nil, fmt.Errorf("cgroup: bad int list format: %s", val)
- }
- if max < min {
- return nil, fmt.Errorf("cgroup: bad int list format: %s", val)
- }
- for i := min; i <= max; i++ {
- ints[i] = lang.Placeholder
- }
- } else {
- v, err := parseUint(r)
- if err != nil {
- return nil, err
- }
- ints[v] = lang.Placeholder
- }
- }
- var sets []uint64
- for k := range ints {
- sets = append(sets, k)
- }
- return sets, nil
- }
|