2012-07-06 11 views
26

Il programma My Go deve conoscere la percentuale di utilizzo corrente della CPU di tutti i processi di sistema e utente.Utilizzo della CPU con golang

Come posso ottenerlo?

+0

che lingua e sistema operativo che usi? –

+1

Io uso Go (da golang.org) sotto Linux, ma mi piacerebbe usare qualcosa di portatile per altri * nix se è possibile. –

risposta

19

Avevo un problema simile e non ho mai trovato un'implementazione leggera. Ecco una versione ridotta della mia soluzione che risponde alla tua domanda specifica. Ho provato il file /proc/stat proprio come consiglia Tylerl. Noterai che aspetto 3 secondi tra un campione e l'altro, ma ho anche avuto buoni risultati con 1 o 2 secondi. Eseguo codice simile in un ciclo all'interno di una routine go, quindi accedo all'utilizzo della CPU quando ne ho bisogno da altre routine di go.

È inoltre possibile analizzare l'output di top -n1 | grep -i cpu per ottenere l'utilizzo della CPU, ma solo campioni per mezzo secondo sulla mia macchina Linux ed è stato spento durante il carico pesante. top regolare sembrava corrispondere a stretto contatto quando ho sincronizzato e il seguente programma:

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

Sembra che io sono autorizzato a collegarsi alla piena attuazione che ho scritto su bitbucket; se non lo è, sentiti libero di cancellarlo. Funziona solo su Linux finora: systemstat.go

13

È possibile utilizzare il pacchetto os.exec per eseguire il comando ps e ottenere il risultato.

Ecco un programma emettendo il comando ps aux, l'analisi del risultato e stampare l'utilizzo della CPU di tutti i processi su 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

Per favore, quando fai un downgrade, prenditi il ​​tempo di spiegare perché ... –

+1

L'analisi delle stringhe da un output di comando non è una grande soluzione dato che il comando può cambiare ed è anche pesante su cpu/mem/etc. –

+0

@EricAnderson Hai notato che la risposta accettata (scritta più di un anno dopo la mia) fa la stessa cosa? Hai scelto di rispondere solo al primo per fornire una soluzione alla domanda? –

16

Il meccanismo per ottenere l'utilizzo della CPU è OS-dipendente, dal momento che i numeri significano un po ' cose diverse per i diversi kernel del sistema operativo.

Su Linux, è possibile interrogare il kernel per ottenere le ultime statistiche leggendo gli pseudo-file nel filesystem . Questi vengono generati al volo quando li leggi per riflettere lo stato corrente della macchina.

In particolare, il file /proc/<pid>/stat per ogni processo contiene le informazioni di contabilità del processo associate. È documentato in proc(5). Ti interessano in particolare i campi utime,, e cstime (a partire dal 14 ° campo).

È possibile calcolare la percentuale abbastanza facilmente: basta leggere i numeri, attendere un intervallo di tempo e leggerli di nuovo. Prendi la differenza, dividi per la quantità di tempo che hai aspettato, e c'è la tua media. Questo è esattamente ciò che fa il programma top (così come tutti gli altri programmi che eseguono lo stesso servizio). Ricorda che puoi avere più del 100% di utilizzo della CPU se hai più di 1 CPU.

Se si desidera solo un riepilogo del sistema, riportato in /proc/stat, calcolare la media utilizzando la stessa tecnica, ma è sufficiente leggere un solo file.

24

Dai un'occhiata a questo pacchetto http://github.com/c9s/goprocinfo, il pacchetto goprocinfo fa il lavoro di analisi per te.

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

Ottima libreria, grazie. Fa di più! – lzap

3

Ecco una soluzione indipendente OS utilizzando Cgo di sfruttare la funzione clock() fornita da 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

È possibile semplificare 'time.Now(). Sub (startTime)' a 'time.Since (startTime)'. –

+0

Grazie per il suggerimento, l'esempio aggiornato. –

+0

Sidenote: 'clock()' fornisce solo l'ora del processo corrente. –

0

Recentemente ho dovuto prendere misurazioni utilizzo della CPU da un lampone Pi (Raspbian OS) e usato github.com/c9s/goprocinfo in combinazione con quanto proposto qui:

L'idea nasce dal codice htop sorgente e è quella di avere due misure (precedente/corrente) per calcolare l'utilizzo della 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 
} 

Per di più si può anche verificare https://github.com/tgogos/rpi_cpu_memory

Problemi correlati