2012-07-06 28 views
26

El programa My Go necesita conocer el porcentaje de uso de la CPU actual de todos los procesos del sistema y del usuario.Obtención de uso de CPU con golang

¿Cómo puedo obtener eso?

+0

cuales idioma y sistema operativo que utiliza? –

+1

Uso Go (de golang.org) en Linux, pero me gustaría usar algo portátil para otro * nix si es posible. –

Respuesta

19

Tuve un problema similar y nunca encontré una implementación liviana. Aquí hay una versión reducida de mi solución que responde a su pregunta específica. Muestro el archivo /proc/stat como lo recomienda tylerl. Notarás que espero 3 segundos entre las muestras para que coincida con la salida de la parte superior, pero también he tenido buenos resultados con 1 o 2 segundos. Ejecuto un código similar en un bucle dentro de una rutina ir, luego accedo al uso de la CPU cuando lo necesito de otras rutinas.

También puede analizar la salida de top -n1 | grep -i cpu para obtener el uso de la CPU, pero solo muestra durante medio segundo en mi cuadro de Linux y estaba muy apagado durante la carga pesada. Regular la parte superior parecía coincidir muy de cerca cuando sincronizado y el siguiente programa:

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

Parece como si se me permite enlazar a la plena aplicación que escribí en bitbucket; si no es así, siéntase libre de eliminar esto. Sin embargo, solo funciona en Linux hasta el momento: systemstat.go

13

Puede usar el paquete os.exec para ejecutar el comando ps y obtener el resultado.

Aquí es un programa de emisión de la orden ps aux, analizar el resultado e imprimir el uso de la CPU de todos los procesos en 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

Por favor, cuando invierte, tómese el tiempo para explicar por qué ... –

+1

El análisis de cadenas desde una salida de comando no es una gran solución ya que el comando puede cambiar y también es pesado en cpu/mem/etc. –

+0

@EricAnderson ¿Notaste que la respuesta aceptada (escrita más de un año después de la mía) hace lo mismo? ¿Elegiste responder solo al primero para brindar una solución a la pregunta? –

16

El mecanismo para conseguir uso de la CPU es OS-dependiente, ya que los números significan poco cosas diferentes a los diferentes núcleos del sistema operativo.

En Linux, puede consultar el kernel para obtener las últimas estadísticas leyendo los pseudo-archivos en el sistema de archivos /proc/. Estos se generan sobre la marcha cuando los lee para reflejar el estado actual de la máquina.

Específicamente, el archivo /proc/<pid>/stat para cada proceso contiene la información de contabilidad de proceso asociada. Está documentado en proc(5). Le interesan específicamente los campos utime, stime, cutime y cstime (comenzando en el campo 14).

Puede calcular el porcentaje con facilidad: simplemente lea los números, espere un intervalo de tiempo y léalos nuevamente. Tome la diferencia, divida por la cantidad de tiempo que esperó, y está su promedio. Esto es precisamente lo que hace el programa top (así como también todos los demás programas que realizan el mismo servicio). Tenga en cuenta que puede tener más del 100% de uso de la CPU si tiene más de 1 CPU.

Si solo desea un resumen de todo el sistema, eso se informa en /proc/stat - calcule su promedio con la misma técnica, pero solo tiene que leer un archivo.

24

Consulte este paquete http://github.com/c9s/goprocinfo, el paquete goprocinfo hace el análisis sintáctico para usted.

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

Excelente biblioteca, gracias. ¡Hace más que eso! – lzap

3

Aquí es una solución independiente OS utilizando Cgo para aprovechar la función clock() proporcionada por 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

Puede simplificar 'time.Now(). Sub (startTime)' a 'time.Since (startTime)'. –

+0

Gracias por la sugerencia, ejemplo actualizado. –

+0

Nota: 'reloj()' da la hora del proceso actual solamente. –

0

recientemente que tenía que tomar mediciones de uso de la CPU de una frambuesa Pi (Raspbian OS) y se utiliza github.com/c9s/goprocinfo combinado con lo que se propone aquí:

La idea viene del código htop origen y es tener dos mediciones (anterior/actual) con el fin de calcular el uso de la 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 
} 

Para más también se puede comprobar https://github.com/tgogos/rpi_cpu_memory