Pagina 1 di 2
Realizzare buffer scrittura [c/c++]
Inviato: sab 18 lug 2009, 16:39
da FireEater
Ho necessità di aumentare l'efficienza di output su file di un mio programma.
Per il momento scrivo su un file binario una serie di struct, sempre precedute da un char che mi indica il tipo di struct che andrò a leggere.
Ho intenzione di realizzare un buffer di 4KB per ottimizzare le scritture.
Per il momento ho poche idee, ho provato a realizzare un buffer allocando un char *buffer di 4KB con una malloc per poi inserire byte per byte i dati, ma oltre a funzionare male non so se è la strada giusta.
Codice: Seleziona tutto
void Profiler::WriteBuffer(char *b, size_t s)
{
char *tmp = NULL;
//buffer size è inizialmente 0;
tmp = outBuffer+bufferSize;
for ( size_t t = 0; t < s; t++)
{
tmp = tmp + t;
*tmp = b[t];
}
bufferSize = bufferSize + s;
if ( bufferSize > 4000 )
{
(*pOBinaryStream2).write((char *)outBuffer, bufferSize);
bufferSize = 0;
for (int i = 0; i<4096; i++)
*(outBuffer+i) = '\0';
}
}
Idee?
FireEater
Re: Realizzare buffer scrittura [c/c++]
Inviato: sab 18 lug 2009, 17:14
da targzeta
Normalmente il S.O. usa una cache per l'I/O, se tu gli chiedi di scrivere 1 byte, lui generalmente non lo fa, ma li mette in un buffer. Questo quindi risolve di per se il tuo problema.
Da una veloce lettura di open(2) si nota:
Codice: Seleziona tutto
O_DIRECT (Since Linux 2.4.10)
Try to minimize cache effects of the I/O to and from this file. In general this will degrade performance,
but it is useful in special situations, such as when applications do their own caching. File I/O is done directly
to/from user space buffers. The I/O is synchronous, that is, at the completion of a read(2) or write(2), data
is guaranteed to have been transferred. See NOTES below for further discussion.
A semantically similar (but deprecated) interface for block devices is described in raw(8).
che dovrebbe confermare che generalmente l'I/O viene "cachato". Se usi le funzioni della libreria standard, ovvero fopen(3) e fwrite(3) sono quasi sicuro di questo.
Più che altro fai attenzione alla serializzazione delle struct, ricorda che se una struct ha un puntatore, scrivere in un file la struct non significa scrivere anche il contenuto del puntatore.
Emanuele
Re: Realizzare buffer scrittura [c/c++]
Inviato: sab 18 lug 2009, 19:10
da Mario Vanoni
spina ha scritto:Normalmente il S.O. usa una cache per l'I/O, se tu gli chiedi di scrivere 1 byte, lui generalmente non lo fa, ma li mette in un buffer. Questo quindi risolve di per se il tuo problema.
Da una veloce lettura di open(2) si nota:
Codice: Seleziona tutto
O_DIRECT (Since Linux 2.4.10)
Try to minimize cache effects of the I/O to and from this file. In general this will degrade performance,
but it is useful in special situations, such as when applications do their own caching. File I/O is done directly
to/from user space buffers. The I/O is synchronous, that is, at the completion of a read(2) or write(2), data
is guaranteed to have been transferred. See NOTES below for further discussion.
A semantically similar (but deprecated) interface for block devices is described in raw(8).
che dovrebbe confermare che generalmente l'I/O viene "cachato". Se usi le funzioni della libreria standard, ovvero fopen(3) e fwrite(3) sono quasi sicuro di questo.
Più che altro fai attenzione alla serializzazione delle struct, ricorda che se una struct ha un puntatore, scrivere in un file la struct non significa scrivere anche il contenuto del puntatore.
Emanuele
Quello che disturba un po` nella man page:
"The thing that has always disturbed me about O_DIRECT is that the whole interface is just stupid, and was probably designed by a deranged monkey on some serious mind-controlling substances." -- Linus
Re: Realizzare buffer scrittura [c/c++]
Inviato: sab 18 lug 2009, 19:13
da targzeta
Emanuele
Re: Realizzare buffer scrittura [c/c++]
Inviato: sab 18 lug 2009, 20:19
da FireEater
So che il sistema operativo bufferizza le scritture su disco, come fa anche lo stesso HD tramite un buffer HW.
Però nei libri di ottimizzazione c'è scritto che un buffer di 4KB è la soluzione(generica) migliore, nel mio caso poi credo che la dimensione salirà anche a 64 o 128KB perchè devo scrivere file da parecchi MB che vengono letti momenti successivi da un altro programma.
Con la serializzazione delle struct non ho problemi dato che il tutto, esclusa la bufferizzazione, funziona.
Idee su un eventuale algoritmo/struttura dati per bufferizzare a mano?
Re: Realizzare buffer scrittura [c/c++]
Inviato: sab 18 lug 2009, 20:53
da targzeta
Hai già scartato il memory-mapperd I/O (mmap(2)) ?
Emanuele
Re: Realizzare buffer scrittura [c/c++]
Inviato: dom 19 lug 2009, 11:56
da robbybby
Dalle mie esperienze (che, pero', sono soprattutto nel mondo M$), se non devi fare I/O a basso livello (tipo accedere ai settori grezzi di un floppy), la via piu' veloce e' aprire un file con fopen(), e scriverci dentro con fwrite(). Invece con la open, e scritture di piccoli blocchi, ho avuto velocita' inferiori che con la fopen().
Re: Realizzare buffer scrittura [c/c++]
Inviato: dom 19 lug 2009, 12:49
da FireEater
Ah... dimenticavo di dire che sono in ambiente M$.
@spina: non ho mai usato il memory mapped, e poi, considerando che devo fare solo output, non mi sembra che possa apportare migliorie. Comunque non avendolo mai provato non ho proprio idea.
@robbybby: Ok, proverò fopen() ed fwrite() perchè devo scrivere di continuo dei blocchi piccoli.
Altre idee per una bufferizzazione fatta in casa?
FE
Re: Realizzare buffer scrittura [c/c++]
Inviato: dom 19 lug 2009, 18:00
da Mario Vanoni
Uso una funzione mia copyfile(3),
ovviamente nella library privata,
che usa fopen(3), getc(3), putc(3) poi fclose(3).
Viene usata da una utilita` mia cpy(1),
che copia e rinomina un file.
time cpy linux-2.6.30.1.tar.bz2
0m2.079s
per 59416602 bytes
Re: Realizzare buffer scrittura [c/c++]
Inviato: dom 19 lug 2009, 19:43
da FireEater
Mario Vanoni ha scritto:Uso una funzione mia copyfile(3),
ovviamente nella library privata,
che usa fopen(3), getc(3), putc(3) poi fclose(3).
Viene usata da una utilita` mia cpy(1),
che copia e rinomina un file.
time cpy linux-2.6.30.1.tar.bz2
0m2.079s
per 59416602 bytes
Mario,
non mi interessa quanto impiega un ciclo di getc(3), putc(3) a copiare un file. Voglio solo che sia più efficiente.
Ciao
PS: non sto realizzando una "utilità mia"
Re: Realizzare buffer scrittura [c/c++]
Inviato: dom 19 lug 2009, 21:15
da robbybby
FireEater ha scritto:Ah... dimenticavo di dire che sono in ambiente M$.
Allora, come detto, usa fopen e fwrite, e lascia fare al sistema. Non sembra, ma e' molto veloce, perche' comunque bufferizza lui.
Prova, sotto debugger, a scrivere un pezzetto alla votla: vedrai che il flush dei dati avviene quando chiudi il file.
Re: Realizzare buffer scrittura [c/c++]
Inviato: lun 20 lug 2009, 19:54
da Mercyful
Ciao fire_eater,
da quanto ho capito vuoi creare un buffer che ti permetta di fare I/O su file di molti dati molto velocemente. Per quanto le fwrite siano ottimizzate secondo me la tua non è una brutta idea. Ho trovato questo codice che potrebbe fare al caso tuo.
http://www.koders.com/cpp/fidD851DBC7C8 ... s=mdef:md5
Implementa una piccola classe che costruisce una buffer di byte sotto forma di vettore di caratteri.
Per quanto riguarda l'ottimizzazione della scrittura e lettura tieni conto che questo buffer deve essere letto e scritto velocemente infatti quando lo leggerai per scriverlo su file dovrai eseguire una scansione di tutto il vettore. Per questo motivo ti consiglio di memorizzarlo in modo "aligned" usando le direttive appropriate.
Se vuoi altre informazioni riguardo ottimizzazioni ti consiglio questo link, riguarda naturalmente il possibili ottimizzazioni sotto M$, tra cui una parte dedicata proprio a File I/0.
http://msdn.microsoft.com/en-us/library ... S.60).aspx
Ciao!
Re: Realizzare buffer scrittura [c/c++]
Inviato: mar 21 lug 2009, 12:28
da FireEater
@Mercyful: grazie mille per i link, ora mi organizzo per migliorare il mio codice.
@robbybby & spina:
Ho fatto dei test per verificare se il mio semplice algoritmo di bufferizzazione potesse migliorare l'efficienza dei buffer del S.O., questo è il risultato:
La mia WriteBuffer è uguale a quella che ho scritto nel primo post, ma usa fwrite e non ofstream.write.
per i tick uso un lpPerformanceCount.
Codice: Seleziona tutto
1000000 di scritture
Tick per write buffer: 4952851
Tick per fwrite: 10488191
Diciamo che implementarsi un proprio buffer non è da considerarsi una brutta idea eh!? Comunque i dati si commentano da soli...
Ora provo le dritte di mercyful e faccio un nuovo test.
FE

Re: Realizzare buffer scrittura [c/c++]
Inviato: mar 21 lug 2009, 12:32
da targzeta
Mizzeca, se i dati sono attendibili....
Però è un peccato che non sei sotto linux, il memory-mapped I/O dovrebbe essere molto più veloce delle fwrite e si potevano fare dei test anche con quelli.
Emanuele
Re: Realizzare buffer scrittura [c/c++]
Inviato: mar 21 lug 2009, 12:54
da FireEater
Ho notato, effettuando altri test, che in generale la scrittura bufferizzata è più efficiente.
A seconda dei casi la scrittura diretta (fwrite) oscilla fra 12milioni e 6 milioni di tick, invece quella bufferizzata non supera mai i 5 milioni.
Ho modificato l'algoritmo di bufferizzazione eliminando il ciclo for ed usando la funzione memcpy, ho visto un leggero miglioramento.
@spina: appena ho il tempo provo memory-mapped I/O e asynchronous file I/O.