2012-07-06 44 views
26

Chương trình My Go cần biết phần trăm sử dụng CPU hiện tại của tất cả các quy trình của hệ thống và người dùng.Sử dụng CPU với golang

Làm cách nào để có được điều đó?

+0

mà ngôn ngữ và hệ điều hành bạn sử dụng? –

+1

Tôi sử dụng Go (từ golang.org) trong Linux, nhưng tôi muốn sử dụng thứ gì đó di động cho * nix khác nếu có thể. –

Trả lời

19

Tôi gặp sự cố tương tự và không bao giờ tìm thấy triển khai nhẹ. Đây là một phiên bản rút gọn của giải pháp của tôi để trả lời câu hỏi cụ thể của bạn. Tôi lấy mẫu tệp /proc/stat giống như tylerl đề xuất. Bạn sẽ nhận thấy rằng tôi đợi 3 giây giữa các mẫu để phù hợp với đầu ra của đầu, nhưng tôi cũng đã có kết quả tốt với 1 hoặc 2 giây. Tôi chạy mã tương tự trong một vòng lặp trong một thói quen đi, sau đó tôi truy cập vào việc sử dụng CPU khi tôi cần nó từ thói quen đi khác.

Bạn cũng có thể phân tích đầu ra của top -n1 | grep -i cpu để sử dụng CPU, nhưng nó chỉ lấy mẫu trong nửa giây trên hộp linux của tôi và nó đã tắt trong khi tải nặng. đầu thường xuyên dường như để phù hợp rất chặt chẽ khi tôi đồng bộ nó và chương trình sau đây:

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

Nó có vẻ như tôi được phép liên kết đến việc thực hiện đầy đủ mà tôi đã viết trên bitbucket; nếu không, hãy xóa nó đi. Nó chỉ hoạt động trên linux cho đến nay, mặc dù: systemstat.go

13

Bạn có thể sử dụng gói os.exec để thực hiện lệnh ps và nhận kết quả.

Dưới đây là một chương trình ban hành lệnh ps aux, phân tích kết quả và in sử dụng CPU của tất cả các quy trình trên 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

Xin vui lòng, khi bạn downvote, dành thời gian để giải thích lý do tại sao ... –

+1

Phân tích chuỗi từ một đầu ra lệnh không phải là một giải pháp tuyệt vời vì lệnh có thể thay đổi và nó cũng nặng trên cpu/mem/etc. –

+0

@EricAnderson Bạn có nhận thấy câu trả lời được chấp nhận (viết hơn một năm sau khi tôi) trả lời không? Bạn đã chọn chỉ trả lời câu hỏi đầu tiên để cung cấp giải pháp cho câu hỏi? –

16

Cơ chế cho việc sử dụng CPU là hệ điều hành phụ thuộc, vì những con số có ý nghĩa hơi những thứ khác nhau cho các hạt nhân OS khác nhau.

Trên Linux, bạn có thể truy vấn hạt nhân để nhận thống kê mới nhất bằng cách đọc các tệp giả trong hệ thống tệp /proc/. Chúng được tạo khi đang di chuyển khi bạn đọc chúng để phản ánh trạng thái hiện tại của máy.

Cụ thể, tệp /proc/<pid>/stat cho mỗi quy trình chứa thông tin kế toán quy trình được liên kết. Nó được ghi lại trong proc(5). Bạn quan tâm cụ thể đến các trường utime, stime, cutimecstime (bắt đầu từ trường thứ 14).

Bạn có thể tính tỷ lệ phần trăm dễ dàng đủ: chỉ cần đọc các số, chờ một khoảng thời gian và đọc lại. Lấy sự khác biệt, chia cho khoảng thời gian bạn chờ đợi và mức trung bình của bạn. Đây chính là điều mà chương trình top thực hiện (cũng như tất cả các chương trình khác thực hiện cùng một dịch vụ). Ghi nhớ rằng bạn có thể có hơn 100% sử dụng CPU nếu bạn có nhiều hơn 1 CPU.

Nếu bạn chỉ muốn một bản tóm tắt toàn hệ thống, báo cáo được ghi trong /proc/stat - tính mức trung bình của bạn bằng cùng một kỹ thuật, nhưng bạn chỉ phải đọc một tệp.

24

Kiểm tra gói này http://github.com/c9s/goprocinfo, gói goprocinfo thực hiện công cụ phân tích cú pháp cho bạn.

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

Thư viện tuyệt vời, cảm ơn. Nó làm nhiều hơn thế! – lzap

3

Dưới đây là một giải pháp độc lập hệ điều hành sử dụng Cgo để khai thác clock() chức năng được cung cấp bởi 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 
} 
+1

Bạn có thể đơn giản hóa 'time.Now(). Sub (startTime)' thành 'time.Since (startTime)'. –

+0

Cảm ơn đề xuất, ví dụ được cập nhật. –

+0

Sidenote: 'clock()' chỉ cho thời gian của quá trình xử lý hiện tại. –

0

Gần đây tôi đã thực hiện đo đạc sử dụng CPU từ Raspberry Pi (Raspbian OS) và sử dụng github.com/c9s/goprocinfo kết hợp với những gì được đề xuất ở đây:

ý tưởng này xuất phát từ các mã htop nguồn và là phải có hai phép đo (trước/hiện tại) để tính toán việc sử dụng 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 
} 

Để biết thêm bạn cũng có thể kiểm tra https://github.com/tgogos/rpi_cpu_memory