2012-07-06 17 views
5

Quiero saber qué parte de un archivo enorme se almacena en caché en la memoria. Estoy usando un código de fincore para eso, que funciona de esta manera: el archivo está mmaped, luego fincore recorre el espacio de direcciones y páginas de verificación con mincore, pero es muy largo (varios minutos) debido al tamaño del archivo (varios TB)Linux: identificación de páginas en la memoria

¿Hay alguna forma de recorrer las páginas RAM usadas? Sería mucho más rápido, pero eso significa que debería obtener la lista de páginas usadas de algún lugar ... Sin embargo, no puedo encontrar una llamada al sistema conveniente que permita eso.

Aquí viene el código:

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
/* } */ 

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/mman.h> 
#include <sys/sysinfo.h> 


void 
fincore(char *filename) { 
    int fd; 
    struct stat st; 

    struct sysinfo info; 
    if (sysinfo(& info)) { 
    perror("sysinfo"); 
    return; 
    } 

    void *pa = (char *)0; 
    char *vec = (char *)0; 
    size_t pageSize = getpagesize(); 
    register size_t pageIndex; 

    fd = open(filename, 0); 
    if (0 > fd) { 
     perror("open"); 
     return; 
    } 

    if (0 != fstat(fd, &st)) { 
     perror("fstat"); 
     close(fd); 
     return; 
    } 

    pa = mmap((void *)0, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); 
    if (MAP_FAILED == pa) { 
     perror("mmap"); 
     close(fd); 
     return; 
    } 

    /* vec = calloc(1, 1+st.st_size/pageSize); */ 
    /* 2.2 sec for 8 TB */ 
    vec = calloc(1, (st.st_size+pageSize-1)/pageSize); 
    if ((void *)0 == vec) { 
     perror("calloc"); 
     close(fd); 
     return; 
    } 

    /* 48 sec for 8 TB */ 
    if (0 != mincore(pa, st.st_size, vec)) { 
     fprintf(stderr, "mincore(%p, %lu, %p): %s\n", 
       pa, (unsigned long)st.st_size, vec, strerror(errno)); 
     free(vec); 
     close(fd); 
     return; 
    } 

    /* handle the results */ 
    /* 2m45s for 8 TB */ 
    for (pageIndex = 0; pageIndex <= st.st_size/pageSize; pageIndex++) { 
     if (vec[pageIndex]&1) { 
     printf("%zd\n", pageIndex); 
     } 
    } 

    free(vec); 
    vec = (char *)0; 

    munmap(pa, st.st_size); 
    close(fd); 

    return; 
} 

int main(int argc, char *argv[]) { 
    fincore(argv[1]); 

    return 0; 
} 
+2

La asignación de un archivo de 8 TB requiere 2 mil millones de páginas de 4k. El tiempo de ejecución de 48 segundos de 'mincore' significa que se examinan 44.7 Mpages/seg. ¿Cuánto más rápido crees que esto podría pasar? Imprimir millones o miles de millones de líneas con 'printf()' tampoco es la cosa más rápida del mundo. –

+0

No espero obtener mmap/mincore más rápido que eso; lo que me gustaría es reducir la longitud del bucle, posiblemente escaneando menos páginas ... – wazoox

+0

'printf' suele ser un funcionamiento muy lento.Reemplácelo con algo como 'activePages ++' y vea cuánto tiempo lleva procesar el ciclo. Tenga en cuenta que 'vec' sigue siendo 2 GiB e incluso llamar' 'mincore' podría cambiar el contenido de la memoria caché a medida que se toca la memoria física dentro del espacio de direcciones virtuales asignado a' vec'. –

Respuesta

0

cach por quién?

Considere después de un arranque que el archivo se encuentra en el disco. Ninguna parte de ella está en la memoria.

Ahora el archivo se abre y se realizan lecturas aleatorias.

El sistema de archivos (por ejemplo, el núcleo) se almacenará en caché.

La biblioteca estándar C se almacenará en caché.

El kernel almacenará en caché la memoria en modo kernel, la biblioteca estándar C en la memoria del modo de usuario.

Si puede emitir una consulta, también podría ser eso inmediatamente después de la consulta, antes de que regrese a usted, los datos en caché en cuestión se eliminan de la memoria caché.

+0

Es un destino iscsi, por lo que el kernel lo almacena en caché en la memoria caché de disco. Me gustaría controlar el uso y la evolución de la memoria caché con el tiempo. – wazoox

1

La cantidad de información necesaria para representar una lista es, para el caso pesimista, cuando todas o casi todas las páginas están en RAM, mucho más que el mapa de bits: al menos 64 contra 1 bits por entrada. Si existiera dicha API, al consultarla sobre sus 2 mil millones de páginas, debería estar preparado para obtener 16 GB de datos en la respuesta. Además, manejar estructuras de longitud variable como listas es más complejo que manejar una matriz de longitud fija, por lo que las funciones de la biblioteca, especialmente las de bajo nivel, tienden a evitar la molestia.

Tampoco estoy muy seguro sobre la implementación (cómo el sistema operativo interactúa con TLB y Co en este caso), pero puede ser que (incluso una diferencia de tamaño aparte) llene el mapa de bits se pueda realizar más rápido que una lista debido a las estructuras de OS y hardware a partir de las cuales se extrae la información.

Si no le preocupa la granularidad muy fina, puede consultar /proc/<PID>/smaps. Para cada región mapeada, muestra algunas estadísticas, incluida la cantidad que se carga en la memoria (campo Rss). Si para la depuración mapea algunas regiones de un archivo con una llamada separada mmap() (además de la asignación principal utilizada para realizar la tarea real), probablemente obtendrá entradas separadas en smaps y, por lo tanto, verá estadísticas separadas para estas regiones. Es casi seguro que no pueda hacer miles de millones de mapeos sin matar su sistema, pero si el archivo está bien estructurado, tal vez tener estadísticas separadas para unas pocas docenas de regiones bien elegidas puede ayudarlo a encontrar las respuestas que está buscando.

+0

Probé smaps de hecho. Sin embargo, por alguna razón, no informa las páginas de memoria mapeadas por otros procesos, por lo que no me ayuda en este caso particular. Lo que realmente estoy buscando es el acceso a la tabla de direcciones virtuales a físicas de MMU :) – wazoox

Cuestiones relacionadas