Di 192 GB di RAM installata sul mio computer, ho 188 GB di RAM superiore a 4 GB (all'indirizzo hardware 0x100000000) riservato dal kernel Linux all'avvio (mem = 4G memmap = 188g $ 4G). I moduli del kernel di acquisizione dati accumulano i dati in questa vasta area utilizzata come buffer circolare utilizzando DMA. Un'applicazione utente mmap memorizza questo buffer ad anello nello spazio utente, quindi copia i blocchi dal buffer circolare nella posizione corrente per l'elaborazione una volta che sono pronti.Scarse prestazioni memcpy nello spazio utente per la memoria fisica di mmap in Linux
La copia di questi blocchi da 16 MB dall'area di mmap'utilizzando memcpy non funziona come previsto. Sembra che le prestazioni dipendano dalla dimensione della memoria riservata al momento dell'avvio (e successivamente memorizzata nello spazio utente). http://www.wurmsdobler.org/files/resmem.zip contiene il codice sorgente di un modulo del kernel che fa implementa l'operazione sul file 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;
}
e un'applicazione di test, che fa in sostanza (con i controlli rimossi):
#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;
ho portato prove memcpy di un blocco di dati di 16 MB per le diverse dimensioni di RAM riservata (resmem_length) su Ubuntu 10.04.4, Linux 2.6.32, su 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)
Le mie osservazioni sono:
Dalla prima alla seconda corsa, memcpy da mmap'ed a malloc'ed sembra trarre beneficio che i contenuti potrebbero già essere memorizzate nella cache da qualche parte.
C'è un significativo peggioramento delle prestazioni da> 64 GB, che può essere notato sia quando si utilizza una memcpy.
Mi piacerebbe capire perché lo sia. Forse qualcuno nel pensiero di gruppo sviluppatori del kernel Linux: 64GB dovrebbe essere sufficiente per chiunque (fa suonare un campanello?)
Cordiali saluti, peter
Ciao Ignacio, si può essere di destra. Il computer è dotato di due Intel Xeon E5620 2.Quad core 4GHz con 12 MB di cache L3 ciascuno e velocità di memoria 1066 MHz. – PeterW
La mia visione semplicistica è che per la prima operazione di lettura il contenuto nella RAM verrebbe memorizzato nella cache, e la seconda richiesta verrebbe pubblicata direttamente dalla cache, a condizione che l'importo si adatti alla cache. Avrei pensato che la quantità di dati trasferiti avrebbe avuto un effetto sulla memcpy, nel mio caso <12 MB, ma non sulla dimensione totale della memoria adattata o sulla RAM dei dati. – PeterW
Ulteriori test hanno dimostrato che lo stesso degrado delle prestazioni si mostra per blocchi di dati più piccoli, ad es. 1MB. Mi sembra che dipenda solo dalla quantità di memoria riservata all'avvio, cioè non più di 64 GB. – PeterW