c - nehalem - sandy bridge e
¿Cómo usar las páginas Intel Westmere de 1GB en Linux? (1)
TL; DR
Usted (específicamente, su procesador) no puede beneficiarse de las páginas de 1 GB en este escenario, pero su código es correcto sin modificaciones en los sistemas que pueden hacerlo.
Versión larga
Seguí estos pasos para intentar reproducir tu problema.
My System: Intel Core i7-4700MQ, 32GB RAM 1600MHz, Chipset H87
-
svn co https://github.com/ManuelSelva/c4fun.git
-
cd c4fun.git/trunk
-
make
Se descubrieron unas cuantas dependencias. Los instalé. La compilación falló, peromem_load
sí construyó ymem_load
, por lo que no siguió con el resto. Reinició el sistema, agregando lo siguiente en GRUB a los argumentos de arranque:
hugepagesz=1G hugepages=10 default_hugepagesz=1G
que reserva 10 páginas de 1GB.
-
cd c4fun.git/trunk/mem_load
memload
varias pruebas usandomemload
, en modo de patrón de acceso aleatorio y fijándolo al núcleo 3, que es algo que no es 0 (el procesador de arranque)../mem_load -a rand -c 3 -m 1073741824 -i 1048576
Esto dio lugar a aproximadamente cero errores TLB.
./mem_load -a rand -c 3 -m 10737418240 -i 1048576
Esto resultó en aproximadamente 60% de fallas de TLB. En una corazonada que hice
./mem_load -a rand -c 3 -m 4294967296 -i 1048576
Esto dio lugar a aproximadamente cero errores TLB. En una corazonada que hice
./mem_load -a rand -c 3 -m 5368709120 -i 1048576
Esto resultó en aproximadamente 20% de fallas de TLB.
En este punto descargué la utilidad cpuid
. Me dio esto para cpuid -1 | grep -i tlb
cpuid -1 | grep -i tlb
cache and TLB information (2):
0x63: data TLB: 1G pages, 4-way, 4 entries
0x03: data TLB: 4K pages, 4-way, 64 entries
0x76: instruction TLB: 2M/4M pages, fully, 8 entries
0xb5: instruction TLB: 4K, 8-way, 64 entries
0xc1: L2 TLB: 4K/2M pages, 8-way, 1024 entries
L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax):
L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx):
L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax):
L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx):
Como puede ver, mi TLB tiene 4 entradas para páginas de 1GB. Esto explica bien mis resultados: para arenas de 1GB y 4GB, las 4 ranuras de la TLB son suficientes para satisfacer todos los accesos. Para arenas de 5 GB y modo de patrón de acceso aleatorio, solo 4 de las 5 páginas pueden asignarse a través del TLB, por lo que perseguir un puntero en el restante hará que se pierda. La probabilidad de perseguir un puntero en la página no asignada es 1/5, por lo que esperamos una tasa de error de 1/5 = 20% y lo conseguimos. Para 10 GB, se asignan 4/10 páginas y 6/10 no, por lo que la tasa de fallos será 6/10 = 60%, y lo conseguimos.
Así que su código funciona sin modificaciones en mi sistema al menos. Tu código no parece ser problemático entonces.
Luego realicé algunas investigaciones sobre CPU-World, y aunque no todas las CPU están listadas con datos de geometría TLB, algunas sí lo están. El único que vi que coincidía exactamente con su impresión de cpuid (podría haber más) es el Xeon Westmere-EP X5650 ; CPU-World no dice explícitamente que el TLB0 de datos tiene entradas para páginas de 1GB, pero sí dice que el procesador tiene "soporte de página grande de 1 GB".
Luego hice más investigación y finalmente lo clavé. Un autor de RealWorldTech hace un comentario directo en la discusión sobre el subsistema de memoria de Sandy Bridge. Lee como sigue :
Después de la generación de direcciones, uops accederá al DTLB para traducir de una dirección virtual a una física, en paralelo con el inicio del acceso al caché. La DTLB se mantuvo igual, pero el soporte para páginas de 1GB ha mejorado. Anteriormente, Westmere agregó soporte para páginas de 1GB, pero fragmentó páginas de 1GB en muchas páginas de 2MB ya que el TLB no tenía ninguna entrada de página de 1GB. Sandy Bridge agrega 4 entradas dedicadas para páginas de 1GB en el DTLB.
(Énfasis añadido)
Conclusión
Cualquiera que sea el concepto nebuloso que "CPU soporta páginas de 1GB" representa, Intel piensa que no implica que "TLB admita entradas de páginas de 1GB" . Me temo que no podrá usar páginas de 1 GB en un procesador Intel Westmere para reducir la cantidad de fallas de TLB.
Eso, o Intel nos está engañando al distinguir las páginas grandes (en la TLB) de las páginas grandes .
Edit : actualicé mi pregunta con los detalles de mi punto de referencia
Con fines de evaluación comparativa, estoy intentando configurar páginas de 1 GB en un sistema Linux 3.13 que se ejecuta sobre dos procesadores Intel Xeon 56xx ("Westmere"). Para eso modifiqué mis parámetros de arranque para agregar soporte para páginas de 1GB (10 páginas). Estos parámetros de arranque solo contienen páginas de 1GB y no 2MB. La ejecución de hugeadm --pool-list
lleva a:
Size Minimum Current Maximum Default
1073741824 10 10 10 *
Mis parámetros de arranque del kernel son tomados en cuenta. En mi punto de referencia, estoy asignando 1GiB de memoria que deseo ser respaldado por una página enorme de 1GiB usando:
#define PROTECTION (PROT_READ | PROT_WRITE)
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
uint64_t size = 1UL*1024*1024*1024;
memory = mmap(0, size, PROTECTION, FLAGS, 0, 0);
if (memory == MAP_FAILED) {
perror("mmap");
exit(1);
}
sleep(200)
Mirando el /proc/meminfo
mientras el banco está durmiendo (llamada de sleep
arriba), podemos ver que se ha asignado una página enorme:
AnonHugePages: 4096 kB
HugePages_Total: 10
HugePages_Free: 9
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 1048576 kB
Nota: Deshabilité THP (a través del sistema de archivos /sys
) antes de ejecutar el banco, por lo que supongo que el campo AnonHugePages
informado por /proc/meminfo
representa las grandes páginas asignadas por THP antes de detenerlo.
En este punto, podemos pensar que todo está bien, pero desafortunadamente mi banco me lleva a pensar que se usan muchas páginas de 2MiB y no una página de 1GiB. Aquí está la explicación:
Este banco accede al azar a la memoria asignada a través de la persecución del puntero: un primer paso llena la memoria para habilitar la persecución del puntero (cada celda apunta a otra celda) y en un segundo paso la banca navega a través de la memoria usando
pointer = *pointer;
Al usar la perf_event_open
sistema perf_event_open
, estoy contando los datos que la lectura de TLB pierde solo para el segundo paso del banco. Cuando el tamaño de la memoria asignada es de 64MiB, cuento un número muy pequeño, el 0,01% de mis 6400000 accesos de memoria, de datos que la TLB no lee. Todos los accesos se guardan en la TLB. En otras palabras, se pueden guardar 64 MB de memoria en la TLB. Tan pronto como el tamaño de la memoria asignada es mayor a 64 MiB, veo datos que la lectura de tlb pierde. Para un tamaño de memoria igual a 128 MiB, tengo el 50% de mis 6400000 accesos de memoria que faltaron en la TLB. 64MiB parece ser el tamaño que puede caber en las entradas TLB y 64MiB = 32 (como se informa a continuación) * páginas de 2MiB. Concluyo que no estoy usando páginas de 1GiB sino de 2MiB.
¿Puedes ver alguna explicación para ese comportamiento?
Además, la herramienta cpuid
, informa lo siguiente sobre el tlb en mi sistema:
cache and TLB information (2):
0x5a: data TLB: 2M/4M pages, 4-way, 32 entries
0x03: data TLB: 4K pages, 4-way, 64 entries
0x55: instruction TLB: 2M/4M pages, fully, 7 entries
0xb0: instruction TLB: 4K, 4-way, 128 entries
0xca: L2 TLB: 4K, 4-way, 512 entries
L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax):
L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx):
L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax):
L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx):
Como puedes ver, no hay información sobre las páginas de 1GiB. ¿Cuántas de estas páginas se pueden almacenar en caché en la TLB?