Forzar directorio a estar siempre en caché

35

He estado probando diferentes métodos para mejorar el tiempo que lleva compilar todo mi proyecto de c ++. Actualmente lleva unos 5 minutos. Experimenté con distcc, ccache y otros. Recientemente, descubrí que si copio todo mi proyecto en una unidad RAM y luego compilo desde allí, reduce el tiempo de compilación al 30% de su original, solo 1.5 minutos.

Obviamente, trabajar desde la unidad de RAM no es práctico. Entonces, ¿alguien sabe de alguna manera en que puedo forzar al sistema operativo a mantener siempre un determinado directorio en caché ? Todavía quiero que el directorio se sincronice de nuevo en el disco de manera normal, pero siempre quiero una copia de los datos en la memoria también. es posible?

EDITAR: Como una posible solución, solo pensamos en lanzar un demonio que se ejecuta rsynccada 10 segundos más o menos para sincronizar la unidad de disco con una unidad de RAM. Luego ejecutamos la compilación desde la unidad RAM. El rsynces increíblemente rápido, pero ¿funcionaría realmente? Seguramente el sistema operativo podría hacerlo mejor ...

JaredC
fuente
La memoria caché no es la única diferencia entre tmpfs y ext3 / 4; tienen diario, por ejemplo, que se escribirá independientemente del almacenamiento en caché.
André Paramés
1
¿Podrías timetu compilación y compartir el resultado con nosotros? Disiparía alguna controversia creciente. make clean && /usr/bin/time -v make(no use el timecomando incorporado bash )
shellholic
1
@she ¿Por qué no el comando incorporado de bash?
tshepang
3
@Tshepang el timebash incorporado ( help time) tiene muchos menos detalles (sin opción detallada) que el tiempo GNU ( man time) con respecto a la E / S, cambios de contexto, ...
shellholic

Respuestas:

18

La forma obvia de mantener un montón de archivos en la memoria caché es acceder a ellos con frecuencia. Linux es bastante bueno para arbitrar entre el intercambio y el almacenamiento en caché, por lo que sospecho que la diferencia de velocidad que observa no se debe realmente a que el sistema operativo no mantenga las cosas en la memoria caché, sino a alguna otra diferencia entre su uso de tmpfs y sus otros intentos.

Intenta observar lo que está haciendo IO en cada caso. La herramienta básica para eso es iotop. Otras herramientas pueden ser útiles; vea el desglose de carga de E / S del disco de Linux, por ruta o proceso del sistema de archivos , ¿Qué programa en Linux puede medir las E / S a lo largo del tiempo? y otros subprocesos en Server Fault.

Aquí hay algunas hipótesis sobre lo que podría estar sucediendo. Si toma medidas, muéstreselas para que podamos confirmar o refutar estas hipótesis.

  • Si tiene activados los tiempos de acceso a los archivos , el sistema operativo puede perder bastante tiempo escribiendo estos tiempos de acceso. Los tiempos de acceso son inútiles para un árbol de compilación, así que asegúrese de que estén apagados con la noatimeopción de montaje. Su solución tmpfs + rsync nunca lee del disco duro, por lo que nunca tiene que dedicar más tiempo a escribir notas.
  • Si las escrituras se están sincronizando , ya sea porque el compilador llama sync()o porque el núcleo frecuentemente vacía sus memorias intermedias de salida, las escrituras tardarán más en un disco duro que en tmpfs.
Gilles 'SO- deja de ser malvado'
fuente
Yo también tengo este sentimiento. La compilación es intensiva en CPU, en lugar de IO.
phunehehe
Hmmm, me gustaría ver un comentario de @JaredC aquí confirmando o negando la hipótesis de Gilles. 1.5 vs. 5 minutos es una gran diferencia ...
Daniel Alder
8

Linux por defecto usa la RAM como caché de disco. Como demostración, intente ejecutar time find /some/dir/containing/a/lot/of/files > /dev/nulldos veces, la segunda vez es mucho más rápida ya que todos los inodos de disco se almacenan en caché. El punto aquí es cómo utilizar esta función del núcleo y detener su intento de reemplazarla.

El punto es cambiar el swappiness. Consideremos tres tipos principales de uso de memoria: programas activos, programas inactivos y caché de disco. Obviamente, la memoria utilizada por los programas activos no debe intercambiarse y la elección entre otros dos es bastante arbitraria. ¿Desea un cambio rápido de programa o acceso rápido a archivos? Un intercambio bajo prefiere mantener los programas en la memoria (incluso si no se usa durante mucho tiempo) y un intercambio alto prefiere mantener más caché de disco (intercambiando programas no utilizados). (la escala de intercambio es de 0 a 100 y el valor predeterminado es 60)

Mi solución a su problema es cambiar el intercambio a muy alto (90-95 por no decir 100) y cargar el caché:

echo 95 | sudo tee /proc/sys/vm/swappiness > /dev/null # once after reboot
find /your/source/directory -type f -exec cat {} \; > /dev/null

Como lo adivina, debe tener suficiente memoria libre para almacenar en caché todos sus archivos fuente y archivos de objetos, así como el compilador, incluidos los archivos de encabezados, las bibliotecas vinculadas, su IDE y otros programas utilizados.

concha
fuente
Esto es útil en general, pero lo que realmente quiero es que mi código fuente tenga poca capacidad de intercambio, pero todo lo demás tenga una capacidad de intercambio normal. Esencialmente, tengo muchas cosas en segundo plano, pero quiero limitarlas a 6 de 8 GB, manteniendo siempre los otros 2 GB para el código fuente. No quiero arriesgarme a que se cambie ... nunca ... porque eso es molesto.
JaredC
El intercambio es de todo el sistema. De hecho, si está haciendo otra cosa y sus archivos se descargan de la memoria, solo tiene que volver a cargarlos con la segunda línea. Si la memoria tiene que ser liberada para otra cosa, realmente no "quieres correr el riesgo" de que se haga desde el intercambio. Por cierto, tmpfsen el mismo caso también sería intercambiado.
Shellholic
2
Personalmente me enamoré de un intercambio elevado que es absolutamente horrible en las estaciones de trabajo. Aunque algunas funciones pueden ser aceleradas por el caché más grande (es decir, más archivos en caché), esto tiene un precio: usted paga por esto en términos de capacidad de respuesta al cambiar entre programas, que es lo que los usuarios notan primero cuando trabajan en un sistema. Cuando cambio de navegador a oficina a otro navegador por correo electrónico, no puedo soportar tener que esperar 1-2 segundos para que cada programa vuelva a conectarse. En todas mis máquinas Linux, generalmente establezco el intercambio en un valor bajo de 10.
fgysin reinstala a Monica el
6

Forzar caché no es la forma correcta de hacer esto. Es mejor mantener las fuentes en el disco duro y compilarlas en tmpfs. Muchos sistemas de compilación, como qmake y CMake, admiten compilaciones fuera de la fuente.

gelraen
fuente
6

El inosyncdemonio suena como si hiciera exactamente lo que quieres si vas a sincronizar a un disco ram. En lugar de rsyncing cada 10 segundos más o menos, utiliza la función de inotify de Linux para rsync cuando cambia un archivo. Lo encontré en el repositorio de Debian como el inosyncpaquete, o su fuente está disponible en http://bb.xnull.de/projects/inosync/ .

Jander
fuente
Eso suena bastante útil. Lo investigaré e informaré. ¡Gracias!
JaredC
5

Esto parece funcionar para mí si quiero mantener ciertos archivos o todos los archivos en un determinado directorio en caché.

vmtouch parece hacer exactamente lo mismo. Ejemplo 5 puede haber lo que necesita.

vmtouch -dl /whatever/directory/

Necesitaba ejecutarlo como root con sudo

Highstaker
fuente
1
No ve archivos nuevos / eliminados.
Vi.
3

Dada suficiente memoria, su compilación del disco RAM no hace E / S. Esto puede acelerar cualquier cosa que lea o escriba archivos. I / O es una de las operaciones más lentas. Incluso si tiene todo en caché antes de la compilación, todavía tiene las E / S para escribir, aunque deberían tener un impacto mínimo.

Puede acelerar un poco cargando previamente todos los archivos en la memoria caché, pero el tiempo necesario para eso debe incluirse en los tiempos de compilación totales. Esto puede no darle mucha ventaja.

Construir el objeto y los archivos intermedios en RAM en lugar de en disco. Hacer compilaciones incrementales puede obtener ganancias significativas en construcciones frecuentes. En la mayoría de los proyectos hago una compilación limpia diaria y compilaciones incrementales en el medio. Las compilaciones de integración son siempre compilaciones limpias, pero trato de limitarlas a menos de una por día.

Puede obtener algo de rendimiento utilizando una partición ext2 con atime desactivado. Su fuente debe estar en control de versiones en un sistema de archivos registrado como ext3 / 4.

BillThor
fuente
2

Como se indicó anteriormente, la forma obvia es leer toda la estructura del directorio y el contenido del archivo de lo que desea almacenar en caché.

Puede automatizar esto escribiendo un script para monitorear la salida de vmstat 1(use cualquier herramienta equivalente para su sistema operativo) y mantener una suma de la cantidad de bloques escritos y leídos. Una vez que la suma supera el umbral de su elección, lea todos los archivos que desea almacenar en caché, restablezca la suma y luego continúe monitoreando la salida de vmstat. Para leer archivos rápidamente: si su árbol contiene muchos archivos, evite find ... -exec cat, en su lugar, intente con find ... -print0 | xargs -0 catun programa personalizado que no ejecute cat para cada archivo.

La supervisión de la E / S del disco es preferible a utilizar un intervalo fijo porque indica que debe volver a leer sus datos con mayor o menor frecuencia según la carga de la E / S del disco.

He utilizado este método automatizado con éxito en sistemas donde necesitaba algunas lecturas de archivos de índice para ser siempre rápidas, evitando la E / S del disco duro. También he usado strace para hacer una lista de cada archivo al que accedo cuando inicio sesión para poder mantener todo caliente en caché para inicios de sesión rápidos.

Puede que esta no sea la mejor solución posible, pero me fue bien.

filebarn
fuente