我的 Go 程序需要知道所有系统和用户进程的当前 cpu 使用百分比。
我怎样才能得到它?
查看这个包http://github.com/c9s/goprocinfo,goprocinfo 包会为您完成解析工作。
stat, err := linuxproc.ReadStat("/proc/stat")
if err != nil {
t.Fatal("stat read fail")
}
for _, s := range stat.CPUStats {
// s.User
// s.Nice
// s.System
// s.Idle
// s.IOWait
}
我有一个类似的问题,从来没有找到一个轻量级的实现。这是我的解决方案的精简版本,可以回答您的具体问题。我/proc/stat
就像 tylerl 推荐的那样对文件进行采样。您会注意到我在样本之间等待 3 秒以匹配 top 的输出,但我也有 1 或 2 秒的良好结果。我在 go 例程中循环运行类似的代码,然后在需要时从其他 go 例程访问 cpu 使用情况。
您还可以解析 的输出top -n1 | grep -i cpu
以获取 cpu 使用情况,但它在我的 linux 机器上仅采样半秒,并且在重负载期间它会消失。当我将常规顶部与以下程序同步时,它似乎非常匹配:
package main
import (
"fmt"
"io/ioutil"
"strconv"
"strings"
"time"
)
func getCPUSample() (idle, total uint64) {
contents, err := ioutil.ReadFile("/proc/stat")
if err != nil {
return
}
lines := strings.Split(string(contents), "\n")
for _, line := range(lines) {
fields := strings.Fields(line)
if fields[0] == "cpu" {
numFields := len(fields)
for i := 1; i < numFields; i++ {
val, err := strconv.ParseUint(fields[i], 10, 64)
if err != nil {
fmt.Println("Error: ", i, fields[i], err)
}
total += val // tally up all the numbers to get total ticks
if i == 4 { // idle is the 5th field in the cpu line
idle = val
}
}
return
}
}
return
}
func main() {
idle0, total0 := getCPUSample()
time.Sleep(3 * time.Second)
idle1, total1 := getCPUSample()
idleTicks := float64(idle1 - idle0)
totalTicks := float64(total1 - total0)
cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks
fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)
}
似乎允许我链接到我在 bitbucket 上编写的完整实现;如果不是,请随时删除此内容。到目前为止,它只适用于 linux:systemstat.go
获取 CPU 使用率的机制取决于操作系统,因为数字对不同操作系统内核的含义略有不同。
在 Linux 上,您可以通过读取文件系统中的伪文件来查询内核以获取最新的统计信息/proc/
。当您阅读它们以反映机器的当前状态时,它们会即时生成。
具体来说,/proc/<pid>/stat
每个进程的文件都包含相关的进程记帐信息。它记录在proc(5)中。您对字段utime
、stime
和cutime
(cstime
从第 14 个字段开始)特别感兴趣。
您可以很容易地计算百分比:只需读取数字,等待一段时间,然后再次读取它们。取差值,除以您等待的时间,这就是您的平均值。这正是top
程序所做的(以及执行相同服务的所有其他程序)。请记住,如果您有超过 1 个 CPU,您的 CPU 使用率可能会超过 100%。
如果您只需要系统范围的摘要,/proc/stat
请使用相同的技术计算您的平均值,但您只需阅读一个文件。
您可以使用该os.exec
包执行ps
命令并获取结果。
这是一个发出ps aux
命令、解析结果并打印 linux 上所有进程的 CPU 使用率的程序:
package main
import (
"bytes"
"log"
"os/exec"
"strconv"
"strings"
)
type Process struct {
pid int
cpu float64
}
func main() {
cmd := exec.Command("ps", "aux")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
processes := make([]*Process, 0)
for {
line, err := out.ReadString('\n')
if err!=nil {
break;
}
tokens := strings.Split(line, " ")
ft := make([]string, 0)
for _, t := range(tokens) {
if t!="" && t!="\t" {
ft = append(ft, t)
}
}
log.Println(len(ft), ft)
pid, err := strconv.Atoi(ft[1])
if err!=nil {
continue
}
cpu, err := strconv.ParseFloat(ft[2], 64)
if err!=nil {
log.Fatal(err)
}
processes = append(processes, &Process{pid, cpu})
}
for _, p := range(processes) {
log.Println("Process ", p.pid, " takes ", p.cpu, " % of the CPU")
}
}
这是一个使用Cgo来利用C 标准库提供的clock()函数的独立于操作系统的解决方案:
//#include <time.h>
import "C"
import "time"
var startTime = time.Now()
var startTicks = C.clock()
func CpuUsagePercent() float64 {
clockSeconds := float64(C.clock()-startTicks) / float64(C.CLOCKS_PER_SEC)
realSeconds := time.Since(startTime).Seconds()
return clockSeconds / realSeconds * 100
}
我最近不得不从 Raspberry Pi (Raspbian OS) 进行 CPU 使用率测量,并将github.com/c9s/goprocinfo与此处建议的内容结合使用:
这个想法来自htop
源代码,并且是有两个测量值(以前/当前)以计算 CPU 使用率:
func calcSingleCoreUsage(curr, prev linuxproc.CPUStat) float32 {
PrevIdle := prev.Idle + prev.IOWait
Idle := curr.Idle + curr.IOWait
PrevNonIdle := prev.User + prev.Nice + prev.System + prev.IRQ + prev.SoftIRQ + prev.Steal
NonIdle := curr.User + curr.Nice + curr.System + curr.IRQ + curr.SoftIRQ + curr.Steal
PrevTotal := PrevIdle + PrevNonIdle
Total := Idle + NonIdle
// fmt.Println(PrevIdle, Idle, PrevNonIdle, NonIdle, PrevTotal, Total)
// differentiate: actual value minus the previous one
totald := Total - PrevTotal
idled := Idle - PrevIdle
CPU_Percentage := (float32(totald) - float32(idled)) / float32(totald)
return CPU_Percentage
}
有关更多信息,您还可以查看https://github.com/tgogos/rpi_cpu_memory