La mappatura della memoria di un file evita direttamente la copia dei buffer che avviene con read()
e write()
chiamate. Chiamate a read()
e write()
includere un puntatore al buffer nello spazio degli indirizzi del processo in cui sono archiviati i dati. Il kernel deve copiare i dati in/da quelle posizioni. Usando mmap()
mappa il file allo spazio degli indirizzi del processo, in modo che il processo possa indirizzare il file direttamente e non sono necessarie copie.
Inoltre, non vi è alcun sovraccarico della chiamata di sistema quando si accede al file mappato in memoria dopo la chiamata iniziale se il file viene caricato in memoria all'iniziale mmap()
. Se una pagina del file mappato non è in memoria, l'accesso genererà un errore e richiederà al kernel di caricare la pagina in memoria. Leggere un grande blocco con read()
può essere più veloce di mmap()
in tali casi, se mmap()
genererebbe un numero significativo di errori per leggere il file. (È possibile avvisare il kernel in anticipo con madvise()
in modo che il kernel possa caricare le pagine in anticipo prima dell'accesso).
Per maggiori dettagli, c'è una domanda correlata su Stack Overflow:mmap() rispetto ai blocchi di lettura
Innanzitutto, nella maggior parte delle operazioni di I/O le caratteristiche dell'hardware di archiviazione sottostante dominano le prestazioni. Un array RAID5 mal configurato di ventinove dischi SATA S-L-O-W 5400 rpm su un sistema lento e affamato di memoria che utilizza RAID S/W con dimensioni dei blocchi non corrispondenti e file system non allineati darà prestazioni scadenti rispetto a un array configurato e allineato correttamente SSD RAID 1+0 su un controller ad alte prestazioni nonostante qualsiasi messa a punto del software che potresti provare.
Ma l'unico modo mmap()
può essere significativamente più veloce se leggi gli stessi dati più di una volta e i dati che leggi non vengono impaginati tra le letture a causa della pressione della memoria.
Passaggi della mappa della memoria:
- Chiamata di sistema per creare mappature virtuali - molto costosa
- Il processo accede alla memoria per la prima volta, causando un errore di pagina:costoso (e potrebbe essere necessario ripeterlo se viene eseguito il paging)
- Il processo legge effettivamente la memoria
Se il processo esegue solo i passaggi 2 e 3 una volta per ogni bit di dati letto o i dati vengono eliminati dalla memoria a causa della pressione della memoria, mmap()
sarà più lento.
read()
passaggi:
- La chiamata di sistema copia i dati dal disco alla cache della pagina (può verificarsi o meno un errore di pagina, i dati potrebbero già trovarsi nella cache della pagina e ciò potrebbe essere saltato)
- Dati copiati dalla cache della pagina alla memoria di elaborazione (possono o meno errori di pagina)
La mappatura della memoria supererà solo questo in termini di prestazioni a causa di quella copia extra dalla cache della pagina per elaborare la memoria. Ma una semplice copia di una pagina di memoria (o meno) deve essere eseguita più volte per battere il costo dell'impostazione della mappatura, probabilmente. Quante volte dipende dal tuo sistema. Larghezza di banda della memoria, come viene utilizzato l'intero sistema, tutto. Ad esempio, se il tempo impiegato dalla gestione della memoria del kernel per impostare la mappatura non sarebbe stato comunque utilizzato da nessun altro processo, il costo della creazione della mappatura in realtà non è molto elevato. Al contrario, se sul tuo sistema sono presenti molte elaborazioni che comportano molte creazione/distruzione di mappatura della memoria virtuale (ovvero molti processi di breve durata), l'impatto dell'IO mappato in memoria potrebbe essere significativo.
Poi c'è read()
utilizzando l'IO diretto:
- Chiamata di sistema per leggere dal disco nello spazio di memoria del processo. (può causare o meno un errore di pagina)
Le letture di IO diretto sono praticamente impossibili da battere in termini di prestazioni. Ma devi davvero adattare i tuoi schemi IO al tuo hardware per massimizzare le prestazioni.
Nota che un processo può praticamente controllare se la lettura dei dati provoca un page fault per il buffer che il processo sta usando per leggere.
Quindi, l'accesso ai file mappati in memoria è più veloce? Forse lo è, forse non lo è.
Dipende dai tuoi schemi di accesso. Insieme al tuo hardware e a tutto il resto nei tuoi percorsi IO.
Se stai riproducendo in streaming un file video da 30 GB su un computer con 4 GB di RAM e non torni mai indietro a rileggere i dati, la mappatura della memoria del file è probabilmente la peggiore modo di leggerlo.
Al contrario, se disponi di una tabella di ricerca da 100 MB per alcuni dati a cui accedi in modo casuale miliardi e miliardi di volte durante l'elaborazione e memoria sufficiente affinché il file non venga mai impaginato, la mappatura della memoria annullerà tutti gli altri metodi di accesso.
Un enorme vantaggio dei file mappati in memoria
I file di mappatura della memoria hanno un enorme vantaggio rispetto ad altre forme di IO:la semplicità del codice. È davvero difficile battere la semplicità di accedere a un file come se fosse in memoria. E la maggior parte delle volte, la differenza di prestazioni tra la mappatura della memoria di un file e l'esecuzione di operazioni di I/O discrete non è poi così tanto.