¿Cómo puede ser tan lento el intercambio?

77

De alguna manera, cambié 14 GB de memoria. Después de haber matado al culpable, tengo toneladas de memoria libre nuevamente, así que pensé que podría traer los datos importantes nuevamente. Entonces, con 5 GB de 32 GB utilizados y 14 GB de espacio de intercambio utilizado, corrí swapoff -a... y 4 horas más tarde, aproximadamente la mitad del trabajo estaba terminado.

Esto significa menos de 1 MB / s, mientras que puedo copiar fácilmente 200 MB / s. Mi intercambio está encriptado, pero también lo están todas las particiones normales y con aes-ni no conduce a una carga notable de CPU (y llenar el espacio de intercambio tomó solo unos minutos). Veo que no hay una razón especial para optimizar swapoff, sin embargo, me pregunto cómo podría ser tan lento.


Solo agrego algunos datos más: mi memoria principal es de 32 GB y tengo espacio de intercambio de 32 GB en cada uno de los 4 discos duros (seguramente una exageración, pero ¿a quién le importa?). Todo el espacio de intercambio se puede (descifrar y) leer en menos de 5 minutos:

time -p sudo sh -c 'for i in /dev/mapper/cryptswap?; do md5sum $i & done; wait'
014a2b7ef300e11094134785e1d882af  /dev/mapper/cryptswap1
a6d8ef09203c1d8d459109ff93b6627c  /dev/mapper/cryptswap4
05aff81f8d276ddf07cf26619726a405  /dev/mapper/cryptswap3
e7f606449327b9a016e88d46049c0c9a  /dev/mapper/cryptswap2
real 264.27

Leer una parte de una partición no puede ser más lento que leerlo todo. Sin embargo, leer alrededor de 1/10 toma alrededor de 100 veces más.

Observé que durante swapoffla CPU la mayoría estaba inactiva (quizás el 10% de un núcleo) y también los discos ("medidos" por los LED). También vi que los espacios de intercambio se desactivaron uno tras otro.

maaartinus
fuente
1
Me pregunto, ¿ocurre el mismo fenómeno cuando el sistema carga las páginas intercambiadas nuevamente en la RAM? Por ejemplo, si un sistema se suspendió en el disco y luego se inicia, todo se cambió y se está volviendo a cargar en la RAM. Parece ser muy lento para mí también.
Petr Pudlák
¿Todos los dispositivos de intercambio se activan con la misma prioridad?
Nils
@Petr Pudlák: Suspender al disco es un poco diferente, simplemente escribe el contenido de RAM en un espacio libre en el área de intercambio, y esto (y cancelar la suspensión) es probablemente mucho más rápido. No puedo intentarlo ya que no funciona con intercambio cifrado.
maaartinus
@Nils: Sí, la prioridad es la misma y también lo son el disco y su partición.
maaartinus
Eso lo hace más extraño. En este caso, el intercambio se divide en todos los discos; esto debería ser muy rápido. ¿ También iostat -d 5mostró bajo IO en los discos durante swapoff?
Nils

Respuestas:

53

Primero, echemos un vistazo a lo que puede esperar de su disco duro. Su disco duro puede hacer 200 MB / s secuencialmente . Cuando factoriza tiempos de búsqueda, puede ser mucho más lento. Para elegir un ejemplo arbitrario, eche un vistazo a las especificaciones de uno de los discos modernos de 3 TB de Seagate, el ST3000DM001 :

  • Velocidad de datos máxima sostenida: 210 MB / s

  • Buscar lectura promedio: <8,5 ms

  • Bytes por sector: 4,096

Si nunca necesita buscar, y si su intercambio está cerca del borde del disco, puede esperar ver hasta la velocidad máxima = 210 MB / s

Pero si sus datos de intercambio están completamente fragmentados, en el peor de los casos, necesitaría buscar por cada sector que lea. Eso significa que solo puede leer 4 KB cada 8,5 ms, o 4 KB / 0.0085 = 470 KB / s

Así que de inmediato, no es inconcebible que de hecho estés corriendo contra la velocidad del disco duro.


Dicho esto, parece una tontería que swapoffse ejecute tan lentamente y tenga que leer las páginas fuera de orden, especialmente si se escribieron rápidamente (lo que implica un orden). Pero esa puede ser la forma en que funciona el núcleo. El informe de error de Ubuntu # 486666 discute el mismo problema:

The swap is being removed at speed of 0.5 MB/s, while the
hard drive speed is 60 MB/s;
No other programs are using harddrive a lot, system is not under
high load etc.

Ubuntu 9.10 on quad core.

Swap partition is encrypted.
Top (atop) shows near 100% hard drive usage
  DSK | sdc | busy 88% | read 56 | write 0 | avio 9 ms |
but the device transfer is low (kdesysguard)
  0.4 MiB/s on /dev/sdc reads, and 0 on writes

Una de las respuestas fue:

It takes a long time to sort out because it has to rearrange and flush the
memory, as well as go through multiple decrypt cycles, etc. This is quite
normal

El informe de error se cerró sin resolver.

El libro de Mel Gorman " Comprender el administrador de memoria virtual de Linux " está un poco desactualizado, pero está de acuerdo en que esta es una operación lenta:

La función responsable de desactivar un área es, como era de esperar, llamada sys_swapoff(). Esta función se ocupa principalmente de actualizar el swap_info_struct. La tarea principal de paginación en cada página paginada es la responsabilidad de la try_to_unuse()cual es extremadamente costosa.

Hay un poco más de discusión desde 2007 sobre la lista de correo del kernel de Linux con el tema " acelerar el intercambio ", aunque las velocidades que están discutiendo allí son un poco más altas de lo que está viendo.


Es una pregunta interesante que probablemente generalmente se ignora, ya swapoffque rara vez se usa. Creo que si realmente quería seguir hacia abajo, el primer paso sería tratar de ver sus patrones de uso de disco con más cuidado (tal vez con atop, iostato incluso las herramientas más potentes como perfo systemtap). Lo que debe buscar puede ser una búsqueda excesiva, pequeñas operaciones de E / S, reescritura constante y movimiento de datos, etc.

Jim Paris
fuente
55
Excelente explicación Cabe señalar que es posible eludir la mayor parte de la fragmentación y liberar la mayoría del intercambio rápidamente volcando al núcleo las grandes secciones de memoria intercambiada: unix.stackexchange.com/questions/254202/…
Brandon DuPree
No es solo fragmentación / tiempo de búsqueda. Mi intercambio está en SSD y las lecturas aleatorias son muy rápidas, sin embargo, el comando de intercambio es mucho más lento de lo que debería y mi carga de SSD se encuentra en alrededor del 1% de utilidad. Sospecho que hay una caminata de lista involucrada en algún lugar del kernel o en el intercambio (que usa ~ 90-100% de CPU). Por supuesto, si todo el trabajo se realiza de forma secuencial y la búsqueda del disco también es lenta, puede sumar mucho.
Thomas Guyot-Sionnest
33

He estado experimentando el mismo problema con mi computadora portátil que tiene un SSD, por lo que buscar tiempos no debería ser un problema.

Encontré una explicación alternativa . Aquí hay un extracto

De la forma en que funciona ahora, swapoff examina cada página de memoria intercambiada en la partición de intercambio e intenta encontrar todos los programas que la usan. Si no puede encontrarlos de inmediato, mirará las tablas de páginas de cada programa que se esté ejecutando para encontrarlos. En el peor de los casos, verificará todas las tablas de páginas para cada página intercambiada en la partición. Así es, las mismas tablas de páginas se revisan una y otra vez.

Por lo tanto, es un problema de kernel en lugar de cualquier otra cosa.

Nick Craig-Wood
fuente
No, no es un problema de kernel en mi humilde opinión. Es cómo swapoffse implementa. Cuando se intercambian las salidas del proceso, no toma mucho tiempo.
Marki555
15
Es un problema con la implementación del intercambio que está en el kernel, ¡por lo tanto, es un problema del kernel! Puedes ver si strace swapoffprácticamente todo lo que hace es llamar a la llamada al swapoffsistema.
Nick Craig-Wood
1
Tengo un servidor con 48 GB de RAM (32 núcleos), tenía 6 GB de intercambio libre de errores y se usaba 0,7 GB. swappiness = 10, traté de ponerlo en 0 y también probé el intercambio para ver qué sucede. El intercambio lleva años, probablemente 30 minutos, liberando el intercambio extremadamente lento. Tengo SSD casi sin carga y la CPU es similar, espero el proceso de intercambio que toma una CPU al 100%.
sorin
1
Es un problema de cómo se implementa el intercambio (en el núcleo). Hubo discusiones sobre un enfoque mucho mejor hace unos años en kernel-dev, pero dicen que es un caso de esquina y no quieren que el esfuerzo lo cambie.
Marki555
77
En el servidor con 1 TB de RAM (sí, TB) y 2 GB de intercambio (requisito tonto de SAP), el intercambio tardó 12 horas en liberar el 5% de esos 2 GB (con 1 núcleo de CPU al 100%).
Marki555
22

Sí, el swapoffmecanismo es terriblemente ineficiente. La solución es fácil: iterar sobre procesos, en lugar de iterar sobre las páginas intercambiadas. Utilice este script de Python (no estoy afiliado):

git clone https://github.com/wiedemannc/deswappify-auto

Tenga en cuenta que el modo de operación daemon es solo para computadoras de escritorio / portátiles que a menudo se hibernan. No lo ejecutaría como un demonio en un sistema de servidor; solo ejecútelo en primer plano, espere hasta que informe que se encargó de algunos procesos, luego deténgalo e intente:

swapoff /dev/x

Dado que la mayoría de las páginas ahora están presentes tanto en intercambio como en memoria, swapofftiene muy poco que hacer y ahora debería ser increíblemente rápido (vi cientos de MB / s).

Sección de historia por delante

El script python mencionado anteriormente se basa en el resto de esta respuesta, que a su vez fue mi mejora de esta respuesta anterior creada por jlong . Como el guión es mucho más seguro, recomiendo probar solo el resto de mi respuesta como la última línea de defensa :

perl -we 'for(`ps -e -o pid,args`) { if(m/^ *(\d+) *(.{0,40})/) { $pid=$1; $desc=$2; if(open F, "/proc/$pid/smaps") { while(<F>) { if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ $start_adr=$1; $end_adr=$2; }  elsif(m/^Swap:\s*(\d\d+) *kB/s){ print "SSIZE=$1_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" }}}}}' | sort -Vr | head

Esto va quizás a 2 segundos y en realidad no hacer nada, sólo una lista de los 10 segmentos de memoria superior (en realidad se imprime más de una sola línea; sí, yo no amo de una sola línea, simplemente examinar los comandos, aceptar el riesgo, copiar y pegar en su caparazón; estos en realidad leerán de intercambio).

...Paste the generated one-liners...
swapoff /your/swap    # much faster now

El one-liner principal es seguro (para mí), excepto que lee mucho / proc.

Los subcomandos preparados para su examen manual no son seguros . Cada comando colgará un proceso mientras dure el intercambio de un segmento de memoria. Por lo tanto, no es seguro con procesos que no toleran ninguna pausa. Las velocidades de transferencia que vi fueron del orden de 1 gigabyte por minuto. (El script Python mencionado anteriormente eliminó esa deficiencia).

Otro peligro es poner demasiada presión de memoria en el sistema, así que verifique con lo habitual free -m

¿Qué hace?

for(`ps -e -o pid,args`) {

  if(m/^ *(\d+) *(.{0,40})/) { 
    $pid=$1; 
    $desc=$2; 

    if(open F, "/proc/$pid/smaps") { 

      while(<F>) { 

        if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ 
          $start_adr=$1; 
          $end_adr=$2; 
        } elsif( m/^Swap:\s*(\d\d+) *kB/s ){
          print "SSIZE=$1_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" 
        }
      }
    }
  }
}

El resultado de este script perl es una serie de gdbcomandos dump memory (range)que recuperan páginas intercambiadas a la memoria.

La salida comienza con el tamaño, por lo que es bastante fácil pasarlo | sort -Vr | headpara obtener los 10 segmentos más grandes por tamaño (SSIZE). Los -Vsoportes para la clasificación version-number-adecuado, pero funciona para mi propósito. No pude entender cómo hacer que la ordenación numérica funcione.

kubanczyk
fuente
sort -t = -k 2n
Usaría el
99
Parece que no hay necesidad de usar gdb para mirar la memoria del proceso (al menos en los núcleos recientes). Uno puede simplemente abrir /proc/$pid/mem, buscar y leer directamente. Aquí está PoC basado en gran medida en su fragmento: gist.github.com/WGH-/91260f6d65db88be2c847053c49be5ae Este proceso no se detiene, AFAIK no debería haber ningún peligro causado por esto.
WGH
10

Durante el intercambio, si se detecta una ranura de intercambio en uso, el núcleo primero se intercambia en la página. La función unuse_process () intenta encontrar todas las entradas de la tabla de páginas que corresponden a la página recién intercambiada y realiza la actualización necesaria de las tablas de páginas. La búsqueda es exhaustiva y requiere mucho tiempo: visita cada descriptor de memoria (de todo el sistema) y examina las entradas de la tabla de páginas una por una.

Consulte la página 724 de "Comprensión de la tercera versión del kernel de Linux".

Leslie
fuente