Domanda

Sto lavorando a un programma che elaborerà file che potrebbero potenzialmente avere dimensioni pari o superiori a 100 GB.I file contengono serie di record di lunghezza variabile.Ho una prima implementazione attiva e funzionante e ora sto cercando di migliorare le prestazioni, in particolare di eseguire l'I/O in modo più efficiente poiché il file di input viene scansionato molte volte.

Esiste una regola pratica per l'utilizzo mmap() rispetto alla lettura in blocchi tramite C++ fstream biblioteca?Quello che mi piacerebbe fare è leggere blocchi di grandi dimensioni dal disco in un buffer, elaborare record completi dal buffer e quindi leggere di più.

IL mmap() il codice potrebbe potenzialmente diventare molto confuso da allora mmapI blocchi devono trovarsi sui limiti delle dimensioni della pagina (da quanto ho capito) e i record potrebbero potenzialmente piacere oltre i limiti della pagina.Con fstreamCosì, posso semplicemente cercare l'inizio di un record e ricominciare a leggere, poiché non siamo limitati a leggere blocchi che si trovano sui limiti delle dimensioni di una pagina.

Come posso decidere tra queste due opzioni senza prima scrivere un'implementazione completa?Eventuali regole pratiche (ad es. mmap() è 2 volte più veloce) o semplici test?

È stato utile?

Soluzione

Stavo cercando di trovare l'ultima parola sulle prestazioni mmap/lettura su Linux e mi sono imbattuto in un bel post (collegamento) sulla mailing list del kernel Linux.È del 2000, quindi da allora ci sono stati molti miglioramenti all'IO e alla memoria virtuale nel kernel, ma spiega bene il motivo per cui mmap O read potrebbe essere più veloce o più lento.

  • Una chiamata a mmap ha più spese generali di read (proprio come epoll ha più spese generali di poll, che ha un sovraccarico maggiore di read).La modifica delle mappature della memoria virtuale è un'operazione piuttosto costosa su alcuni processori per gli stessi motivi per cui è costoso il passaggio tra processi diversi.
  • Il sistema IO può già utilizzare la cache del disco, quindi se leggi un file, colpirai la cache o la perderai, indipendentemente dal metodo utilizzato.

Tuttavia,

  • Le mappe di memoria sono generalmente più veloci per l'accesso casuale, soprattutto se i modelli di accesso sono sparsi e imprevedibili.
  • Le mappe della memoria te lo consentono Mantenere utilizzando le pagine dalla cache finché non hai finito.Ciò significa che se utilizzi un file in modo intensivo per un lungo periodo di tempo, quindi lo chiudi e lo riapri, le pagine verranno comunque memorizzate nella cache.Con read, il tuo file potrebbe essere stato cancellato dalla cache molto tempo fa.Ciò non si applica se si utilizza un file e lo si elimina immediatamente.(Se ci provi mlock pagine solo per tenerle nella cache, stai cercando di superare in astuzia la cache del disco e questo tipo di sciocchezze raramente aiuta le prestazioni del sistema).
  • Leggere direttamente un file è molto semplice e veloce.

La discussione su mmap/read mi ricorda altre due discussioni sulle prestazioni:

  • Alcuni programmatori Java sono rimasti scioccati nello scoprire che l'I/O non bloccante è spesso più lento dell'I/O bloccante, il che aveva perfettamente senso se si sapeva che l'I/O non bloccante richiede l'esecuzione di più chiamate di sistema.

  • Alcuni altri programmatori di rete sono rimasti scioccati nell'apprenderlo epoll è spesso più lento di poll, il che ha perfettamente senso se sai che gestire epoll richiede di effettuare più chiamate di sistema.

Conclusione: Utilizza le mappe di memoria se accedi ai dati in modo casuale, li mantieni per molto tempo o se sai che puoi condividerli con altri processi (MAP_SHARED non è molto interessante se non c'è una vera condivisione).Leggi i file normalmente se accedi ai dati in sequenza o li scarti dopo la lettura.E se uno dei due metodi rende il tuo programma meno complesso, fallo Quello.Per molti casi reali non esiste un modo sicuro per dimostrare che uno è più veloce senza testare l'applicazione reale e NON un benchmark.

(Mi scuso per aver infangato questa domanda, ma stavo cercando una risposta e questa domanda continuava ad apparire in cima ai risultati di Google.)

Altri suggerimenti

Il costo principale delle prestazioni sarà l'i/o del disco."mmap()" è certamente più veloce di istream, ma la differenza potrebbe non essere evidente perché l'i/o del disco dominerà i tempi di esecuzione.

Ho provato il frammento di codice di Ben Collins (vedi sopra/sotto) per verificare la sua affermazione che "mmap() is modo più veloce" e non ha trovato alcuna differenza misurabile.Vedi i miei commenti sulla sua risposta.

Lo farei sicuramente non consiglia di mappare separatamente ciascun record a turno, a meno che i tuoi "record" non siano enormi: sarebbe terribilmente lento, richiederebbe 2 chiamate di sistema per ciascun record e potrebbe perdere la pagina dalla cache della memoria del disco .....

Nel tuo caso penso che mmap(), istream e le chiamate open()/read() di basso livello saranno tutte più o meno le stesse.Consiglierei mmap() in questi casi:

  1. Esiste un accesso casuale (non sequenziale) all'interno del file, AND
  2. il tutto si adatta comodamente alla memoria OPPURE esiste una località di riferimento all'interno del file in modo che alcune pagine possano essere mappate e altre pagine mappate.In questo modo il sistema operativo utilizza la RAM disponibile per il massimo beneficio.
  3. OPPURE se più processi leggono/lavorano sullo stesso file, mmap() è fantastico perché i processi condividono tutti le stesse pagine fisiche.

(a proposito, adoro mmap()/MapViewOfFile()).

mmap è modo Più veloce.Potresti scrivere un semplice benchmark per dimostrarlo a te stesso:

char data[0x1000];
std::ifstream in("file.bin");

while (in)
{
  in.read(data, 0x1000);
  // do something with data
}

contro:

const int file_size=something;
const int page_size=0x1000;
int off=0;
void *data;

int fd = open("filename.bin", O_RDONLY);

while (off < file_size)
{
  data = mmap(NULL, page_size, PROT_READ, 0, fd, off);
  // do stuff with data
  munmap(data, page_size);
  off += page_size;
}

Chiaramente, sto tralasciando i dettagli (come come determinare quando raggiungi la fine del file nel caso in cui il tuo file non sia un multiplo di page_size, per esempio), ma in realtà non dovrebbe essere molto più complicato di così.

Se puoi, potresti provare a suddividere i tuoi dati in più file che possono essere mmap()-ed in tutto invece che in parte (molto più semplice).

Un paio di mesi fa ho avuto un'implementazione incompleta di una classe stream mmap()-ed a finestra scorrevole per boost_iostreams, ma a nessuno importava e mi sono dato da fare con altre cose.Sfortunatamente, qualche settimana fa ho cancellato un archivio di vecchi progetti incompiuti, e quella è stata una delle vittime :-(

Aggiornamento:Dovrei anche aggiungere l'avvertenza che questo benchmark apparirebbe molto diverso in Windows perché Microsoft ha implementato un'elegante cache di file che fa la maggior parte di ciò che faresti con mmap in primo luogo.Cioè, per i file a cui si accede di frequente, potresti semplicemente fare std::ifstream.read() e sarebbe veloce come mmap, perché la cache dei file avrebbe già eseguito una mappatura della memoria per te ed è trasparente.

Aggiornamento finale:Guarda, gente:su molte combinazioni di piattaforme diverse di sistemi operativi e librerie standard, dischi e gerarchie di memoria, non posso dire con certezza che la chiamata di sistema mmap, visto come una scatola nera, sarà sempre sempre sostanzialmente più veloce di read.Non era esattamente questo il mio intento, anche se le mie parole potevano essere interpretate in quel modo. In definitiva, il mio punto era che l'i/o mappato in memoria è generalmente più veloce dell'i/o basato su byte;questo è ancora vero.Se trovi sperimentalmente che non c'è differenza tra i due, allora l'unica spiegazione che mi sembra ragionevole è che la tua piattaforma implementa la mappatura della memoria sotto le coperte in un modo vantaggioso per le prestazioni delle chiamate a read.L'unico modo per essere assolutamente certi di utilizzare l'i/o mappato in memoria in modo portabile è utilizzare mmap.Se non ti interessa la portabilità e puoi fare affidamento sulle caratteristiche particolari delle tue piattaforme di destinazione, allora utilizza read può essere adatto senza sacrificare in modo misurabile alcuna prestazione.

Modifica per ripulire l'elenco delle risposte:@jbl:

La mMap della finestra scorrevole sembra interessante.Puoi dire un po 'di più al riguardo?

Certo, stavo scrivendo una libreria C++ per Git (una libgit++, se vuoi), e mi sono imbattuto in un problema simile a questo:Dovevo essere in grado di aprire file di grandi dimensioni (molto grandi) e non che le prestazioni fossero un cane totale (come sarebbe con std::fstream).

Boost::Iostreams ha già un mapped_file Source, ma il problema era che lo era mmapeseguire il ping di interi file, che ti limita a 2 ^ (dimensione parole).Su macchine a 32 bit, 4 GB non sono abbastanza grandi.Non è irragionevole aspettarsi di avere .pack file in Git che diventano molto più grandi di così, quindi avevo bisogno di leggere il file in blocchi senza ricorrere al normale i/o dei file.Sotto le coperte di Boost::Iostreams, ho implementato una Sorgente, che è più o meno un'altra visione dell'interazione tra std::streambuf E std::istream.Potresti anche provare un approccio simile semplicemente ereditando std::filebuf in un mapped_filebuf e allo stesso modo, ereditare std::fstream in a mapped_fstream.È l'interazione tra i due che è difficile da ottenere. Boost::Iostreams ha svolto parte del lavoro per te e fornisce anche hook per filtri e catene, quindi ho pensato che sarebbe stato più utile implementarlo in questo modo.

Ci sono già molte buone risposte qui che coprono molti dei punti salienti, quindi aggiungerò solo un paio di questioni che non ho visto affrontate direttamente sopra.Cioè, questa risposta non dovrebbe essere considerata un elenco completo dei pro e dei contro, ma piuttosto un'aggiunta ad altre risposte qui.

mmap sembra magico

Prendendo il caso in cui il file è già completamente memorizzato nella cache1 come linea di base2, mmap potrebbe sembrare molto simile Magia:

  1. mmap richiede solo 1 chiamata di sistema per mappare (potenzialmente) l'intero file, dopodiché non sono necessarie altre chiamate di sistema.
  2. mmap non richiede una copia dei dati del file dal kernel allo spazio utente.
  3. mmap ti consente di accedere al file "come memoria", inclusa l'elaborazione con qualsiasi trucco avanzato che puoi fare contro la memoria, come la vettorizzazione automatica del compilatore, SIMD intrinseci, precaricamento, routine di analisi in memoria ottimizzate, OpenMP, ecc.

Nel caso in cui il file sia già nella cache, sembra impossibile batterlo:accedi direttamente alla cache della pagina del kernel come memoria e non può essere più veloce di così.

Beh, può.

mmap non è in realtà magico perché...

mmap funziona ancora per pagina

Un costo nascosto primario di mmap contro read(2) (che è in realtà la chiamata di sistema comparabile a livello di sistema operativo per blocchi di lettura) è quello con mmap dovrai fare "un po' di lavoro" per ogni pagina 4K nello spazio utente, anche se potrebbe essere nascosta dal meccanismo di page-fault.

Ad esempio, un'implementazione tipica che just mmapPoiché l'intero file dovrà essere inserito in errore, quindi 100 GB / 4K = 25 milioni di errori per leggere un file da 100 GB.Ora, questi saranno difetti minori, ma 25 miliardi di errori di pagina non saranno comunque super veloci.Nel migliore dei casi, il costo di un guasto minore è probabilmente nell'ordine delle centinaia di nanometri.

mmap fa molto affidamento sulle prestazioni TLB

Ora puoi passare MAP_POPULATE A mmap per dirgli di impostare tutte le tabelle delle pagine prima di tornare, quindi non dovrebbero esserci errori di pagina durante l'accesso.Ora, questo ha il piccolo problema che legge anche l'intero file nella RAM, che esploderà se provi a mappare un file da 100 GB, ma per ora ignoriamolo3.Il kernel deve fare lavoro per pagina per impostare queste tabelle delle pagine (appare come ora del kernel).Questo finisce per essere un costo importante nel mmap approccio ed è proporzionale alla dimensione del file (ovvero, non diventa relativamente meno importante man mano che la dimensione del file aumenta)4.

Infine, anche nello spazio utente l'accesso a tale mappatura non è esattamente gratuito (rispetto ai buffer di memoria di grandi dimensioni non originati da un sistema basato su file). mmap) - anche una volta impostate le tabelle delle pagine, ogni accesso a una nuova pagina comporterà, concettualmente, un errore TLB.Da mmapInserendo un file significa utilizzare la cache della pagina e le sue pagine da 4K, si sostiene nuovamente questo costo 25 milioni di volte per un file da 100 GB.

Ora, il costo effettivo di questi errori TLB dipende in larga misura almeno dai seguenti aspetti del tuo hardware:(a) quante entità TLB 4K hai e come funziona il resto della memorizzazione nella cache della traduzione (b) quanto bene il precaricamento dell'hardware gestisce il TLB: ad esempio, il precaricamento può attivare un passaggio di pagina?(c) quanto velocemente e quanto è parallelo l'hardware di spostamento delle pagine.Sui moderni processori Intel x86 di fascia alta, l'hardware di spostamento delle pagine è in generale molto potente:ci sono almeno 2 page walker paralleli, un page walk può verificarsi contemporaneamente all'esecuzione continua e il prelettura dell'hardware può attivare un page walk.Quindi l’impatto del TLB su a streaming il carico di lettura è piuttosto basso e tale carico spesso avrà prestazioni simili indipendentemente dalle dimensioni della pagina.Tuttavia, altri hardware sono solitamente molto peggiori!

read() evita queste trappole

IL read() syscall, che è ciò che generalmente è alla base delle chiamate di tipo "lettura a blocchi" offerte ad esempio in C, C++ e altri linguaggi, presenta uno svantaggio principale di cui tutti sono ben consapevoli:

  • Ogni read() la chiamata di N byte deve copiare N byte dal kernel allo spazio utente.

D'altra parte, evita la maggior parte dei costi sopra indicati: non è necessario mappare 25 milioni di pagine 4K nello spazio utente.Di solito puoi malloc un singolo buffer, un piccolo buffer nello spazio utente e riutilizzarlo ripetutamente per tutti i tuoi read chiamate.Dal lato del kernel, non ci sono quasi problemi con le pagine 4K o i mancati TLB perché tutta la RAM è solitamente mappata linearmente utilizzando poche pagine molto grandi (ad esempio, pagine da 1 GB su x86), quindi le pagine sottostanti nella cache delle pagine sono coperte in modo molto efficiente nello spazio del kernel.

Quindi in pratica hai il seguente confronto per determinare quale è più veloce per una singola lettura di un file di grandi dimensioni:

Il lavoro extra per pagina è implicito nel file mmap approccio più costoso del lavoro per byte di copia del contenuto del file dal kernel allo spazio utente implicito nell'utilizzo read()?

Su molti sistemi, in realtà sono approssimativamente bilanciati.Tieni presente che ognuno di essi è scalabile con attributi completamente diversi dell'hardware e dello stack del sistema operativo.

In particolare, il mmap l’approccio diventa relativamente più veloce quando:

  • Il sistema operativo dispone di una gestione rapida degli errori minori e soprattutto di ottimizzazioni del bulking degli errori minori come il Fault-around.
  • Il sistema operativo ha una buona MAP_POPULATE implementazione in grado di elaborare in modo efficiente mappe di grandi dimensioni nei casi in cui, ad esempio, le pagine sottostanti sono contigue nella memoria fisica.
  • L'hardware ha ottime prestazioni di traduzione delle pagine, come TLB di grandi dimensioni, TLB veloci di secondo livello, page walker veloci e paralleli, buona interazione di precaricamento con la traduzione e così via.

...mentre il read() l’approccio diventa relativamente più veloce quando:

  • IL read() syscall ha buone prestazioni di copia.Ad esempio, buono copy_to_user prestazioni lato kernel.
  • Il kernel ha un modo efficiente (rispetto allo spazio utente) per mappare la memoria, ad esempio utilizzando solo poche pagine di grandi dimensioni con supporto hardware.
  • Il kernel dispone di chiamate di sistema veloci e di un modo per mantenere le voci TLB del kernel in giro tra le chiamate di sistema.

I fattori hardware sopra indicati variano selvaggiamente su piattaforme diverse, anche all'interno della stessa famiglia (ad esempio, all'interno di generazioni x86 e soprattutto in segmenti di mercato) e sicuramente attraverso architetture (ad esempio, ARM vs x86 vs PPC).

Anche i fattori del sistema operativo continuano a cambiare, con vari miglioramenti da entrambe le parti che causano un grande salto nella velocità relativa per un approccio o l'altro.Un elenco recente include:

  • Aggiunta del sistema di aggiramento dei guasti, descritto sopra, che aiuta davvero il mmap caso senza MAP_POPULATE.
  • Aggiunta del percorso rapido copy_to_user metodi dentro arch/x86/lib/copy_user_64.S, ad esempio, utilizzando REP MOVQ quando è veloce, il che aiuta davvero read() caso.

Aggiornamento dopo Spectre e Meltdown

Le mitigazioni per le vulnerabilità Spectre e Meltdown hanno aumentato notevolmente il costo di una chiamata di sistema.Sui sistemi che ho misurato, il costo di una chiamata di sistema "non fare nulla" (che è una stima del puro sovraccarico della chiamata di sistema, a parte qualsiasi lavoro effettivo svolto dalla chiamata) è passato da circa 100 ns su un valore tipico moderno sistema Linux a circa 700 ns.Inoltre, a seconda del sistema, il file isolamento della tabella delle pagine la correzione specifica per Meltdown può avere ulteriori effetti a valle oltre al costo diretto delle chiamate di sistema dovuto alla necessità di ricaricare le voci TLB.

Tutto questo è uno svantaggio relativo per read() metodi basati rispetto a mmap metodi basati, da allora read() i metodi devono effettuare una chiamata di sistema per ogni valore di "dimensione buffer" di dati.Non è possibile aumentare arbitrariamente la dimensione del buffer per ammortizzare questo costo poiché l'utilizzo di buffer di grandi dimensioni di solito ha prestazioni peggiori poiché si supera la dimensione L1 e quindi si subiscono costantemente errori di cache.

D'altra parte, con mmap, puoi mappare un'ampia regione di memoria con MAP_POPULATE e accedervi in ​​modo efficiente, al costo di una sola chiamata di sistema.


1 Ciò include più o meno anche il caso in cui il file non è stato completamente memorizzato nella cache all'inizio, ma in cui la lettura anticipata del sistema operativo è abbastanza buona da farlo apparire tale (ovvero, la pagina viene solitamente memorizzata nella cache nel momento desiderato Esso).Si tratta di un problema sottile, tuttavia, perché il modo in cui funziona la lettura anticipata è spesso molto diverso mmap E read chiamate e può essere ulteriormente regolato mediante chiamate "avvisate" come descritto in 2.

2 ...perché se il file è non memorizzato nella cache, il tuo comportamento sarà completamente dominato dalle preoccupazioni di IO, incluso quanto sia comprensivo il tuo modello di accesso per l'hardware sottostante - e tutto il tuo sforzo dovrebbe essere volto a garantire che tale accesso sia il più comprensivo possibile, ad es.tramite l'uso di madvise O fadvise chiamate (e qualsiasi modifica a livello di applicazione che è possibile apportare per migliorare i modelli di accesso).

3 Potresti aggirare il problema, ad esempio, in sequenza mmaping in finestre di dimensioni più piccole, diciamo 100 MB.

4 In effetti, risulta che MAP_POPULATE L'approccio è (almeno una combinazione hardware/sistema operativo) solo leggermente più veloce rispetto a non utilizzarlo, probabilmente perché il kernel lo sta utilizzando difettoso - quindi il numero effettivo di difetti minori viene ridotto di un fattore pari a 16 circa.

Mi dispiace che Ben Collins abbia perso il codice sorgente dell'MMAP di Windows scorrevole.Sarebbe carino averlo in Boost.

Sì, la mappatura del file è molto più veloce.Stai essenzialmente utilizzando il sottosistema di memoria virtuale del sistema operativo per associare memoria a disco e viceversa.Pensaci in questo modo:se gli sviluppatori del kernel del sistema operativo potessero renderlo più veloce, lo farebbero.Perché così facendo tutto diventa più veloce:database, tempi di avvio, tempi di caricamento del programma, eccetera.

L'approccio con la finestra scorrevole non è poi così difficile in quanto è possibile mappare più pagine contigue contemporaneamente.Quindi la dimensione del record non ha importanza purché il più grande di ogni singolo record possa essere contenuto nella memoria.L'importante è gestire la contabilità.

Se un record non inizia sul confine getpagesize(), la mappatura deve iniziare dalla pagina precedente.La lunghezza della regione mappata si estende dal primo byte del record (arrotondato per difetto, se necessario, al multiplo più vicino di getpagesize()) all'ultimo byte del record (arrotondato per eccesso al multiplo più vicino di getpagesize()).Quando hai finito di elaborare un record, puoi unmap() e passare a quello successivo.

Tutto funziona perfettamente anche sotto Windows utilizzando CreateFileMapping() e MapViewOfFile() (e GetSystemInfo() per ottenere SYSTEM_INFO.dwAllocationGranularity --- non SYSTEM_INFO.dwPageSize).

mmap dovrebbe essere più veloce, ma non so quanto.Dipende molto dal tuo codice.Se usi mmap è meglio mmap l'intero file in una volta, questo ti renderà la vita molto più semplice.Un potenziale problema è che se il tuo file è più grande di 4 GB (o in pratica il limite è inferiore, spesso 2 GB) avrai bisogno di un'architettura a 64 bit.Quindi, se stai utilizzando un ambiente 32, probabilmente non vorrai usarlo.

Detto questo, potrebbe esserci una strada migliore per migliorare le prestazioni.Hai detto il file di input viene scansionato più volte, se riesci a leggerlo in un solo passaggio e poi a finirlo, potrebbe essere potenzialmente molto più veloce.

Sono d'accordo che l'I/O del file mmap sarà più veloce, ma mentre esegui il benchmarking del codice, il controesempio non dovrebbe essere un po' ottimizzato?

Ben Collins ha scritto:

char data[0x1000];
std::ifstream in("file.bin");

while (in)
{
    in.read(data, 0x1000);
    // do something with data 
}

Suggerirei anche di provare:

char data[0x1000];
std::ifstream iifle( "file.bin");
std::istream  in( ifile.rdbuf() );

while( in )
{
    in.read( data, 0x1000);
    // do something with data
}

Oltre a ciò, potresti anche provare a rendere la dimensione del buffer uguale a quella di una pagina di memoria virtuale, nel caso in cui 0x1000 non abbia la dimensione di una pagina di memoria virtuale sul tuo computer...L'I/O del file mmap'd IMHO vince ancora, ma questo dovrebbe avvicinare le cose.

Forse dovresti pre-elaborare i file, quindi ogni record si trova in un file separato (o almeno che ogni file abbia una dimensione compatibile con mmap).

Potresti anche eseguire tutte le fasi di elaborazione per ciascun record, prima di passare a quello successivo?Forse questo eviterebbe parte del sovraccarico di IO?

A mio avviso, l'utilizzo di mmap() "semplicemente" solleva lo sviluppatore dal dover scrivere il proprio codice di memorizzazione nella cache.In un semplice caso "leggi il file esattamente una volta", questo non sarà difficile (anche se, come sottolinea mlbrock, salvi comunque la copia di memoria nello spazio del processo), ma se vai avanti e indietro nel file o saltando pezzi e così via, credo che gli sviluppatori del kernel lo abbiano fatto probabilmente ho fatto un lavoro migliore di quanto potessi implementare la memorizzazione nella cache ...

Ricordo di aver mappato in memoria un enorme file contenente una struttura ad albero anni fa.Sono rimasto stupito dalla velocità rispetto alla normale deserializzazione che comporta molto lavoro in memoria, come l'allocazione dei nodi dell'albero e l'impostazione dei puntatori.Quindi, in effetti, stavo confrontando una singola chiamata con MMAP (o la sua controparte su Windows) rispetto a molte (molte) chiamate alle chiamate nuove e di costruzione.Per questo tipo di attività, mmap è imbattibile rispetto alla deserializzazione.Naturalmente si dovrebbe esaminare il puntatore rilocabile del boost per questo.

Sembra un buon caso d'uso per il multi-threading...Penserei che potresti facilmente impostare un thread per leggere i dati mentre gli altri li elaborano.Questo potrebbe essere un modo per aumentare notevolmente la prestazione percepita.Solo un pensiero.

Penso che la cosa più bella di mmap sia il potenziale per la lettura asincrona con:

    addr1 = NULL;
    while( size_left > 0 ) {
        r = min(MMAP_SIZE, size_left);
        addr2 = mmap(NULL, r,
            PROT_READ, MAP_FLAGS,
            0, pos);
        if (addr1 != NULL)
        {
            /* process mmap from prev cycle */
            feed_data(ctx, addr1, MMAP_SIZE);
            munmap(addr1, MMAP_SIZE);
        }
        addr1 = addr2;
        size_left -= r;
        pos += r;
    }
    feed_data(ctx, addr1, r);
    munmap(addr1, r);

Il problema è che non riesco a trovare il MAP_FLAGS giusto per suggerire che questa memoria dovrebbe essere sincronizzata dal file al più presto.Spero che MAP_POPULATE dia il suggerimento giusto per mmap (cioènon tenterà di caricare tutti i contenuti prima del ritorno dalla chiamata, ma lo farà in modo asincrono.con feed_data).Almeno dà risultati migliori con questo flag anche se il manuale afferma che non fa nulla senza MAP_PRIVATE dalla versione 2.6.23.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top