...¿pero realmente tenemos que ir armados para comprar algo de RAM?... |
#include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> #include <linux/kernel.h> #include <stdlib.h> #include <stdio.h> #include <sys/sysinfo.h> // struct para los resultados typedef struct { ... } Results; // prototipos locales void testSys(Results *results); void *tMyThread(void *arg); // función main() int main(int argc, char *argv[]) { // init thread pthread_t tid; int error; if ((error = pthread_create(&tid, NULL, &tMyThread, NULL)) != 0) printf("%s: no puedo crear el thread (%s)\n", argv[0], strerror(error)); // llama testSys() para primer set valores estáticos Results results; testSys(&results); sleep(2); // testSys() loop para testear repetidamente el sistema for (;;) { // get valores testSys(&results); printf("cpu: total usage = %.1f\n", results.total_cpu / results.prec); printf("mem: total usage = %.1f\n", results.mem_system / results.prec); printf("cpu: proc usage = %.1f\n", results.proc_cpu / results.prec); printf("mem: proc usage = %.1f\n", results.mem_proc / results.prec); printf("load average: %.2f , %.2f , %.2f\n", results.loads[0] / results.loads_prec, results.loads[1] / results.loads_prec, results.loads[2] / results.loads_prec); // sleep 2 segundos sleep(2); } // exit exit(EXIT_SUCCESS); } // función de test del sistema void testSys( Results *results) // destinación de los resultados { ... } // thread routine void *tMyThread(void *arg) { // alloc memoria unsigned long mem = 1024 * 1024 * 512; // 512 mb char *ptr = malloc(mem); // thread loop infinito for (;;) { // usa memoria memset(ptr, 0, mem); // thread sleep usleep(10); // NOTA: sleep muy pequeña para forzar mucha actividad de cpu } return NULL; }Como podeis ver, el programa es de una simplicidad desarmante (y con excelentes comentarios, como de costumbre). Para estresar la CPU y la Memoria he utilizado algunos simples trucos: asigno (con malloc()) un megabúfer de 512MB, y luego en un loop infinito lo uso intensamente (con una memset() completa). El ciclo del thread una usleep muuuuy pequeña (10 us) que carga mucho la CPU (que nos odiará un poco, pero es el objetivo del nuestro test, ¿no?).
Ahora viene lo bueno: como se ha mencionado varias veces en el post anterior, nuestra referencia es el comando top de la familia UNIX así que tenemos que abrir dos terminales, y en una ejecutamos nuestro programa de test, y en la otra ejecutamos top para poder comparar en tiempo real si los resultados coinciden (recordaros de activar la opción "I" de top, como descrito en el otro post). Veamos qué ha pasado en mi ordenador:
en la terminal con testsys ... load average: 0.85 , 0.42 , 0.32 cpu: total usage = 12.9 mem: total usage = 47.8 cpu: proc usage = 12.5 mem: proc usage = 6.9 ... en la terminal con top top - 18:45:16 up 39 min, 2 users, load average: 0,85, 0,42, 0,32 Tasks: 236 total, 1 running, 235 sleeping, 0 stopped, 0 zombie %Cpu(s): 12,5 us, 0,1 sy, 0,0 ni, 87,2 id, 0,0 wa, 0,0 hi, 0,1 si, 0,0 st KiB Mem : 7600656 total, 3962420 free, 1705536 used, 1932700 buff/cache KiB Swap: 0 total, 0 free, 0 used. 5384092 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 5266 aldo 20 0 604548 524744 628 S 12,5 6,9 0:43.01 testpstat 1380 root 20 0 559772 94056 82400 S 0,1 1,2 0:43.89 Xorg 1012 root 20 0 4396 1276 1196 S 0,0 0,0 0:00.07 acpid 2628 aldo 20 0 2542528 358152 128056 S 0,0 4,7 3:18.25 firefox ...dado que la salida es continua, he seleccionado solo una parte y he agregado las elipsis, en cualquier caso podéis repetir fácilmente el test en el vuestro ordenador para verificar la consistencia de los resultados: yo diría que el resultado es más que satisfactorio, ¿no? ¡Misión cumplida!
¿Qué falta? Ah, sí, prometí algunas notas sobre los resultados que muestra top (y, consecuentemente, también el nuestro testsys): en lo que concierne a la CPU, los comentarios en el codigo de la testSys() son suficientes (descripción de las cargas medias, opción "I", etc.). Además, podemos agregar que la línea %Cpu(s) mostrada arriba confirma las fórmulas contenidas (y comentadas) en testSys(): por ejemplo, la suma de los diversos componentes (user, idle, sys, etc.) vale, como esperado, 100.
Para la memoria, sin embargo, el discurso es un poco más complejo, y habria que dedicar un post dedicado (tal vez lo haré en el futuro): por el momento os paso un enlace interesante: understanding-memory-usage-on-linux, y os añado sólo una explicación muy simple de algo (extraño) que a veces ocurre en sistemas embedded echos con BusyBox: en algunos casos parece que algunos procesos usan más del 100% de la memoria (en la columna %MEM): esto se debe al hecho de que está utilizando una versión antigua de top proporcionada por BusyBox que calcula %MEM como VSZ/MemTotal en lugar de RSS/MemTotal: debemos tener en cuenta que RSS es un valor residente mientras VSZ es un valor virtual, que por lo tanto está influenciado, por ejemplo, de eventuales shared library que se cargan y se comparten entre varias aplicaciones, de páginas de memoria no utilizadas en ese momento, etc., por lo que no es sorprendente que el valor exceda el 100%. Sin embargo, las nuevas versiones de top para BusyBox redefinen la columna %MEM en %VSZ solucionando así cualquier malentendido (oops... el significado de las siglas extrañas anteriores lo vais a encontrar en los comentarios de testSys(), en el manual de top y en el enlace que os he pasado sobre la memoria de Linux).
Bueno, yo diría que para este post es suficiente. Os dejo con una pequeña nota: dado que he utilizado solamente loop infinitos en el programa de test, podéis modificarlo a vuestro gusto añadiendo condiciones de salida. O, en alternativa, no tengáis miedo de detenerlo con CTL-C, no creo que Linux se enfade mucho...
¡Hasta el próximo post!