Tabla de Contenidos

Hugepages

Los procesos no trabajan directamente con la memoria física, sino que lo hacen con la memoria virtual. Aplicaciones que realizan una gran cantidad de accesos a memoria pueden obtener mejoras de rendimiento usando páginas grandes gracias a la traducción reducida Lookaside Buffer (TLB). Hugetlbfs es una función de administración de memoria que se ofrece en el kernel de Linux, que es útil para aplicaciones que utilizan un gran espacio de direcciones virtuales.

Para ello se debe realizar una conversión, entre la memoria física y la virtual. Para dicha conversión cada proceso dispone de una tabla de conversión, y como lo que contiene son direcciones de pagina, se llama tabla de paginación. En aplicaciones con mucho consumo de memoria, donde además la información cambia constantemente (por ejemplo, una base de datos), el acceso a la tabla de paginación es constante.

Debido a esto existe la “Translation Lookaside Buffer”, una pequeña cache con parte de la tabla de paginación. El problema es que la TLB es de tamaño fijo, y como normalmente guardamos direcciones de páginas de 4 KBytes; el total de memoria al que nos da acceso la TLB no es muy grande. Con lo cual como consecuente tenemos esta situación :

¿Cuál es la solución?

Utilizar tamaños mayores de página o Hugepages (el caso más habitual 2 MBytes). Esto supone acceder a una mayor cantidad de memoria con las mismas entradas (PTE) en la tabla de paginación. Reduciendo así el consumo de CPU.

¿Cómo se si mi sistema operativo Linux tiene habilitada dicha funcionalidad en el kernel?

Ejecutar el siguiente comando:

$ grep -i huge /proc/meminfo 

La salida debe ser similar a:

HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

El núcleo compilado con hugepage debe mostrar el número de páginas gigantes configuradas en el sistema. De lo contrario, es necesario recompilar el kernel de Linux con la opción de CONFIG_HUGETLBFS habilitada.

Para mas información leer Manejo de memoria en Linux.

Los pasos a seguir son

  1. Definir el límite memlock para el usuario del servicio que estamos configurando, con un valor algo menor de la memoria disponible (/etc/sysctl.conf).
  2. Iniciar el servicio que consume la memoria.
  3. Calcular el número de hugepages que queremos utilizar en función de la memoria consumida por nuestro proceso (en el caso de Oracle hay un script en la Nota 401749.1)
  4. Definir el parámetro del kernel vm.nr_hugepages= en el archivo /etc/security/limits.conf
  5. Reiniciar el servidor.
  6. Revisar el valor: $ grep Huge /proc/meminfo

Detalles sobre su uso, especialmente con Oracle:

La característica de hugetlbfs permite a una aplicación a poder utilizar un tamaño de página mucho más grande de lo normal, de modo que una entrada de TLB solo puede asignar un mayor espacio de direcciones. Las entradas en HugeTLB pueden variar en tamaño. Por ejemplo, la arquitectura i386 soporta 4K y 4M (2M en modo PAE), tamaños de página, ia64 arquitectura soporta tamaños de varias páginas 4K, 8K,64K, 256K, 1M, 4M, 16M, 256M y ppc64 apoya 4K y 16M.

Para asignar hugepage, puede definir el número de páginas gigantes mediante la configuración de valor en /proc/sys/vm/nr_hugepages, escriba:

sysctl -w vm.nr_hugepages=40 (Puede hacerlo de manera mas manual, abriendo el archivo /etc/sysctl y agregando vm.nr_hugepages=40)

Hecho lo anterior actualizamos:

bash$ sysctl -p

Ahora a verificar si se configuraron las paginas:

bash# grep -i huge /proc/meminfo 

HugePages_Total:    40
HugePages_Free:     40
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

Donde:

Implementación

Memoria compartida

Semáforos

Un semáforo se puede pensar como un contador que se utiliza para acceder a los recursos compartidos del sistema.

Desde la linea de comandos se puede ver la memoria compartida y los semáforos usados

srvlxsid:~ # ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x52205704 32768      orasid     640        20487077888 375
0x00000000 65537      sidadm     777        1024       1
0x00004dbe 13074463   sidadm     777        574868     1
0x00002748 13140000   sidadm     740        534592     15
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0xc1f65328 98304      orasid     640        1004
0x00004e62 3932277    sidadm     740        1
0x00004e28 3965046    sidadm     740        1
0x00004e68 3997815    sidadm     740        1
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
ipcs -l
---- Límites memoria compartida ----
número máx. segmentos = 4096
tamaño máx. segmento (kbytes) = 9007199254740991
max total shared memory (kbytes) = 4611686018427386880
tamaño mín. segmento (bytes) = 1
------ Límites semáforo --------
número máximo de matrices = 8192
máx. semáforos por matriz = 1250
máx. semáforos sistema = 256000
máx. oper. por llamada semop = 100
valor máx. semáforo = 32767
------ Mensajes: límites -------
máx. colas sistema = 32768
tamaño máx. mensaje (bytes) = 65536
tamaño máx. predeterminado cola (bytes) = 65536
kernel.shmmax = 9223372036854775807
kernel.sem = 1250 256000 100 8192
kernel.shmall = 1152921504606846720
vm.max_map_count = 1000000
vm.nr_hugepages=12000

/etc/security/limits.conf

memlock : memoria compartida en kilobytes

*              soft     nofile    4096
*              hard     nofile    63536
*              soft     memlock   26214400
*              hard     memlock   26214400
@ejemplo - memlock unlimited

Tips

/etc/security/limits.conf Debe tener un valor asignado un poco menor a la memoria instalada, por ejemplo si tenemos 64GB of RAM, un valor apropiado puede ser :

soft memlock 60397977
hard memlock 60397977

Script que calcula automaticamente el valor de hugepages, usar solo como orientación

Oracle recomiendar calcular de esta forma :

ipcs -m

key shmid owner perms bytes
0x00004dc4
0x00004dbe
0x52205704
0x00000000
0x0382be84
0x00002749
0x0000271a
0x00002711
0x00002712
0x00002713
0x00002744
0x0000272f
0x00002743
0x0000274e
0x00002759
0x0000274f
0x0000271e
0x00002719
0x00002718
0x00002722
0x00002738
0x00002717
0x00002714
0x00002739
0x00002723
0x00002731
0x00002746
0x00002751
0x00002750
0x00002761
0x00002716
0x0000272e
0x00002732
0x0000274a
0x00002748
229376
262145
88670210
88702979
360452
88735749
92143622
92176391
92209160
92241929
92274698
92307467
92340236
92405773
95813646
99221519
99254288
99287057
99319826
99352595
99385364
99418133
99483670
99516439
99549208
99581977
99614746
99647515
99680284
99713053
101646366
101679135
101711904
101744673
101777442
sapadm
root
orasid
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
sidadm
760
777
640
740
640
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
740
40141728
793440
47246737408
1024
4096
1639280
200000000
588
62456056
200592000
179368
6387876
23738964
86484792
60211232
86040
40000000
2147483648
2147483648
6423584
662000000
31072
645640
45454312
1799999904
92159912
287465496
33554456
4194456
19480
4096000000
126790
83394560
2076
535000

De la cantidad de bytes formamos una matriz que es la de segmentos de memoria compartida en bytes y realizamos el siguiente cálculo :

| MATRIZ DE SEGMENTOS DE MEMORIA COMPARTIDA | / (TAMAÑO DE PAGINA*1024)+1

http://docs.oracle.com/cd/E37670_01/E37355/html/ol_config_hugepages.html

Metalink Note 401749.1, Shell Script to Calculate Values Recommended HugePages / HugeTLB Configuration

#!/bin/bash
#
# hugepages_settings.sh
#
# Linux bash script to compute values for the
# recommended HugePages/HugeTLB configuration
#
# Note: This script does calculation for all shared memory
# segments available when the script is run, no matter it
# is an Oracle RDBMS shared memory segment or not.
# Check for the kernel version
KERN=`uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'`
# Find out the HugePage size
HPG_SZ=`grep Hugepagesize /proc/meminfo | awk {'print $2'}`
# Start from 1 pages to be on the safe side and guarantee 1 free HugePage
NUM_PG=1
# Cumulative number of pages required to handle the running shared memory segments
for SEG_BYTES in `ipcs -m | awk {'print $5'} | grep "[0-9][0-9]*"`
do
   MIN_PG=`echo "$SEG_BYTES/($HPG_SZ*1024)" | bc -q`
   if [ $MIN_PG -gt 0 ]; then
      NUM_PG=`echo "$NUM_PG+$MIN_PG+1" | bc -q`
   fi
done
# Finish with results
case $KERN in
   '2.4') HUGETLB_POOL=`echo "$NUM_PG*$HPG_SZ/1024" | bc -q`;
          echo "Recommended setting: vm.hugetlb_pool = $HUGETLB_POOL" ;;
   '2.6') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
    *) echo "Unrecognized kernel version $KERN. Exiting." ;;
esac
# End

Con Oracle en el Kernel 3.0 es recomendable deshabilitar las páginas transparentes.

Podemos hacerlos on-the-fly

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

O al inicio del sistema desde la cmdline de booteo :

transparent_hugepage=never

Referencias