De 192 GB de RAM instalados en mi computadora, tengo 188GB RAM por encima de 4GB (en la dirección de hardware 0x100000000) reservados por el kernel Linux en el arranque (mem = 4G memmap = 188G $ 4G). Los módulos del kernel de adquisición de datos acumulan datos en esta gran área utilizada como un buffer en anillo usando DMA. Una aplicación de espacio de usuario mmap almacena este búfer de anillo en el espacio de usuario, luego copia los bloques del búfer de anillo en la ubicación actual para procesarlos una vez que estén listos.Pobre rendimiento memcpy en el espacio de usuario para memoria física mmap'ed en Linux
Copiando estos bloques de 16MB del área mmap'ed utilizando memcpy no funciona como esperaba. Parece que el rendimiento depende del tamaño de la memoria reservada en el momento del arranque (y más tarde mmap'ed en el espacio del usuario). http://www.wurmsdobler.org/files/resmem.zip contiene el código fuente para un módulo de núcleo que hace implementa la operación de archivo mmap:
module_param(resmem_hwaddr, ulong, S_IRUSR);
module_param(resmem_length, ulong, S_IRUSR);
//...
static int resmem_mmap(struct file *filp, struct vm_area_struct *vma) {
remap_pfn_range(vma, vma->vm_start,
resmem_hwaddr >> PAGE_SHIFT,
resmem_length, vma->vm_page_prot);
return 0;
}
y una aplicación de prueba, que hace en esencia (con los controles eliminados):
#define BLOCKSIZE ((size_t)16*1024*1024)
int resMemFd = ::open(RESMEM_DEV, O_RDWR | O_SYNC);
unsigned long resMemLength = 0;
::ioctl(resMemFd, RESMEM_IOC_LENGTH, &resMemLength);
void* resMemBase = ::mmap(0, resMemLength, PROT_READ | PROT_WRITE, MAP_SHARED, resMemFd, 4096);
char* source = ((char*)resMemBase) + RESMEM_HEADER_SIZE;
char* destination = new char[BLOCKSIZE];
struct timeval start, end;
gettimeofday(&start, NULL);
memcpy(destination, source, BLOCKSIZE);
gettimeofday(&end, NULL);
float time = (end.tv_sec - start.tv_sec)*1000.0f + (end.tv_usec - start.tv_usec)/1000.0f;
std::cout << "memcpy from mmap'ed to malloc'ed: " << time << "ms (" << BLOCKSIZE/1000.0f/time << "MB/s)" << std::endl;
he llevado memcpy a cabo pruebas de un bloque de datos de 16 MB para los diferentes tamaños de memoria RAM reservada (resmem_length) en Ubuntu 10.04.4, Linux 2.6.32, en un SuperMicro 1026GT-TF-FM109:
| | 1GB | 4GB | 16GB | 64GB | 128GB | 188GB
|run 1 | 9.274ms (1809.06MB/s) | 11.503ms (1458.51MB/s) | 11.333ms (1480.39MB/s) | 9.326ms (1798.97MB/s) | 213.892ms ( 78.43MB/s) | 206.476ms ( 81.25MB/s)
|run 2 | 4.255ms (3942.94MB/s) | 4.249ms (3948.51MB/s) | 4.257ms (3941.09MB/s) | 4.298ms (3903.49MB/s) | 208.269ms ( 80.55MB/s) | 200.627ms ( 83.62MB/s)
Mis observaciones son:
De la primera a la segunda pasada, establecimiento de memoria de mmap'ed a malloc'ed parece beneficiar a los contenidos ya que podrían ser cacheados en alguna parte.
Existe una degradación significativa del rendimiento de> 64 GB, que se puede notar cuando se utiliza una memcpy.
Me gustaría entender por qué eso es así. Tal vez alguien en el pensamiento de grupo desarrolladores del núcleo Linux: 64 GB debería ser suficiente para cualquiera (hace esto suena?)
Saludos cordiales, peter
Hola Ignacio, puede que tengas razón. La computadora está equipada con dos Intel Xeon E5620 2.4GHz quad core con 12MB L3 caché cada uno y 1066MHz de velocidad de memoria. – PeterW
Mi visión simplista es que para la primera operación de lectura, los contenidos en la RAM se almacenarían en caché, y la segunda solicitud se serviría directamente desde el caché, siempre que la cantidad se ajuste a la caché. Hubiera pensado que la cantidad de datos transferidos tendría un efecto en memcpy, en mi caso <12MB, pero no en el tamaño total de la memoria instalada o en la memoria RAM de los datos. – PeterW
Pruebas adicionales han demostrado que la misma degradación del rendimiento se muestra para bloques de datos más pequeños, p. 1MB. Solo parece depender de la cantidad de memoria reservada en el momento del arranque, es decir, no más de 64 GB. – PeterW