How to get CPU usage

前端 未结 6 1800
刺人心
刺人心 2020-12-22 23:55

My Go program needs to know the current cpu usage percentage of all system and user processes.

How can I obtain that?

相关标签:
6条回答
  • 2020-12-23 00:27

    Check out this package http://github.com/c9s/goprocinfo, goprocinfo package does the parsing stuff for you.

    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
    }
    
    0 讨论(0)
  • 2020-12-23 00:27

    Here is an OS independent solution using Cgo to harness the clock() function provided by C standard library:

    //#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
    }
    
    0 讨论(0)
  • 2020-12-23 00:30

    You can use the os.exec package to execute the ps command and get the result.

    Here is a program issuing the ps aux command, parsing the result and printing the CPU usage of all processes on linux :

    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")
        }
    }
    
    0 讨论(0)
  • 2020-12-23 00:34

    I recently had to take CPU usage measurements from a Raspberry Pi (Raspbian OS) and used github.com/c9s/goprocinfo combined with what is proposed here:

    • Accurate calculation of CPU usage given in percentage in Linux?

    The idea comes from the htop source code and is to have two measurements (previous / current) in order to calculate the CPU usage:

    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
    }
    

    For more you can also check https://github.com/tgogos/rpi_cpu_memory

    0 讨论(0)
  • 2020-12-23 00:42

    The mechanism for getting CPU usage is OS-dependent, since the numbers mean slightly different things to different OS kernels.

    On Linux, you can query the kernel to get the latest stats by reading the pseudo-files in the /proc/ filesystem. These are generated on-the-fly when you read them to reflect the current state of the machine.

    Specifically, the /proc/<pid>/stat file for each process contains the associated process accounting information. It's documented in proc(5). You're interested specifically in fields utime, stime, cutime and cstime (starting at the 14th field).

    You can calculate the percentage easily enough: just read the numbers, wait some time interval, and read them again. Take the difference, divide by the amount of time you waited, and there's your average. This is precisely what the top program does (as well as all other programs that perform the same service). Bear in mind that you can have over 100% cpu usage if you have more than 1 CPU.

    If you just want a system-wide summary, that's reported in /proc/stat -- calculate your average using the same technique, but you only have to read one file.

    0 讨论(0)
  • 2020-12-23 00:44

    I had a similar issue and never found a lightweight implementation. Here is a slimmed down version of my solution that answers your specific question. I sample the /proc/stat file just like tylerl recommends. You'll notice that I wait 3 seconds between samples to match top's output, but I have also had good results with 1 or 2 seconds. I run similar code in a loop within a go routine, then I access the cpu usage when I need it from other go routines.

    You can also parse the output of top -n1 | grep -i cpu to get the cpu usage, but it only samples for half a second on my linux box and it was way off during heavy load. Regular top seemed to match very closely when I synchronized it and the following program:

    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)
    }
    

    It seems like I'm allowed to link to the full implementation that I wrote on bitbucket; if it's not, feel free to delete this. It only works on linux so far, though: systemstat.go

    0 讨论(0)
提交回复
热议问题