Ventajas y desventajas de HugePages


Se preparó una traducción del artículo para los estudiantes del curso de Administrador de Linux .




Anteriormente, hablé sobre cómo probar y habilitar el uso de Hugepages en Linux.
Este artículo solo será útil si realmente tiene dónde usar Hugepages. He conocido a muchas personas que están engañadas por la posibilidad de que Hugepages aumente mágicamente la productividad. Sin embargo, la paginación enorme es un tema complejo y, si se usa incorrectamente, puede reducir el rendimiento.


Parte 1: verifique que las páginas gigantes estén incluidas en Linux (original aquí )


Problema:
Debe verificar si HugePages está habilitado en su sistema.


Solución:
Es bastante simple:


cat /sys/kernel/mm/transparent_hugepage/enabled 

Obtendrás algo como esto:


 always [madvise] never 

Verá una lista de opciones disponibles ( siempre, madvise, nunca ), mientras que la opción activa actual estará entre paréntesis (por defecto, madvise ).


madvise significa que las páginas grandes transparent hugepages solo se incluyen para las regiones de memoria que solicitan explícitamente páginas grandes con madvise (2) .


siempre significa que las transparent hugepages siempre están habilitadas para todos los procesos. Esto generalmente mejora el rendimiento, pero si tiene un caso de uso en el que muchos procesos consumen una pequeña cantidad de memoria, la carga de memoria total puede aumentar drásticamente.


nunca significa que las transparent hugepages no se incluirán incluso cuando se solicite con madvise. Consulte la documentación del kernel de Linux para obtener más información .


Cómo cambiar el valor predeterminado


Opción 1 : cambiar sysfs directamente (después de reiniciar, el parámetro volverá al valor predeterminado):


 echo always >/sys/kernel/mm/transparent_hugepage/enabled echo madvise >/sys/kernel/mm/transparent_hugepage/enabled echo never >/sys/kernel/mm/transparent_hugepage/enabled 

Opción 2 : cambie la configuración predeterminada del sistema volviendo a compilar el núcleo con la configuración modificada (esta opción se recomienda solo si utiliza su propio núcleo):


  • Para establecer siempre el valor predeterminado, use:
     CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y 
  • Para configurar madvise por defecto, use:
     CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y 

Parte 2: Ventajas y desventajas de HugePages


Intentaremos explicar selectivamente las ventajas, desventajas y posibles errores al usar Hugepages. Dado que el artículo tecnológicamente sofisticado y pedante probablemente sea difícil para las personas engañadas al considerar que Hugepages es una panacea, sacrificaré la precisión en aras de la simplicidad. Vale la pena tener en cuenta que muchos temas son realmente complejos y, por lo tanto, muy simplificados.


Tenga en cuenta que estamos hablando de sistemas x86 de 64 bits que se ejecutan en Linux, y que supongo que el sistema admite páginas enormes transparentes (ya que no es una desventaja que las páginas grandes no se reemplacen), como sucede en casi cualquier moderno Entorno Linux.


En los enlaces a continuación adjuntaré una descripción más técnica.


Memoria virtual


Si es un programador de C ++, sabe que los objetos en la memoria tienen direcciones específicas (valores de puntero).


Sin embargo, estas direcciones no reflejan necesariamente las direcciones físicas en la memoria (direcciones en la RAM). Son direcciones en la memoria virtual. El procesador tiene un módulo especial MMU (unidad de administración de memoria) que ayuda al núcleo a asignar la memoria virtual a una ubicación física.


Este enfoque tiene muchas ventajas, pero la más básica de ellas:


  • Rendimiento (por varias razones);
  • Aislamiento de programas, es decir, ninguno de los programas puede leer de la memoria de otro programa.

¿Qué son las páginas?


La memoria virtual se divide en páginas. Cada página individual apunta a una memoria física específica, puede apuntar a una región en la RAM o puede apuntar a una dirección asignada a un dispositivo físico, como una tarjeta de video.


La mayoría de las páginas con las que trata apuntan a RAM o intercambio, es decir, se almacenan en su disco duro o SSD. El núcleo controla el diseño físico de cada página. Si se accede a una página falsificada, el núcleo detiene el hilo que intenta acceder a la memoria, lee la página del disco duro / SSD en la RAM y luego continúa ejecutando el hilo.


Este proceso es transparente para la transmisión, es decir, no necesariamente se lee directamente desde el disco duro / SSD. El tamaño de las páginas normales es de 4096 bytes. Las páginas enormes tienen un tamaño de 2 megabytes.


Memoria intermedia de traducción asociativa (TLB)


Cuando un programa accede a una página de memoria, el procesador central debe saber de qué página física leer los datos (es decir, tener un mapa de direcciones virtuales).


El núcleo tiene una estructura de datos (tabla de páginas) que contiene toda la información sobre las páginas utilizadas. Con esta estructura de datos, puede asignar una dirección virtual a una dirección física.


Sin embargo, la tabla de páginas es bastante compleja y se ejecuta lentamente, por lo que simplemente no podemos analizar la estructura de datos completa cada vez que un proceso accede a la memoria.


Afortunadamente, nuestro procesador tiene un TLB que almacena en caché la asignación de direcciones virtuales y físicas. Esto significa que a pesar del hecho de que necesitamos analizar la tabla de páginas en el primer intento de obtener acceso, todas las llamadas de página posteriores se pueden procesar en el TLB, lo que garantiza un funcionamiento rápido.


Dado que se implementa como un dispositivo físico (lo que lo hace principalmente rápido), su capacidad es limitada. Por lo tanto, si desea acceder a más páginas, TLB no podrá almacenar la asignación para todas ellas, como resultado de lo cual su programa funcionará mucho más lentamente.


Enormes páginas vienen al rescate


Entonces, ¿qué podemos hacer para evitar el desbordamiento de TLB? (Suponemos que el programa todavía necesita la misma cantidad de memoria).


Aquí es donde aparecen las Hugepages. En lugar de 4096 bytes, que requieren solo una entrada en el TLB, una entrada en el TLB ahora puede apuntar a la friolera de 2 megabytes. Asumiremos que el TLB tiene 512 entradas, aquí sin Hugepages podemos igualar:


 4096 b⋅512=2 MB 

Mientras que con ellos podemos comparar:


 2 MB⋅512=1 GB 

Es por eso que Hugepages es increíble. Pueden aumentar la productividad sin un esfuerzo significativo. Pero hay reservas importantes.


Hugepages spoofing


El kernel rastrea automáticamente la frecuencia de uso de cada página de memoria. Si la memoria física (RAM) es insuficiente, el núcleo moverá las páginas menos importantes (de uso menos frecuente) al disco duro para liberar parte de la RAM para páginas más importantes.
Básicamente, lo mismo ocurre con Hugepages. Sin embargo, el núcleo solo puede intercambiar páginas enteras, no bytes individuales.


Supongamos que tenemos un programa como este:


 char* mymemory = malloc(2*1024*1024); //     Hugepage! //  mymemory -  //    , //      mymemory // ... //       putchar(mymemory[0]); 

En este caso, el núcleo necesitará reemplazar (leer) hasta 2 megabytes de información del disco duro / SSD solo para que pueda leer un byte. En cuanto a las páginas normales, solo se deben leer 4096 bytes del disco duro / SSD.


Por lo tanto, si se reemplaza una página enorme, su lectura es más rápida solo si necesita acceder a toda la página. Esto significa que si está intentando acceder aleatoriamente a diferentes partes de la memoria y solo lee un par de kilobytes, debe usar páginas regulares y no preocuparse por nada más.


Por otro lado, si necesita acceder secuencialmente a la mayor parte de la memoria, las grandes páginas aumentarán su productividad. Sin embargo, debe verificar esto usted mismo (y no en el ejemplo del software abstracto) y ver qué funciona más rápido.


Asignación de memoria


Si escribe en C, sabe que puede solicitar cantidades de memoria arbitrariamente pequeñas (o casi arbitrariamente grandes) del montón utilizando malloc() . Digamos que necesita 30 bytes de memoria:


 char* mymemory = malloc(30); 

Puede parecerle al programador que "solicita" 30 bytes de memoria del sistema operativo y devuelve un puntero a alguna memoria virtual. Pero en realidad malloc () es solo una función C que llama a las funciones brk y sbrk desde adentro para solicitar o liberar memoria del sistema operativo.


Sin embargo, solicitar más y más memoria para cada asignación es ineficiente; es muy probable que cualquier segmento de memoria ya haya sido liberado (free()) , y podemos reutilizarlo. malloc() implementa algoritmos bastante complejos para reutilizar la memoria liberada.


Al mismo tiempo, todo pasa desapercibido para usted, entonces, ¿por qué debería preocuparle? Pero debido a que la llamada a free() no significa que la memoria se devolverá inmediatamente al sistema operativo .


Existe la fragmentación de la memoria. En casos extremos, hay segmentos de almacenamiento dinámico en los que solo se usan unos pocos bytes, mientras que todo lo demás se liberó (free()) .


Tenga en cuenta que la fragmentación de la memoria es un tema increíblemente complejo, e incluso pequeños cambios en el programa pueden afectarlo significativamente. En la mayoría de los casos, los programas no causan una fragmentación significativa de la memoria, pero debe tener en cuenta que si se produce fragmentación en alguna área del montón, las páginas gigantes solo pueden agravar la situación.


Aplicación personalizada de hugepages


Después de leer el artículo, ha determinado qué partes de su programa pueden beneficiarse del uso de páginas grandes y cuáles no. Entonces, ¿deberían incluirse las grandes páginas?


Afortunadamente, puede usar madvise() para habilitar la paginación enorme solo para áreas de memoria donde será útil.


Para comenzar, verifique que las grandes páginas funcionen en modo madvise (), siguiendo las instrucciones al comienzo del artículo.


Luego, use madvise() para decirle al kernel exactamente dónde usar las páginas grandes.


 #include <sys/mman.h> //    ,    size_t size = 256*1024*1024; char* mymemory = malloc(size); //   hugepages… madvise(mymemory, size, MADV_HUGEPAGE); // …    madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL) 

Tenga en cuenta que este método es solo una recomendación al núcleo para la gestión de la memoria. Esto no significa que el kernel utilizará automáticamente páginas enormes para la memoria dada.


Consulte la página de manual de madvise para obtener más información sobre la gestión de memoria y madvise() , una curva de aprendizaje increíblemente empinada para este tema. Por lo tanto, si tiene la intención de entenderlo bien, prepárese para leerlo y probarlo durante varias semanas antes de contar con al menos algún resultado positivo.


Que leer





Tiene una pregunta Escribe en los comentarios!

Source: https://habr.com/ru/post/460403/


All Articles