123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- // +build linux
- package cpu
- import (
- "bufio"
- "fmt"
- "os"
- "strconv"
- "strings"
- "github.com/pkg/errors"
- )
- const nanoSecondsPerSecond = 1e9
- // ErrNoCFSLimit is no quota limit
- var ErrNoCFSLimit = errors.Errorf("no quota limit")
- var clockTicksPerSecond = uint64(GetClockTicks())
- // systemCPUUsage returns the host system's cpu usage in
- // nanoseconds. An error is returned if the format of the underlying
- // file does not match.
- //
- // Uses /proc/stat defined by POSIX. Looks for the cpu
- // statistics line and then sums up the first seven fields
- // provided. See man 5 proc for details on specific field
- // information.
- func systemCPUUsage() (usage uint64, err error) {
- var (
- line string
- f *os.File
- )
- if f, err = os.Open("/proc/stat"); err != nil {
- return
- }
- bufReader := bufio.NewReaderSize(nil, 128)
- defer func() {
- bufReader.Reset(nil)
- f.Close()
- }()
- bufReader.Reset(f)
- for err == nil {
- if line, err = bufReader.ReadString('\n'); err != nil {
- err = errors.WithStack(err)
- return
- }
- parts := strings.Fields(line)
- switch parts[0] {
- case "cpu":
- if len(parts) < 8 {
- err = errors.WithStack(fmt.Errorf("bad format of cpu stats"))
- return
- }
- var totalClockTicks uint64
- for _, i := range parts[1:8] {
- var v uint64
- if v, err = strconv.ParseUint(i, 10, 64); err != nil {
- err = errors.WithStack(fmt.Errorf("error parsing cpu stats"))
- return
- }
- totalClockTicks += v
- }
- usage = (totalClockTicks * nanoSecondsPerSecond) / clockTicksPerSecond
- return
- }
- }
- err = errors.Errorf("bad stats format")
- return
- }
- func totalCPUUsage() (usage uint64, err error) {
- var cg *cgroup
- if cg, err = currentcGroup(); err != nil {
- return
- }
- return cg.CPUAcctUsage()
- }
- func perCPUUsage() (usage []uint64, err error) {
- var cg *cgroup
- if cg, err = currentcGroup(); err != nil {
- return
- }
- return cg.CPUAcctUsagePerCPU()
- }
- func cpuSets() (sets []uint64, err error) {
- var cg *cgroup
- if cg, err = currentcGroup(); err != nil {
- return
- }
- return cg.CPUSetCPUs()
- }
- func cpuQuota() (quota int64, err error) {
- var cg *cgroup
- if cg, err = currentcGroup(); err != nil {
- return
- }
- return cg.CPUCFSQuotaUs()
- }
- func cpuPeriod() (peroid uint64, err error) {
- var cg *cgroup
- if cg, err = currentcGroup(); err != nil {
- return
- }
- return cg.CPUCFSPeriodUs()
- }
- func cpuFreq() uint64 {
- lines, err := readLines("/proc/cpuinfo")
- if err != nil {
- return 0
- }
- for _, line := range lines {
- fields := strings.Split(line, ":")
- if len(fields) < 2 {
- continue
- }
- key := strings.TrimSpace(fields[0])
- value := strings.TrimSpace(fields[1])
- if key == "cpu MHz" || key == "clock" {
- // treat this as the fallback value, thus we ignore error
- if t, err := strconv.ParseFloat(strings.Replace(value, "MHz", "", 1), 64); err == nil {
- return uint64(t * 1000.0 * 1000.0)
- }
- }
- }
- return 0
- }
- func cpuMaxFreq() uint64 {
- feq := cpuFreq()
- data, err := readFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq")
- if err != nil {
- return feq
- }
- // override the max freq from /proc/cpuinfo
- cfeq, err := parseUint(data)
- if err == nil {
- feq = cfeq
- }
- return feq
- }
|