mirror of
https://github.com/datarhei/core.git
synced 2025-10-20 22:49:50 +08:00
Add v16.7.2
This commit is contained in:
288
vendor/github.com/lufia/plan9stats/cpu.go
generated
vendored
Normal file
288
vendor/github.com/lufia/plan9stats/cpu.go
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CPUType represents /dev/cputype.
|
||||
type CPUType struct {
|
||||
Name string
|
||||
Clock int // clock rate in MHz
|
||||
}
|
||||
|
||||
func ReadCPUType(ctx context.Context, opts ...Option) (*CPUType, error) {
|
||||
cfg := newConfig(opts...)
|
||||
var c CPUType
|
||||
if err := readCPUType(cfg.rootdir, &c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
type SysStats struct {
|
||||
ID int
|
||||
NumCtxSwitch int64
|
||||
NumInterrupt int64
|
||||
NumSyscall int64
|
||||
NumFault int64
|
||||
NumTLBFault int64
|
||||
NumTLBPurge int64
|
||||
LoadAvg int64 // in units of milli-CPUs and is decayed over time
|
||||
Idle int // percentage
|
||||
Interrupt int // percentage
|
||||
}
|
||||
|
||||
// ReadSysStats reads system statistics from /dev/sysstat.
|
||||
func ReadSysStats(ctx context.Context, opts ...Option) ([]*SysStats, error) {
|
||||
cfg := newConfig(opts...)
|
||||
file := filepath.Join(cfg.rootdir, "/dev/sysstat")
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
var stats []*SysStats
|
||||
for scanner.Scan() {
|
||||
a := strings.Fields(scanner.Text())
|
||||
if len(a) != 10 {
|
||||
continue
|
||||
}
|
||||
var (
|
||||
p intParser
|
||||
stat SysStats
|
||||
)
|
||||
stat.ID = p.ParseInt(a[0], 10)
|
||||
stat.NumCtxSwitch = p.ParseInt64(a[1], 10)
|
||||
stat.NumInterrupt = p.ParseInt64(a[2], 10)
|
||||
stat.NumSyscall = p.ParseInt64(a[3], 10)
|
||||
stat.NumFault = p.ParseInt64(a[4], 10)
|
||||
stat.NumTLBFault = p.ParseInt64(a[5], 10)
|
||||
stat.NumTLBPurge = p.ParseInt64(a[6], 10)
|
||||
stat.LoadAvg = p.ParseInt64(a[7], 10)
|
||||
stat.Idle = p.ParseInt(a[8], 10)
|
||||
stat.Interrupt = p.ParseInt(a[9], 10)
|
||||
if err := p.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stats = append(stats, &stat)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func readCPUType(rootdir string, c *CPUType) error {
|
||||
file := filepath.Join(rootdir, "/dev/cputype")
|
||||
b, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b = bytes.TrimSpace(b)
|
||||
i := bytes.LastIndexByte(b, ' ')
|
||||
if i < 0 {
|
||||
return fmt.Errorf("%s: invalid format", file)
|
||||
}
|
||||
clock, err := strconv.Atoi(string(b[i+1:]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Name = string(b[:i])
|
||||
c.Clock = clock
|
||||
return nil
|
||||
}
|
||||
|
||||
// Time represents /dev/time.
|
||||
type Time struct {
|
||||
Unix time.Duration
|
||||
UnixNano time.Duration
|
||||
Ticks int64 // clock ticks
|
||||
Freq int64 //cloc frequency
|
||||
}
|
||||
|
||||
// Uptime returns uptime.
|
||||
func (t *Time) Uptime() time.Duration {
|
||||
v := float64(t.Ticks) / float64(t.Freq)
|
||||
return time.Duration(v*1000_000_000) * time.Nanosecond
|
||||
}
|
||||
|
||||
func ReadTime(ctx context.Context, opts ...Option) (*Time, error) {
|
||||
cfg := newConfig(opts...)
|
||||
file := filepath.Join(cfg.rootdir, "/dev/time")
|
||||
var t Time
|
||||
if err := readTime(file, &t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// ProcStatus represents a /proc/n/status.
|
||||
type ProcStatus struct {
|
||||
Name string
|
||||
User string
|
||||
State string
|
||||
Times CPUTime
|
||||
MemUsed int64 // in units of 1024 bytes
|
||||
BasePriority uint32 // 0(low) to 19(high)
|
||||
Priority uint32 // 0(low) to 19(high)
|
||||
}
|
||||
|
||||
// CPUTime represents /dev/cputime or a part of /proc/n/status.
|
||||
type CPUTime struct {
|
||||
User time.Duration // the time in user mode (millisecconds)
|
||||
Sys time.Duration
|
||||
Real time.Duration
|
||||
ChildUser time.Duration // exited children and descendants time in user mode
|
||||
ChildSys time.Duration
|
||||
ChildReal time.Duration
|
||||
}
|
||||
|
||||
// CPUStats emulates Linux's /proc/stat.
|
||||
type CPUStats struct {
|
||||
User time.Duration
|
||||
Sys time.Duration
|
||||
Idle time.Duration
|
||||
}
|
||||
|
||||
func ReadCPUStats(ctx context.Context, opts ...Option) (*CPUStats, error) {
|
||||
cfg := newConfig(opts...)
|
||||
a, err := ReadSysStats(ctx, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dir := filepath.Join(cfg.rootdir, "/proc")
|
||||
d, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
names, err := d.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var up uint32parser
|
||||
pids := make([]uint32, len(names))
|
||||
for i, s := range names {
|
||||
pids[i] = up.Parse(s)
|
||||
}
|
||||
if up.err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(pids, func(i, j int) bool {
|
||||
return pids[i] < pids[j]
|
||||
})
|
||||
|
||||
var stat CPUStats
|
||||
for _, pid := range pids {
|
||||
s := strconv.FormatUint(uint64(pid), 10)
|
||||
file := filepath.Join(dir, s, "status")
|
||||
var p ProcStatus
|
||||
if err := readProcStatus(file, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stat.User += p.Times.User
|
||||
stat.Sys += p.Times.Sys
|
||||
}
|
||||
|
||||
var t Time
|
||||
file := filepath.Join(cfg.rootdir, "/dev/time")
|
||||
if err := readTime(file, &t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// In multi-processor host, Idle should multiple by number of cores.
|
||||
u := t.Uptime() * time.Duration(len(a))
|
||||
stat.Idle = u - stat.User - stat.Sys
|
||||
return &stat, nil
|
||||
}
|
||||
|
||||
func readProcStatus(file string, p *ProcStatus) error {
|
||||
b, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
fields := strings.Fields(string(b))
|
||||
if len(fields) != 12 {
|
||||
return errors.New("invalid format")
|
||||
}
|
||||
p.Name = string(fields[0])
|
||||
p.User = string(fields[1])
|
||||
p.State = string(fields[2])
|
||||
var up uint32parser
|
||||
p.Times.User = time.Duration(up.Parse(fields[3])) * time.Millisecond
|
||||
p.Times.Sys = time.Duration(up.Parse(fields[4])) * time.Millisecond
|
||||
p.Times.Real = time.Duration(up.Parse(fields[5])) * time.Millisecond
|
||||
p.Times.ChildUser = time.Duration(up.Parse(fields[6])) * time.Millisecond
|
||||
p.Times.ChildSys = time.Duration(up.Parse(fields[7])) * time.Millisecond
|
||||
p.Times.ChildReal = time.Duration(up.Parse(fields[8])) * time.Millisecond
|
||||
p.MemUsed, err = strconv.ParseInt(fields[9], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.BasePriority = up.Parse(fields[10])
|
||||
p.Priority = up.Parse(fields[11])
|
||||
return up.err
|
||||
}
|
||||
|
||||
func readTime(file string, t *Time) error {
|
||||
b, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fields := strings.Fields(string(b))
|
||||
if len(fields) != 4 {
|
||||
return errors.New("invalid format")
|
||||
}
|
||||
n, err := strconv.ParseInt(fields[0], 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Unix = time.Duration(n) * time.Second
|
||||
v, err := strconv.ParseInt(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.UnixNano = time.Duration(v) * time.Nanosecond
|
||||
t.Ticks, err = strconv.ParseInt(fields[2], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Freq, err = strconv.ParseInt(fields[3], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type uint32parser struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (p *uint32parser) Parse(s string) uint32 {
|
||||
if p.err != nil {
|
||||
return 0
|
||||
}
|
||||
n, err := strconv.ParseUint(s, 10, 32)
|
||||
if err != nil {
|
||||
p.err = err
|
||||
return 0
|
||||
}
|
||||
return uint32(n)
|
||||
}
|
Reference in New Issue
Block a user