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  }