Pantalla LCD personalizada para ODROID CloudShell y CloudShell 2

Este artículo no es guía paso a paso para crear una pantalla de información personalizada, sino que más bien tiene un enfoque general. Para continuar, necesitarás unos conocimientos básicos de programación. Cualquier lenguaje de programación servirá, ya que mostraré dónde y cómo encontrar la información que necesitamos para alcanzar nuestro objetivo. Dicho esto, también he incluido un enlace al proyecto al final del artículo, el cual está escrito en lenguaje Go.

Si tiene una carcasa ODROID CloudShell o CloudShell 2, es muy probable que hayas utilizado el paquete cloudshell-lcd y hayas comprobado lo útil que resulta la pantalla de información. Mi problema era que quería que se mostrara más información y que el texto pequeño que aparece resultaba muy difícil de leer desde el otro lado de la sala. Quería algo más visual que se pudiera leer rápidamente y entender al instante. Las barras de progreso parecían una buena solución, así que me centre en ello. La mayoría de la información necesaria se podía recopilar leyendo archivos de /proc en Linux, esto se puede conseguir con el sistema de archivos linproc.

Uso de CPU

Consciente de que quería estadísticas sobre la CPU, RAM, Memoria de intercambio, sistema de red y almacenamiento, tenía suficiente para empezar. Linux permite que el uso de la CPU y la mayoría de las estadísticas, sea bastante fácil de obtener con la información disponible en '/proc/stat'. Hay más información disponible en http://bit.ly/2jGKrRd. La primera línea nos proporciona un conjunto de estadísticas básicas, con los siguientes campos representados:

* user: Tiempo consumido en modo usuario * nice: Tiempo consumido en modo usuario con baja prioridad (agradable) * system: Tiempo consumido en modo sistema * idle: Tiempo consumido en reposo sin tareas activas * iowait: Tiempo de espera hasta completar E/S. Poco fiable, ver página de manual proc(5) para más detalles.

* irq: Tiempo de interrupción del servicio * softirq: Tiempo del servicio softirqs * steal: Tiempo robado, tiempo consumido en otros sistemas operativos, en cargas de trabajo de virtualización * guest: Tiempo dedicado a ejecutar una CPU virtual para sistemas operativos invitados (cargas de trabajo virtuales) * guest_nice: Tiempo dedicado a ejecutar un invitado niced (cargas de trabajo virtuales)

Dado que el espacio es muy escaso en nuestra pantalla, solo nos preocupamos por la primera línea, ya que nos proporciona las estadísticas totales. El siguiente comando mostrará únicamente la primera línea de '/proc/stat'.

$ head -n1 /proc/stat
 cpu 817905 909158 818680 133949276 2463 0 11128 0 0 0
Para recopilar nuestras estadísticas, necesitamos un delta, esto significa que necesitamos leer el valor, esperar un tiempo, por ejemplo 1 segundo, y luego leer otro. La diferencia entre estos valores nos indica como de ocupado estaba el sistema en ese segundo. Los números serán un poco raros, no parecerán marcas de tiempo. Hay una buena explicación para ello, ya que realmente no lo son. Son un contador para lo que se denomina "jiffies". Para mediciones más precisas, como es el tiempo real del procesador consumido en cada atributo, necesitaríamos encontrar el valor estático HZ del kernel. Este comando debería darnos este valor.
$ zgrep -i hz /proc/config.gz
Este valor es aproximadamente el número de tics por segundo, que suele ser 1000 en la mayoría de las plataformas compatibles con Intel, pero los sistemas embebidos a menudo usan 100. En nuestro caso, solo podemos obtener una medida del proceso frente al tiempo de trabajo:
$ head -n1 /proc/stat ; sleep 1; head -n1 /proc/stat
 cpu 885034 1050588 935349 152731137 2546 0 12670 0 0 0
 cpu 885039 1050588 935350 152731533 2546 0 12670 0 0 0
$ tot1=$((885034 + 1050588 + 935349 + 152731137 + 2546 + 12670))
$ wrk1=$((935349 + 152731137 + 2546 + 12670))
$ tot2=$((885039 + 1050588 + 935350 + 152731533 + 2546 + 12670))
$ wrk2=$((935350 + 152731533 + 2546 + 12670))
$ tot3=$((${tot2} - ${tot1}))
$ wrk3=$((${wrk2} - ${wrk1}))
$ python -c "print((${wrk3}.0 / ${tot3}.0) * 100.0)"

Uso de RAM y de Memoria Intermedia

Las estadísticas de la RAM se pueden coger de múltiples fuentes. Por ejemplo, podrían leerse de '/proc/meminfo'. Sin embargo, decidí no hacerlo porque los valores están en kilobytes en lugar de bytes. Elegí un syscall directo en lugar de tener que abrir un archivo con su correspondiente tratamiento resultante. A continuación, tienes un pequeño programa escrito en GO usando CGO en lugar del paquete syscall, el cual hice para simplicidad las cosas. Utiliza "sysconf (3)", que permite recopilar rápidas estadísticas de memoria. Para más información, visita http://bit.ly/2jBNXfI.

package main

// #include 
 import "C"
 import "fmt"

func main() {
 maxRam := int64(C.sysconf(C._SC_PHYS_PAGES) * C.sysconf(C._SC_PAGE_SIZE))
 freeRam := int64(C.sysconf(C._SC_AVPHYS_PAGES) * C.sysconf(C._SC_PAGE_SIZE))
 usedRam := (maxRam - freeRam)
 ramPercUsed := (float64(usedRam) / float64(maxRam)) * 100.0
 fmt.Println("total =", maxRam)
 fmt.Println("free =", freeRam)
 fmt.Println("used =", usedRam)
 fmt.Println("(used / total) * 100 =", ramPercUsed)
 }
Este método te proporciona tanto la cantidad de páginas de memoria usadas como disponibles. Esto, multiplicado por la constante de tamaño de página del sistema _SC_PAGE_SIZE, nos da la cantidad de memoria utilizada y disponible. Esta estadística fue fácil y tiene menos "partes móviles" que la estadística del uso de la CPU.

Las estadísticas de memoria de intercambio (swap), por otro lado, pueden leerse fácilmente, de modo confiable y sin gasto adicional de cálculo desde el archivo "/proc/swaps". Se parece a esto:

$ cat /proc/swaps
 Filename Type Size Used Priority
 /dev/sda2 partition 8388604 0 -1
 ...
A esto no le hace falta explicación alguna, el tamaño y las columnas usadas se miden en bytes.

Uso de red

Este puede resultar divertido. Primero, necesitas saber qué dispositivo de red deseas medir. Puede buscar esta lista de múltiples formas. Una forma sería analizar el resultado "ifconfig -a" o "ip addr". Éste es un poco engorroso si lo comparamos con otros métodos, como es hacer una relación de los contenidos de "/sys/class/net/". En mi sistema, esto devuelve "eth0", "lo" y "wlan0". Conseguir la velocidad de la interfaz es tan simple como usar el siguiente comando:

$ cat /sys/class/net/eth0/speed
 1000
El siguiente paso es medir nuestro rendimiento. Tomaremos valores periódicos como los que usamos para medir el consumo de la CPU. En este artículo, me centraré en la interfaz eth0, y los datos que busco se encuentran en "/sys/class/net/eth0/statistics/rx_bytes" y "/sys/class/net/eth0/statistics/tx_bytes ". Tienen el siguiente formato, el cual nos proporciona con facilidad métricas de red básicas:
$ cat /sys/class/net/eth0/statistics/rx_bytes
 324429106

Uso del Disco

Aquí podemos medir dos tipos de uso del disco: el rendimiento y la capacidad. El primero se puede extraer de forma similar a otras estadísticas que hemos recopilado hasta ahora del directorio "/proc". El archivo "/proc/diskstats" almacenará datos similares a los siguientes:

8 0 sda 52410 323 1699276 29193 450364 121816 4772512 41466 0 19286 70376
 8 1 sda1 101 0 6594 93 1 0 8 0 0 70 93
 8 2 sda2 46 0 4424 43 0 0 0 0 0 33 43
 8 3 sda3 52238 323 1686170 29020 448708 121816 4772504 41316 0 19113 70040
 8 16 sdb 81 0 4184 33 0 0 0 0 0 16 33
Los campos están definidos en el árbol de fuentes del kernel de Linux en el archivo "Documentation/iostats.txt":

  • Major number
  • Minor number
  • Device name
  • Reads completed
  • Reads merged
  • Sectors read
  • Time spent reading (in ms)
  • Writes completed
  • Writes merged
  • Sectors written
  • Time spent writing (in ms)
  • Iops currently in progress
  • Time spent in iops (in ms)
  • Weighted time spent in iops (in ms)

Es fácil encontrar las mediciones de rendimiento, pero ¿qué pasa con la capacidad del disco? Una forma de hacerlo es con un poco de C (o Go, Rust, Nim, Python, Ruby o cualquier otro que pueda interactuar con C) y el syscall "statfs (2)". Go tiene un paquete syscall, como he mencionado anteriormente, que voy a usar nuevamente para este ejemplo en particular:

package main

import (
 "fmt"
 "syscall"
 )

func main() {
 stat := &syscall.Statfs_t{}
 syscall.Statfs("/", stat)
 fmt.Println("Total space:", (stat.Blocks * uint64(stat.Bsize)))
 fmt.Println("Free space :", (stat.Bfree * uint64(stat.Bsize)))
 }
Guardar ese código en un archivo como "disk.go" y ejecutándolo te proporcionará:
$ go run disk.go
 Total space: 87352057856
 Free space : 35807154176
The new LCD status display on the CloudShell La nueva pantalla LCD de estado en el CloudShell

¡Este proyecto me ha resultado muy divertido, ya que me ha dado la oportunidad de probar cosas nuevas como CGO! Espero que tú también le hayas sacado partido. El proyecto al que aludí al principio se puede encontrar en GitHub en http://bit.ly/2hEUa6B.

Be the first to comment

Leave a Reply