Articulo de referencia

Carga (computación)

htop muestra una carga de computación significativa (arriba a la derecha: Carga promedio: ) En los sistemas informáticos UNIX , la carga del sistema es una medida de la cantidad...

htop muestra una carga de computación significativa (arriba a la derecha: Carga promedio: )

En los sistemas informáticos UNIX , la carga del sistema es una medida de la cantidad de trabajo computacional que realiza un sistema informático. La carga promedio representa la carga promedio del sistema durante un período de tiempo. Generalmente se presenta en forma de tres números que representan la carga del sistema durante los últimos uno, cinco y quince minutos.

Carga

El número de carga de Unix se refiere a la cantidad de procesos que utilizan o esperan CPU ; es decir, la cantidad de procesos en la cola de listos o en la cola de ejecución . Un ordenador inactivo tiene un número de carga de 0 (el proceso inactivo no se cuenta). Cada proceso en ejecución incrementa el número de carga en 1. Cada proceso que finaliza lo decrementa en 1. La mayoría de los sistemas UNIX solo cuentan los procesos en estado de ejecución (en CPU) o en estado ejecutable (esperando CPU) (estado R).

Además de los procesos en estado "R", Linux también incluye procesos en estados de suspensión ininterrumpible (generalmente esperando actividad del disco ; estado "D"), lo que puede generar resultados marcadamente diferentes si muchos procesos permanecen bloqueados en E/S debido a un sistema de E/S ocupado o bloqueado. [ 1 ] Esto incluye, por ejemplo, procesos bloqueados debido a una falla del servidor NFS o a medios demasiado lentos (por ejemplo, dispositivos de almacenamiento USB 1.x). Tales circunstancias pueden resultar en una carga promedio elevada, que no refleja un aumento real en el uso de la CPU. La idea detrás de su inclusión es que, si bien la espera del disco no es lo mismo que la espera de la CPU, aún refleja cuánto tiempo necesita esperar un usuario.

En los sistemas UNIX modernos, el tratamiento de los hilos con respecto a las cargas promedio varía. Algunos sistemas tratan los hilos como procesos para el cálculo de la carga promedio: cada hilo en espera de ejecución suma 1 a la carga. Sin embargo, otros sistemas, especialmente aquellos que implementan el llamado sistema de hilos M:N , utilizan estrategias diferentes, como contar el proceso exactamente una vez para el cálculo de la carga (independientemente del número de hilos), o contar solo los hilos que el planificador de hilos de usuario expone actualmente al kernel, lo cual puede depender del nivel de concurrencia establecido en el proceso. Linux parece contar cada hilo por separado, sumando 1 a la carga. [ 2 ]

No existe una forma estándar de obtener la longitud de la cola de ejecución en diferentes sistemas tipo Unix, [ a ] ​​pero una forma comúnmente disponible es mediante el análisis de la salida del comando psps -ax -o stat , específicamente , y contando el número de líneas que comienzan con "R" (correspondiente a procesos en el estado "R"). Si se desea, también se puede agregar el estado de espera "disco" ininterrumpible , etiquetado como "D" en Linux y FreeBSD, "U" en macOS . -Mse puede usar para obtener información por hilo en Linux y macOS, pero no en FreeBSD, donde la opción es en su lugar -H. [ 4 ] (La carga informada nunca será 0, ya que el psproceso en sí se cuenta. Para obtener la carga real, reste uno al conteo).

En Linux específicamente, el archivo procfs/proc/stat contiene dos líneas procs_runningy procs_blocked, que corresponden a entidades de planificación (procesos/hilos) en estados "R" y "D" respectivamente. Esto se puede usar para leer la carga actual en lugar de ps. Como antes, la carga reportada incluye el programa que actualmente está leyendo el archivo procfs, así que reste uno de la suma para obtener la carga real. [ 5 ]

En comparación con la utilización de la CPU

El estudio comparativo de diferentes índices de carga realizado por Ferrari et al. informó que la información de carga de la CPU basada en la longitud de la cola de la CPU funciona mucho mejor en el equilibrio de carga en comparación con la utilización de la CPU. La razón por la que la longitud de la cola de la CPU funcionó mejor es probablemente porque cuando un host está muy cargado, su utilización de la CPU es probable que esté cerca del 100%, y no puede reflejar el nivel de carga exacto de la utilización. Por el contrario, las longitudes de las colas de la CPU pueden reflejar directamente la cantidad de carga en una CPU. Por ejemplo, dos sistemas, uno con 3 y el otro con 6 procesos en la cola, tienen muy probabilidades de tener ambas utilizaciones cercanas al 100%, aunque obviamente diferirían en términos de tiempos de espera de los procesos. [ 6 ]

Carga promedio

Todos los sistemas Unix y similares generan una métrica adimensional de tres números de "carga promedio" en el núcleo . Los usuarios pueden consultar fácilmente el resultado actual desde un intérprete de comandos Unix ejecutando el uptimecomando:

$ uptime 14:34:03 up 10:43, 4 usuarios, carga promedio: 0.06, 0.11, 0.09

Los comandos wy topmuestran los mismos tres números de carga promedio, al igual que una variedad de utilidades de interfaz gráfica de usuariogetloadavg() . La interfaz subyacente es , una función C presente en la mayoría de los sistemas UNIX desde 4.3BSD-Reno de 1990 (pero no forma parte de POSIX ). [ 7 ] En Linux específicamente, también se puede leer /proc/loadavgpara obtener esta información. Este archivo también proporciona información instantánea sobre el número de procesos en estado "R", el número total de procesos y el ID del proceso creado más recientemente. [ 8 ]

Los sistemas calculan la carga promedio como el promedio móvil ponderado/amortiguado exponencialmente del número de carga . Los tres valores de carga promedio se refieren a los últimos uno, cinco y quince minutos de funcionamiento del sistema. [ 9 ]

Matemáticamente hablando, los tres valores siempre promedian toda la carga del sistema desde su inicio. Todos decaen exponencialmente, pero a diferentes velocidades : decaen exponencialmente por e después de 1, 5 y 15 minutos respectivamente. Por lo tanto, el promedio de carga de 1 minuto consiste en el 63% (más precisamente: 1 - 1/ e ) de la carga del último minuto y el 37% (1/ e ) de la carga promedio desde el inicio, excluyendo el último minuto. Para los promedios de carga de 5 y 15 minutos, se calcula la misma proporción de 63%/37% sobre 5 y 15 minutos, respectivamente. Por lo tanto, no es técnicamente exacto que el promedio de carga de 1 minuto solo incluya los últimos 60 segundos de actividad, ya que incluye el 37% de la actividad pasada, pero es correcto afirmar que incluye principalmente el último minuto.

Interpretación

En sistemas con un solo procesador, donde el rendimiento está limitado por la CPU , la carga promedio puede considerarse una medida de la utilización del sistema durante el período de tiempo correspondiente. En sistemas con múltiples procesadores, se debe dividir la carga entre el número de procesadores para obtener una medida comparable.

Por ejemplo, se puede interpretar una carga promedio de "1,73 0,60 7,98" en un sistema de una sola CPU como:

  • Durante el último minuto, el sistema se sobrecargó en un 73% de media (1,73 procesos ejecutables, de modo que 0,73 procesos tuvieron que esperar su turno para un sistema con una sola CPU de media).
  • Durante los últimos 5 minutos, la CPU estuvo inactiva el 40% del tiempo, en promedio.
  • Durante los últimos 15 minutos, el sistema estuvo sobrecargado un 698% de media (7,98 procesos ejecutables, de modo que 6,98 procesos tuvieron que esperar su turno para un sistema con una sola CPU de media).

Esto implica que este sistema podría haber gestionado todo el trabajo programado para el último minuto si fuera 1,73 veces más rápido.

En un sistema con cuatro CPU, una carga promedio de 3,73 indicaría que, en promedio, hay 3,73 procesos listos para ejecutarse. Dado que este valor es menor que 4, sabemos que cada uno podría asignarse a una CPU y que no existe sobrecarga.

Calculando la carga de la CPU

Linux como ejemplo

En los sistemas Linux, la carga promedio no se calcula en cada ciclo de reloj, sino que se basa en un valor variable que depende de la HZconfiguración de frecuencia y se prueba en cada ciclo de reloj. Esta configuración define la frecuencia de ciclo del reloj del kernel en hercios (veces por segundo) y su valor predeterminado es 100.Ticks de 10 ms  . Las actividades del kernel utilizan este número de ticks para cronometrarse. Específicamente, la calc_load()función (en loadavavg.h, anteriormente sched.h), que calcula la carga promedio, se ejecuta nominalmente cada LOAD_FREQ (5*HZ+1)ticks, es decir, un poco más5  s .

extern unsigned long avenrun []; /* Promedios de carga */ extern void get_avenrun ( unsigned long * loads , unsigned long offset , int shift );#define FSHIFT 11 /* número de bits de precisión */ #define FIXED_1 (1<<FSHIFT) /* 1.0 como punto fijo */ #define LOAD_FREQ (5*HZ+1) /* intervalos de 5 segundos */ #define EXP_1 1884 /* 1/exp(5seg/1min) como punto fijo */ #define EXP_5 2014 /* 1/exp(5seg/5min) */ #define EXP_15 2037 /* 1/exp(5seg/15min) *//* a1 = a0 * e + a * (1 - e) */ static inline unsigned long calc_load ( unsigned long load , unsigned long exp , unsigned long active ) { unsigned long newload ;nuevacarga = carga * exp + activo * ( FIJO_1 - exp ); si ( activo >= carga ) nuevacarga += FIJO_1 -1 ;devolver newload / FIXED_1 ; }extern unsigned long calc_load_n ( unsigned long load , unsigned long exp , unsigned long active , unsigned int n );#define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)

El array avenrun contiene promedios de 1 minuto, 5 minutos y 15 minutos. La calc_load()función proporciona la actualización correcta del promedio de carga para la tasa de actualización predeterminada de LOAD_FREQ (5*HZ+1). [ 10 ] Se utiliza de la siguiente manera en loadavg.c (anteriormente sched.c): [ 11 ]

void calc_global_load ( void ) { unsigned long sample_window ; long active , delta ;sample_window = READ_ONCE ( calc_load_update ); if ( time_before ( jiffies , sample_window + 10 )) return ;/*  * Pliega el delta NO_HZ 'antiguo' para incluir todas las CPU NO_HZ.  */ delta = calc_load_nohz_read (); if ( delta ) atomic_long_add ( delta , & calc_load_tasks );activo = lectura_larga_atómica ( & calc_load_tasks ); activo = activo > 0 ? activo * FIXED_1 : 0 ;avenrun [ 0 ] = calc_load ( avenrun [ 0 ], EXP_1 , active ); avenrun [ 1 ] = calc_load ( avenrun [ 1 ], EXP_5 , active ); avenrun [ 2 ] = calc_load ( avenrun [ 2 ], EXP_15 , active );ESCRIBIR_UNA_VEZ ( calc_load_update , sample_window + LOAD_FREQ );/*  * En caso de que hayamos ido a NO_HZ durante varios intervalos LOAD_FREQ  , * recuperaremos en bloque.  */ calc_global_nohz (); }

Tenga en cuenta este manejo de las CPU NO_HZ. NO_HZ es un modo diseñado para reducir el número de interrupciones del reloj de planificación en procesadores inactivos, lo que mejora la eficiencia energética y reduce la fluctuación del reloj. Sin embargo, esto provocaría que los procesadores perdieran sus ciclos de actualización. Como resultado, el conteo de tareas se realiza mediante operaciones atómicas. La función calc_global_nohzmaneja el cálculo en caso de necesitar ponerse al día con varios ciclos, utilizando esta función:

/* [1] aplicación de la serie geométrica: * n 1 - x^(n+1) * S_n := \Sum x^i = ------------- * i=0 1 - x */ unsigned long calc_load_n ( unsigned long load , unsigned long exp , unsigned long active , unsigned int n ) { return calc_load ( load , fixed_power_int ( exp , FSHIFT , n ), active ); }

Aquí fixed_power_int(no incluido en el artículo) se eleva exp a su enésima potencia en aritmética de punto fijo.

Muestreo y precisión

El cálculo "muestreado" de los promedios de carga es un comportamiento bastante común; FreeBSD también actualiza el valor cada cinco segundos. El intervalo generalmente no se considera exacto para evitar que se registren procesos programados para ejecutarse en un momento determinado. Esta es la razón del "+1" en el código de Linux mencionado anteriormente; FreeBSD, en cambio, utiliza un desplazamiento pseudoaleatorio que se suma al intervalo. [ 12 ]

loadavg.hTambién se menciona que el uso de 11 bits fraccionarios en el cálculo de punto fijo anterior impide reducir el intervalo ( LOAD_FREQ) mucho más. Por ejemplo, un intervalo de dos segundos daría como resultado que los valores EXP fueran 1981, 2034 y 2043, saturando casi por completo la precisión disponible (0 2047). [ 10 ]

Ripke Klaus demostró en 2011 que la modificación "+1" por sí sola no es suficiente para evitar artefactos de Moiré de procesos programados regularmente. Sus experimentos sugieren que 4,61 es un mejor valor: 0,61 está cerca de la proporción áurea , lo que ayuda a distribuir el punto de muestreo entre fracciones de segundo. Al mismo tiempo, 4,61 está cerca de 60/13 , por lo que la propiedad de5  s siendo una fracción entera de Se mantiene 60 s . [ 13 ] [ 14 ] El cambio de Ripke es común entre los núcleos del sistema Android , aunque la expresión exacta utilizada ( 4*HZ+61) asume un HZ de 100. [ 15 ]60*HZ/13 sería más apropiado para valores variables de HZ. Los nuevos valores serían: [ 14 ]

#define LOAD_FREQ (60*HZ/13) /* 60/13 ~ intervalos de 4,61 segundos */ #define EXP_1 1896 /* 1/exp(4,61seg/1min) = 1/exp(1/13) como punto fijo */ #define EXP_5 2017 /* 1/exp(4,61seg/5min) = 1/exp(1/13/5) */ #define EXP_15 2038 /* 1/exp(4,61seg/15min) = 1/exp(1/13/15) */

Cálculo desde el espacio de usuario

Como ya hemos comentado, la mayoría de los kernels utilizan aritmética de punto fijo para calcular la carga promedio, lo que resulta eficiente y sencillo. Sin embargo, esto limita la frecuencia de actualización y la precisión alcanzables. Dado que ya sabemos cómo obtener la carga instantánea desde el espacio de usuario, también es posible calcular la carga promedio desde ese mismo espacio. El siguiente código lo hace en Python, utilizando una frecuencia de actualización de φ 1,618 segundos, en intervalos de tiempo que van desde 10 segundos hasta 1 hora:

#!/usr/bin/env python3hora de importaciónimportar sistema operativofrom datetime import datetimefrom math import exp , logfrom dataclasses import dataclassPERÍODOS DE LOGÍSTICA = [ log ( x ) para x en [ 60 , 300 , 900 ]]FRECUENCIA_DE_ACTUALIZACIÓN = (( 5 ** 0.5 ) + 1 ) / 2 # Proporción áurea de RipkePERÍODOS = [ 10 , 30 , 60 , 120 , 300 , 900 , 1800 , 3600 ]COUNT_DISKWAIT = True # Indica si se debe incluir la espera del disco en el cálculo de la carga@clase de datosclase LoadEntry :promedio : flotanteexp : flotantedef initialize_loads ( now : int | float , lavgs : dict [ int , LoadEntry ]):"""Inicializar los promedios de carga basándose en la interpolación lineal de los promedios de carga del sistema y el recuento de carga instantáneo."""sys = getloadavg ()pendientes = (( sys [ 0 ] - ahora ) / 60 , ( sys [ 1 ] - sys [ 0 ]) / 240 , ( sys [ 2 ] - sys [ 1 ]) / 600 )para el período en [ 10 , 30 , 60 , 120 , 300 , 900 , 1800 , 3600 ]:exp_factor = exp ( - REFRESH_RATE / period )si el período < 60 :est_avg = ahora + pendientes [ 0 ] * ( periodo - 60 )elif period < 300 :est_avg = sys [ 0 ] + slopes [ 1 ] * ( period - 300 )demás :est_avg = sys [ 1 ] + slopes [ 2 ] * ( period - 900 )lavgs [ periodo ] = LoadEntry ( avg = max ( est_avg , 0 ), exp = exp_factor )def update_loads ( lavgs : dict [ int , LoadEntry ], current_load : int | float ) -> None :para _ , entrada en lavgs . items ():entrada.promedio = entrada.promedio * entrada.exp + carga_actual * ( 1 - entrada.exp )si os.name == " posix " :uname = os . uname ()[ 0 ] . más bajo ()getloadavg = os.getloadavgsi uname == "linux" :def get_current_load () -> int :carga = 0con open ( "/proc/stat" , "r" ) como f :para cada línea en f :si la línea comienza con ( "procs_running" ):cargar += int ( línea . split ()[ 1 ]) # Leer procs_runningcarga -= 1 # Resta uno por ti mismoelif line . startswith ( "procs_blocked " ) and COUNT_DISKWAIT :cargar += int ( línea . split ()[ 1 ]) # Leer procs_blockedcarga de retornodemás :PS_THREAD_OPTION = "-H" if os . uname ()[ 0 ] . lower () . endswith ( "bsd" ) else "-M"PS_DISK_WAIT = "U" if os . uname ()[ 0 ] == "Darwin" else "D"PS_STATES = ( "R" + PS_DISK_WAIT ) si COUNT_DISKWAIT sino "R"def get_current_load () -> int :con os.popen ( f "ps { PS_THREAD_OPTION } ax -o stat" , " r " ) como f :estados = map ( f , lambda línea : línea . split ()[ - 1 ]) # Obtener la última columna. ¡Requerido en macOS!devolver suma ( 1 si estado [ 0 ] en PS_STATES sino 0 para estado en estados ) - 1elif os . name == "nt" :# Es posible utilizar los contadores de rendimiento de Windows para obtener la longitud de la cola.# De hecho, Microsoft lo recomienda como una métrica adicional para la carga, además del uso de la CPU:# https://learn.microsoft.com/en-us/biztalk/technical-guides/using-the-performance-analysis-of-logs-pal-tool#processor-queue-length-analysis# Usándolo también podemos obtener una carga similar a la de los sistemas Unix.from pyperfmon import pyperfmonpm = pyperfmon.pyperfmon ( )núcleos = os.cpu_count ( )obtener_contador = lambda x : pm . obtenerContador ( x )def get_current_load () -> float :devolver (# Hilos esperando CPU, no los que se están ejecutandoobtener_contador ( r "Longitud de la cola del procesador\Sistema" )# Número aproximado de subprocesos que utilizan la CPU+ get_counter ( r "Processor_Total_% Processor Time" ) * ncores# Hilos esperando E/S de disco+ get_counter ( r "Longitud total de la cola de disco actual del disco físico" )si COUNT_DISKWAITde lo contrario 0)def getloadavg () -> tupla [ float , float , float ]:# Implementación ficticia para Windowscarga = obtener_carga_actual ()devolver ( cargar , cargar , cargar )def principal ():lavgs : dict [ int , LoadEntry ] = {}carga_actual = obtener_carga_actual ()inicializar_cargas ( carga_actual , lavgs )encabezado = [ "SYSTIME" , " CURR" ] + [ str ( x ) para x en PERIODOS ]imprimir ( " \t " . unir ( encabezado ))mientras sea verdadero :# Imprimir siempre antes de recalcularentradas = [ f " { datetime . now () . strftime ( '%H:%M:%S' ) } { current_load : .4f } " ]entradas += [ f " { entrada . promedio : .4f } " para entrada en valores promedio . valores ()]print ( " \t " . join ( entries ), flush = True )# Dormir y esperar. Esto supone que el tiempo utilizado para actualizar una nueva línea es# minúsculo comparado con el tiempo dormido. Si este no es el caso, un# Se debe utilizar el cálculo de tipo sleepuntil().tiempo.dormir ( REFRESH_FATE )# Imprimircarga_actual = obtener_carga_actual ()actualizar_cargas ( lavgs , carga_actual )Si __name__ == "__main__" :principal ()

Otros comandos de rendimiento del sistema

Otros comandos para evaluar el rendimiento del sistema incluyen:

  • uptime  la fiabilidad del sistema y la carga media
  • top  para una visión general del sistema
    • htop  visor de procesos interactivo
  • btop  otra herramienta para visualizar el sistema en general
  • vmstat  vmstat informa sobre los procesos ejecutables o bloqueados, la memoria, la paginación, la E/S de bloques, las interrupciones y la CPU.
  • dool(anteriormente dstat), [ 16 ] ayuda a correlacionar todos los datos de recursos existentes para procesos, memoria, paginación, E/S de bloques, trampas y actividad de la CPU.atop 
  • iftop  Visualizador interactivo de tráfico de red por interfaz
  • nethogs  Visualizador interactivo de tráfico de red por proceso
  • iotop  Visor de E/S interactivo [ 17 ]
  • iostat  para estadísticas de E/S de almacenamiento
  • netstat  para estadísticas de red
  • mpstat  para estadísticas de la CPU
  • tload  Gráfico de carga promedio para terminal
  • xload  Gráfico de carga promedio para X

Véase también

Notas

  1. La parte opcional XSI de POSIX sí proporcionaps -axl, que da una salida de varias columnas que contiene el estado que se puede analizar. [ 3 ] Desafortunadamente, está implementado de forma aún menos consistente que-o staty requiere más trabajo para analizar.

Referencias

  1. "Soporte técnico de Linux: ¿Qué es exactamente una carga promedio?" . 23 de octubre de 2008.
  2. Ver http://serverfault.com/a/524818/27813
  3. Shell and Utilities Reference, The Single UNIX Specification , Versión 5 de The Open Groupps  
  4. "Estadísticas diversas del kernel en /proc/stat" . Consultado el 4 de octubre de 2023 .
  5. Ferrari, Domenico; y Zhou, Songnian; " Una investigación empírica de los índices de carga para aplicaciones de equilibrio de carga ", Actas de Performance '87, XII Simposio Internacional sobre Modelado, Medición y Evaluación del Rendimiento Informático, North Holland Publishers, Ámsterdam, Países Bajos, 1988, págs. 515-528.
  6. Manual de llamadas al sistema de FreeBSDgetloadavg(2)  
  7. Manual del programador de Linux – Formatos de archivo de Manned.orgproc_loadavg(5)  
  8. Walker, Ray (1 de diciembre de 2006). "Examinando la carga promedio" . Linux Journal . Recuperado el 13 de marzo de 2012 .
  9. 1 2 "Linux v6.17 :: include/linux/sched/loadavg.h" . 
  10. "Linux v6.17 :: kernel/sched/loadavg.c" . 
  11. "¿Cómo se calcula la carga promedio en FreeBSD?" . Unix & Linux Stack Exchange .
  12. Ripke, Klaus (2011). "Archivo del kernel de Linux: evita el efecto moiré" . lkml.iu.edu .LOAD_FREQ (4*HZ+61)loadavg
  13. ^ Ripke , Klaus (2011). "Patrones de muaré en promedio de carga de Linux" .(Gráfico que muestra el patrón; comentario posterior para 60*HZ/13)
  14. "Parchear el kernel con la función de carga de 4,61 s · Problema n.º 2109 · AOSC-Dev/aosc-os-abbs" . GitHub .
  15. Baker, Scott (28 de septiembre de 2022). "dool - Clon de dstat compatible con Python 3" . GitHub . Consultado el 22 de noviembre de 2022. ... Dag Wieers dejó de desarrollar Dstat...
  16. "Iotop(8) - Página del manual de Linux" .
  • Brendan Gregg (8 de agosto de 2017). "Promedios de carga de Linux: resolviendo el misterio" . Recuperado el 22 de enero de 2018 .
  • Neil J. Gunther . "Promedio de carga en UNIX : Parte 1: Cómo funciona"  (PDF) . TeamQuest . Consultado el 12 de agosto de 2009 .
  • Andre Lewis (31 de julio de 2009). "Comprender la carga de la CPU en Linux : ¿cuándo debería preocuparse?"  . Consultado el 21 de julio de 2011 .Explicación mediante una analogía ilustrada sobre el tráfico.
  • Ray Walker (1 de diciembre de 2006). "Examinando la carga promedio" . Linux Journal . Recuperado el 21 de julio de 2011 .
  • Karsten Becker. "Conjunto de herramientas de monitorización de carga de software de código abierto para Linux" . LoadAvg.