github.com/shuguocloud/go-zero@v1.3.0/core/stat/internal/cpu_linux.go (about)

     1  package internal
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/shuguocloud/go-zero/core/iox"
    10  	"github.com/shuguocloud/go-zero/core/logx"
    11  )
    12  
    13  const (
    14  	cpuTicks  = 100
    15  	cpuFields = 8
    16  )
    17  
    18  var (
    19  	preSystem uint64
    20  	preTotal  uint64
    21  	quota     float64
    22  	cores     uint64
    23  )
    24  
    25  // if /proc not present, ignore the cpu calculation, like wsl linux
    26  func init() {
    27  	cpus, err := perCpuUsage()
    28  	if err != nil {
    29  		logx.Error(err)
    30  		return
    31  	}
    32  
    33  	cores = uint64(len(cpus))
    34  	sets, err := cpuSets()
    35  	if err != nil {
    36  		logx.Error(err)
    37  		return
    38  	}
    39  
    40  	quota = float64(len(sets))
    41  	cq, err := cpuQuota()
    42  	if err == nil {
    43  		if cq != -1 {
    44  			period, err := cpuPeriod()
    45  			if err != nil {
    46  				logx.Error(err)
    47  				return
    48  			}
    49  
    50  			limit := float64(cq) / float64(period)
    51  			if limit < quota {
    52  				quota = limit
    53  			}
    54  		}
    55  	}
    56  
    57  	preSystem, err = systemCpuUsage()
    58  	if err != nil {
    59  		logx.Error(err)
    60  		return
    61  	}
    62  
    63  	preTotal, err = totalCpuUsage()
    64  	if err != nil {
    65  		logx.Error(err)
    66  		return
    67  	}
    68  }
    69  
    70  // RefreshCpu refreshes cpu usage and returns.
    71  func RefreshCpu() uint64 {
    72  	total, err := totalCpuUsage()
    73  	if err != nil {
    74  		return 0
    75  	}
    76  	system, err := systemCpuUsage()
    77  	if err != nil {
    78  		return 0
    79  	}
    80  
    81  	var usage uint64
    82  	cpuDelta := total - preTotal
    83  	systemDelta := system - preSystem
    84  	if cpuDelta > 0 && systemDelta > 0 {
    85  		usage = uint64(float64(cpuDelta*cores*1e3) / (float64(systemDelta) * quota))
    86  	}
    87  	preSystem = system
    88  	preTotal = total
    89  
    90  	return usage
    91  }
    92  
    93  func cpuQuota() (int64, error) {
    94  	cg, err := currentCgroup()
    95  	if err != nil {
    96  		return 0, err
    97  	}
    98  
    99  	return cg.cpuQuotaUs()
   100  }
   101  
   102  func cpuPeriod() (uint64, error) {
   103  	cg, err := currentCgroup()
   104  	if err != nil {
   105  		return 0, err
   106  	}
   107  
   108  	return cg.cpuPeriodUs()
   109  }
   110  
   111  func cpuSets() ([]uint64, error) {
   112  	cg, err := currentCgroup()
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	return cg.cpus()
   118  }
   119  
   120  func perCpuUsage() ([]uint64, error) {
   121  	cg, err := currentCgroup()
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	return cg.acctUsagePerCpu()
   127  }
   128  
   129  func systemCpuUsage() (uint64, error) {
   130  	lines, err := iox.ReadTextLines("/proc/stat", iox.WithoutBlank())
   131  	if err != nil {
   132  		return 0, err
   133  	}
   134  
   135  	for _, line := range lines {
   136  		fields := strings.Fields(line)
   137  		if fields[0] == "cpu" {
   138  			if len(fields) < cpuFields {
   139  				return 0, fmt.Errorf("bad format of cpu stats")
   140  			}
   141  
   142  			var totalClockTicks uint64
   143  			for _, i := range fields[1:cpuFields] {
   144  				v, err := parseUint(i)
   145  				if err != nil {
   146  					return 0, err
   147  				}
   148  
   149  				totalClockTicks += v
   150  			}
   151  
   152  			return (totalClockTicks * uint64(time.Second)) / cpuTicks, nil
   153  		}
   154  	}
   155  
   156  	return 0, errors.New("bad stats format")
   157  }
   158  
   159  func totalCpuUsage() (usage uint64, err error) {
   160  	var cg *cgroup
   161  	if cg, err = currentCgroup(); err != nil {
   162  		return
   163  	}
   164  
   165  	return cg.acctUsageAllCpus()
   166  }