GNU/Linux >> Tutoriales Linux >  >> Linux

El uso de páginas de 1 GB degrada el rendimiento

Intel tuvo la amabilidad de responder a este problema. Vea su respuesta a continuación.

Este problema se debe a cómo se comprometen realmente las páginas físicas. En caso de páginas de 1GB, la memoria es contigua. Entonces, tan pronto como escriba en cualquier byte dentro de la página de 1 GB, se asigna la página completa de 1 GB. Sin embargo, con las páginas de 4 KB, las páginas físicas se asignan cuando toca por primera vez en cada una de las páginas de 4 KB.

for (uint64_t i = 0; i < size / MESSINESS_LEVEL / sizeof(*ptr); i++) {
   for (uint64_t j = 0; j < MESSINESS_LEVEL; j++) {
       index = i + j * size / MESSINESS_LEVEL / sizeof(*ptr);
           ptr[index] = index * 5;
   }
}

En el bucle más interno, el índice cambia a un ritmo de 512 KB. Entonces, las referencias consecutivas se asignan a compensaciones de 512 KB. Por lo general, los cachés tienen 2048 conjuntos (que son 2 ^ 11). Entonces, los bits 6:16 seleccionan los conjuntos. Pero si avanza con compensaciones de 512 KB, los bits 6:16 serían los mismos y terminarían seleccionando el mismo conjunto y perdiendo la localidad espacial.

Recomendamos inicializar todo el búfer de 1 GB secuencialmente (en la prueba de página pequeña) como se muestra a continuación antes de iniciar el reloj para cronometrarlo

for (uint64_t i = 0; i < size / sizeof(*ptr); i++)
    ptr[i] = i * 5;

Básicamente, el problema es con los conflictos de conjuntos que resultan en fallas de caché en el caso de páginas grandes en comparación con páginas pequeñas debido a desplazamientos constantes muy grandes. Cuando usa compensaciones constantes, la prueba realmente no es aleatoria .


No es una respuesta, sino proporcionar más detalles sobre este tema desconcertante.

Los contadores de rendimiento muestran aproximadamente una cantidad similar de instrucciones, pero aproximadamente el doble de la cantidad de ciclos utilizados cuando se usan páginas grandes:

  • 4KiB páginas IPC 0.29,
  • 1GiB páginas IPC 0.10.

Estos números de IPC dicen que el código tiene un cuello de botella en el acceso a la memoria (el IPC vinculado a la CPU en Skylake es 3 y superior). Las páginas enormes hacen más difícil el cuello de botella.

Modifiqué su punto de referencia para usar MAP_POPULATE | MAP_LOCKED | MAP_FIXED con dirección fija 0x600000000000 para ambos casos para eliminar la variación de tiempo asociada con fallas de página y asignación aleatoria de direcciones. En mi sistema Skylake, 2 MiB y 1 GiB son más del doble de lentos que las páginas de 4 kiB.

Compilado con g++-8.4.0 -std=gnu++14 -pthread -m{arch,tune}=skylake -O3 -DNDEBUG :

[[email protected]:~/src/test] $ sudo hugeadm --pool-pages-min 2MB:64 --pool-pages-max 2MB:64
[[email protected]:~/src/test] $ sudo hugeadm --pool-pages-min 1GB:1 --pool-pages-max 1GB:1
[[email protected]:~/src/test] $ for s in small huge; do sudo chrt -f 40 taskset -c 7 perf stat -dd ./release/gcc/test $s random; done
Duration: 2156150

 Performance counter stats for './release/gcc/test small random':

       2291.190394      task-clock (msec)         #    1.000 CPUs utilized          
                 1      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                53      page-faults               #    0.023 K/sec                  
    11,448,252,551      cycles                    #    4.997 GHz                      (30.83%)
     3,268,573,978      instructions              #    0.29  insn per cycle           (38.55%)
       430,248,155      branches                  #  187.784 M/sec                    (38.55%)
           758,917      branch-misses             #    0.18% of all branches          (38.55%)
       224,593,751      L1-dcache-loads           #   98.025 M/sec                    (38.55%)
       561,979,341      L1-dcache-load-misses     #  250.22% of all L1-dcache hits    (38.44%)
       271,067,656      LLC-loads                 #  118.309 M/sec                    (30.73%)
           668,118      LLC-load-misses           #    0.25% of all LL-cache hits     (30.73%)
   <not supported>      L1-icache-loads                                             
           220,251      L1-icache-load-misses                                         (30.73%)
       286,864,314      dTLB-loads                #  125.203 M/sec                    (30.73%)
             6,314      dTLB-load-misses          #    0.00% of all dTLB cache hits   (30.73%)
                29      iTLB-loads                #    0.013 K/sec                    (30.73%)
             6,366      iTLB-load-misses          # 21951.72% of all iTLB cache hits  (30.73%)

       2.291300162 seconds time elapsed

Duration: 4349681

 Performance counter stats for './release/gcc/test huge random':

       4385.282466      task-clock (msec)         #    1.000 CPUs utilized          
                 1      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                53      page-faults               #    0.012 K/sec                  
    21,911,541,450      cycles                    #    4.997 GHz                      (30.70%)
     2,175,972,910      instructions              #    0.10  insn per cycle           (38.45%)
       274,356,392      branches                  #   62.563 M/sec                    (38.54%)
           560,941      branch-misses             #    0.20% of all branches          (38.63%)
         7,966,853      L1-dcache-loads           #    1.817 M/sec                    (38.70%)
       292,131,592      L1-dcache-load-misses     # 3666.84% of all L1-dcache hits    (38.65%)
            27,531      LLC-loads                 #    0.006 M/sec                    (30.81%)
            12,413      LLC-load-misses           #   45.09% of all LL-cache hits     (30.72%)
   <not supported>      L1-icache-loads                                             
           353,438      L1-icache-load-misses                                         (30.65%)
         7,252,590      dTLB-loads                #    1.654 M/sec                    (30.65%)
               440      dTLB-load-misses          #    0.01% of all dTLB cache hits   (30.65%)
               274      iTLB-loads                #    0.062 K/sec                    (30.65%)
             9,577      iTLB-load-misses          # 3495.26% of all iTLB cache hits   (30.65%)

       4.385392278 seconds time elapsed

Se ejecutó en Ubuntu 18.04.5 LTS con Intel i9-9900KS (que no es NUMA), 4x8GiB 4GHz CL17 RAM en las 4 ranuras, con performance regulador para no escalar la frecuencia de la CPU, ventiladores de refrigeración líquida al máximo para no estrangulamiento térmico, prioridad FIFO 40 para no preferencia, en un núcleo de CPU específico para no migrar la CPU, varias ejecuciones. Los resultados son similares con clang++-8.0.0 compilador.

Parece que hay algo sospechoso en el hardware, como un búfer de almacenamiento por marco de página, por lo que las páginas de 4 KiB permiten ~2 veces más almacenamiento por unidad de tiempo.

Sería interesante ver los resultados de las CPU AMD Ryzen 3.

En AMD Ryzen 3 5950X, la versión de páginas grandes es solo un 10 % más lenta:

Duration: 1578723

 Performance counter stats for './release/gcc/test small random':

          1,726.89 msec task-clock                #    1.000 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
             1,947      page-faults               #    0.001 M/sec                  
     8,189,576,204      cycles                    #    4.742 GHz                      (33.02%)
         3,174,036      stalled-cycles-frontend   #    0.04% frontend cycles idle     (33.14%)
            95,950      stalled-cycles-backend    #    0.00% backend cycles idle      (33.25%)
     3,301,760,473      instructions              #    0.40  insn per cycle         
                                                  #    0.00  stalled cycles per insn  (33.37%)
       480,276,481      branches                  #  278.116 M/sec                    (33.49%)
           864,075      branch-misses             #    0.18% of all branches          (33.59%)
       709,483,403      L1-dcache-loads           #  410.844 M/sec                    (33.59%)
     1,608,181,551      L1-dcache-load-misses     #  226.67% of all L1-dcache accesses  (33.59%)
   <not supported>      LLC-loads                                                   
   <not supported>      LLC-load-misses                                             
        78,963,441      L1-icache-loads           #   45.726 M/sec                    (33.59%)
            46,639      L1-icache-load-misses     #    0.06% of all L1-icache accesses  (33.51%)
       301,463,437      dTLB-loads                #  174.570 M/sec                    (33.39%)
       301,698,272      dTLB-load-misses          #  100.08% of all dTLB cache accesses  (33.28%)
                54      iTLB-loads                #    0.031 K/sec                    (33.16%)
             2,774      iTLB-load-misses          # 5137.04% of all iTLB cache accesses  (33.05%)
       243,732,886      L1-dcache-prefetches      #  141.140 M/sec                    (33.01%)
   <not supported>      L1-dcache-prefetch-misses                                   

       1.727052901 seconds time elapsed

       1.579089000 seconds user
       0.147914000 seconds sys

Duration: 1628512

 Performance counter stats for './release/gcc/test huge random':

          1,680.06 msec task-clock                #    1.000 CPUs utilized          
                 1      context-switches          #    0.001 K/sec                  
                 1      cpu-migrations            #    0.001 K/sec                  
             1,947      page-faults               #    0.001 M/sec                  
     8,037,708,678      cycles                    #    4.784 GHz                      (33.34%)
         4,684,831      stalled-cycles-frontend   #    0.06% frontend cycles idle     (33.34%)
         2,445,415      stalled-cycles-backend    #    0.03% backend cycles idle      (33.34%)
     2,217,699,442      instructions              #    0.28  insn per cycle         
                                                  #    0.00  stalled cycles per insn  (33.34%)
       281,522,918      branches                  #  167.567 M/sec                    (33.34%)
           549,427      branch-misses             #    0.20% of all branches          (33.33%)
       312,930,677      L1-dcache-loads           #  186.261 M/sec                    (33.33%)
     1,614,505,314      L1-dcache-load-misses     #  515.93% of all L1-dcache accesses  (33.33%)
   <not supported>      LLC-loads                                                   
   <not supported>      LLC-load-misses                                             
           888,872      L1-icache-loads           #    0.529 M/sec                    (33.33%)
            13,140      L1-icache-load-misses     #    1.48% of all L1-icache accesses  (33.33%)
             9,168      dTLB-loads                #    0.005 M/sec                    (33.33%)
               870      dTLB-load-misses          #    9.49% of all dTLB cache accesses  (33.33%)
             1,173      iTLB-loads                #    0.698 K/sec                    (33.33%)
             1,914      iTLB-load-misses          #  163.17% of all iTLB cache accesses  (33.33%)
       253,307,275      L1-dcache-prefetches      #  150.772 M/sec                    (33.33%)
   <not supported>      L1-dcache-prefetch-misses                                   

       1.680230802 seconds time elapsed

       1.628170000 seconds user
       0.052005000 seconds sys

Linux
  1. Uso de nfsstat y nfsiostat para solucionar problemas de rendimiento de NFS en Linux

  2. ¿Inconveniente al usar un chroot en computación de alto rendimiento?

  3. ¿Cómo acelerar el rendimiento del sitio web utilizando la solución de almacenamiento en caché XCache?

  4. Uso del script Apache2Buddy para rendimiento y estabilidad

  5. Uso de Windows Performance Analyzer para solucionar problemas de rendimiento

Cómo monitorear el rendimiento de Linux usando la herramienta systat

Usando Runit en Devuan

Cómo monitorear el rendimiento de Apache usando mod_status en Ubuntu

Cómo monitorear el rendimiento de Ubuntu usando Netdata

Uso de vmstat para solucionar problemas de rendimiento en Linux

Mejora del rendimiento mediante el uso de un servidor de archivos estático adicional