diff --git a/cpu/cpu_linux.go b/cpu/cpu_linux.go index 23b0952..d90bbf4 100644 --- a/cpu/cpu_linux.go +++ b/cpu/cpu_linux.go @@ -13,7 +13,7 @@ import ( "github.com/shirou/gopsutil/internal/common" ) -var cpu_tick = float64(100) +var CPUTick = float64(100) func init() { getconf, err := exec.LookPath("/usr/bin/getconf") @@ -25,7 +25,7 @@ func init() { if err == nil { i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64) if err == nil { - cpu_tick = float64(i) + CPUTick = i } } } @@ -251,34 +251,34 @@ func parseStatLine(line string) (*TimesStat, error) { ct := &TimesStat{ CPU: cpu, - User: float64(user) / cpu_tick, - Nice: float64(nice) / cpu_tick, - System: float64(system) / cpu_tick, - Idle: float64(idle) / cpu_tick, - Iowait: float64(iowait) / cpu_tick, - Irq: float64(irq) / cpu_tick, - Softirq: float64(softirq) / cpu_tick, + User: user / CPUTick, + Nice: nice / CPUTick, + System: system / CPUTick, + Idle: idle / CPUTick, + Iowait: iowait / CPUTick, + Irq: irq / CPUTick, + Softirq: softirq / CPUTick, } if len(fields) > 8 { // Linux >= 2.6.11 steal, err := strconv.ParseFloat(fields[8], 64) if err != nil { return nil, err } - ct.Steal = float64(steal) / cpu_tick + ct.Steal = steal / CPUTick } if len(fields) > 9 { // Linux >= 2.6.24 guest, err := strconv.ParseFloat(fields[9], 64) if err != nil { return nil, err } - ct.Guest = float64(guest) / cpu_tick + ct.Guest = guest / CPUTick } if len(fields) > 10 { // Linux >= 3.2.0 guestNice, err := strconv.ParseFloat(fields[10], 64) if err != nil { return nil, err } - ct.GuestNice = float64(guestNice) / cpu_tick + ct.GuestNice = guestNice / CPUTick } return ct, nil diff --git a/docker/docker.go b/docker/docker.go index 76791c2..623af0e 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" + "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/internal/common" ) @@ -12,6 +13,11 @@ var ErrCgroupNotAvailable = errors.New("cgroup not available") var invoke common.Invoker = common.Invoke{} +type CgroupCPUStat struct { + cpu.TimesStat + Usage float64 +} + type CgroupMemStat struct { ContainerID string `json:"containerID"` Cache uint64 `json:"cache"` diff --git a/docker/docker_linux.go b/docker/docker_linux.go index 4dcb477..85fa6f5 100644 --- a/docker/docker_linux.go +++ b/docker/docker_linux.go @@ -89,11 +89,31 @@ func GetDockerIDListWithContext(ctx context.Context) ([]string, error) { // containerID is same as docker id if you use docker. // If you use container via systemd.slice, you could use // containerID = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ -func CgroupCPU(containerID string, base string) (*cpu.TimesStat, error) { +func CgroupCPU(containerID string, base string) (*CgroupCPUStat, error) { return CgroupCPUWithContext(context.Background(), containerID, base) } -func CgroupCPUWithContext(ctx context.Context, containerID string, base string) (*cpu.TimesStat, error) { +func CgroupCPUUsage(containerID string, base string) (float64, error) { + return CgroupCPUUsageWithContext(context.Background(), containerID, base) +} + +func CgroupCPUUsageWithContext(ctx context.Context, containerID, base string) (float64, error) { + usagefile := getCgroupFilePath(containerID, base, "cpuacct", "cpuacct.usage") + lines, err := common.ReadLinesOffsetN(usagefile, 0, 1) + if err != nil { + return 0.0, err + } + + ns, err := strconv.ParseFloat(lines[0], 64) + if err != nil { + return 0.0, err + } + + return ns / 1e9, nil + +} + +func CgroupCPUWithContext(ctx context.Context, containerID string, base string) (*CgroupCPUStat, error) { statfile := getCgroupFilePath(containerID, base, "cpuacct", "cpuacct.stat") lines, err := common.ReadLines(statfile) if err != nil { @@ -103,31 +123,40 @@ func CgroupCPUWithContext(ctx context.Context, containerID string, base string) if len(containerID) == 0 { containerID = "all" } - ret := &cpu.TimesStat{CPU: containerID} + ret := &CgroupCPUStat{} + ret.CPU = containerID for _, line := range lines { fields := strings.Split(line, " ") if fields[0] == "user" { user, err := strconv.ParseFloat(fields[1], 64) if err == nil { - ret.User = float64(user) + ret.User = user / cpu.CPUTick } } if fields[0] == "system" { system, err := strconv.ParseFloat(fields[1], 64) if err == nil { - ret.System = float64(system) + ret.System = system / cpu.CPUTick } } } - + usage, err := CgroupCPUUsageWithContext(ctx, containerID, base) + if err != nil { + return nil, err + } + ret.Usage = usage return ret, nil } -func CgroupCPUDocker(containerid string) (*cpu.TimesStat, error) { +func CgroupCPUDocker(containerid string) (*CgroupCPUStat, error) { return CgroupCPUDockerWithContext(context.Background(), containerid) } -func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*cpu.TimesStat, error) { +func CgroupCPUDockerUsageWithContext(ctx context.Context, containerid string) (float64, error) { + return CgroupCPUUsage(containerid, common.HostSys("fs/cgroup/cpuacct/docker")) +} + +func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*CgroupCPUStat, error) { return CgroupCPU(containerid, common.HostSys("fs/cgroup/cpuacct/docker")) } diff --git a/docker/docker_notlinux.go b/docker/docker_notlinux.go index 7a93c45..04e87fd 100644 --- a/docker/docker_notlinux.go +++ b/docker/docker_notlinux.go @@ -4,7 +4,7 @@ package docker import ( "context" - "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/internal/common" ) @@ -32,19 +32,19 @@ func GetDockerIDListWithContext(ctx context.Context) ([]string, error) { // containerid is same as docker id if you use docker. // If you use container via systemd.slice, you could use // containerid = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ -func CgroupCPU(containerid string, base string) (*cpu.TimesStat, error) { +func CgroupCPU(containerid string, base string) (*CgroupCPUStat, error) { return CgroupCPUWithContext(context.Background(), containerid, base) } -func CgroupCPUWithContext(ctx context.Context, containerid string, base string) (*cpu.TimesStat, error) { +func CgroupCPUWithContext(ctx context.Context, containerid string, base string) (*CgroupCPUStat, error) { return nil, ErrCgroupNotAvailable } -func CgroupCPUDocker(containerid string) (*cpu.TimesStat, error) { +func CgroupCPUDocker(containerid string) (*CgroupCPUStat, error) { return CgroupCPUDockerWithContext(context.Background(), containerid) } -func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*cpu.TimesStat, error) { +func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*CgroupCPUStat, error) { return CgroupCPU(containerid, common.HostSys("fs/cgroup/cpuacct/docker")) }