123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- package internal
- import (
- "errors"
- "fmt"
- "strings"
- "time"
- "git.i2edu.net/i2/go-zero/core/iox"
- "git.i2edu.net/i2/go-zero/core/logx"
- )
- const (
- cpuTicks = 100
- cpuFields = 8
- )
- var (
- preSystem uint64
- preTotal uint64
- quota float64
- cores uint64
- )
- // if /proc not present, ignore the cpu calculation, like wsl linux
- func init() {
- cpus, err := perCpuUsage()
- if err != nil {
- logx.Error(err)
- return
- }
- cores = uint64(len(cpus))
- sets, err := cpuSets()
- if err != nil {
- logx.Error(err)
- return
- }
- quota = float64(len(sets))
- cq, err := cpuQuota()
- if err == nil {
- if cq != -1 {
- period, err := cpuPeriod()
- if err != nil {
- logx.Error(err)
- return
- }
- limit := float64(cq) / float64(period)
- if limit < quota {
- quota = limit
- }
- }
- }
- preSystem, err = systemCpuUsage()
- if err != nil {
- logx.Error(err)
- return
- }
- preTotal, err = totalCpuUsage()
- if err != nil {
- logx.Error(err)
- return
- }
- }
- // RefreshCpu refreshes cpu usage and returns.
- func RefreshCpu() uint64 {
- total, err := totalCpuUsage()
- if err != nil {
- return 0
- }
- system, err := systemCpuUsage()
- if err != nil {
- return 0
- }
- var usage uint64
- cpuDelta := total - preTotal
- systemDelta := system - preSystem
- if cpuDelta > 0 && systemDelta > 0 {
- usage = uint64(float64(cpuDelta*cores*1e3) / (float64(systemDelta) * quota))
- }
- preSystem = system
- preTotal = total
- return usage
- }
- func cpuQuota() (int64, error) {
- cg, err := currentCgroup()
- if err != nil {
- return 0, err
- }
- return cg.cpuQuotaUs()
- }
- func cpuPeriod() (uint64, error) {
- cg, err := currentCgroup()
- if err != nil {
- return 0, err
- }
- return cg.cpuPeriodUs()
- }
- func cpuSets() ([]uint64, error) {
- cg, err := currentCgroup()
- if err != nil {
- return nil, err
- }
- return cg.cpus()
- }
- func perCpuUsage() ([]uint64, error) {
- cg, err := currentCgroup()
- if err != nil {
- return nil, err
- }
- return cg.acctUsagePerCpu()
- }
- func systemCpuUsage() (uint64, error) {
- lines, err := iox.ReadTextLines("/proc/stat", iox.WithoutBlank())
- if err != nil {
- return 0, err
- }
- for _, line := range lines {
- fields := strings.Fields(line)
- if fields[0] == "cpu" {
- if len(fields) < cpuFields {
- return 0, fmt.Errorf("bad format of cpu stats")
- }
- var totalClockTicks uint64
- for _, i := range fields[1:cpuFields] {
- v, err := parseUint(i)
- if err != nil {
- return 0, err
- }
- totalClockTicks += v
- }
- return (totalClockTicks * uint64(time.Second)) / cpuTicks, nil
- }
- }
- return 0, errors.New("bad stats format")
- }
- func totalCpuUsage() (usage uint64, err error) {
- var cg *cgroup
- if cg, err = currentCgroup(); err != nil {
- return
- }
- return cg.acctUsageAllCpus()
- }
|