2012-07-06 1676 views
26

My Go程序需要知道所有系統和用戶進程的當前cpu使用百分比。通過golang獲取CPU使用率

我該如何獲得?

+0

這你使用的語言和操作系統? – 2012-07-06 05:34:33

+1

我在Linux下使用Go(來自golang.org),但是如果可能的話,我想使用可移植到其他* nix的東西。 – 2012-07-06 05:37:16

回答

19

我有一個類似的問題,從來沒有找到一個輕量級的實現。這是我的解決方案的簡化版本,可以解答您的具體問題。我像Tylerl建議的那樣對/proc/stat文件進行了抽樣。您會注意到我在樣本間等待了3秒鐘以匹配頂部的輸出,但我也有1秒或2秒的良好結果。我在去程序的循環中運行類似的代碼,然後當我從其他去程序需要它時訪問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) 
} 

好像我被允許鏈接到全面實施,我在寫到位桶;如果不是,請隨時刪除。它只適用於Linux,但目前爲止:systemstat.go

13

可以使用os.exec包執行ps命令並獲得結果。

這裏是一個程序發出ps aux命令,解析結果和打印所有進程的CPU使用在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") 
    } 
} 
+2

請當你downvote,花時間來解釋爲什麼... – 2014-02-08 20:42:42

+1

字符串解析從命令輸出不是一個很好的解決方案,因爲該命令可以改變,它也是沉重的CPU/MEM /等。 – 2014-08-05 15:23:18

+0

@EricAnderson你注意到接受的答案(寫在我的一年多後)是否也一樣?你是否選擇回答第一個問題以解決問題? – 2014-08-05 16:21:14

16

用於獲取CPU的使用的機制是操作系統相關的,因爲這些數字略微意味着不同的操作系統內核不同的東西。

在Linux上,您可以通過讀取/proc/文件系統中的僞文件來查詢內核以獲取最新統計信息。當您讀取它們以反映機器的當前狀態時,它們即時生成。

具體而言,每個進程的/proc/<pid>/stat文件包含關聯的進程記帳信息。它記錄在proc(5)。你特別感興趣的領域是utime,stime,cutimecstime(從第14場開始)。

你可以很容易地計算出百分比:只需讀取數字,等待一段時間間隔,然後再讀一遍。採取差異,除以你等待的時間,這就是你的平均水平。這正是top程序所做的(以及執行相同服務的所有其他程序)。請記住,如果您有超過1個CPU,則可以擁有超過100%的CPU使用率。

如果您只是想要一個系統範圍的摘要,那麼在/proc/stat中報告 - 使用相同的技術計算您的平均值,但只需讀取一個文件。

24

查看此軟件包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 
} 
+2

優秀的圖書館,謝謝。它不止於此! – lzap 2014-02-04 14:50:53

3

下面是使用Cgo以利用由C standard library提供的clock()功能的OS獨立的解決方案:

//#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 
} 
+1

你可以簡化'time.Now().Sub(startTime)'到'time.Since(startTime)'。 – 2015-06-24 16:21:24

+0

感謝您的建議,更新了示例。 – 2015-06-25 22:00:43

+0

旁註:'clock()'只給出當前進程的時間。 – 2015-11-02 17:49:09

0

我最近不得不採取CPU使用率測量從樹莓PI(Raspbian OS)和用於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