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 }