Realizzare buffer scrittura [c/c++]

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Realizzare buffer scrittura [c/c++]

Messaggio 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

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6631
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Mario Vanoni
Iper Master
Iper Master
Messaggi: 3174
Iscritto il: lun 3 set 2007, 21:20
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey
Località: Cuasso al Monte (VA)

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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
Ultima modifica di Mario Vanoni il sab 18 lug 2009, 19:34, modificato 1 volta in totale.

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6631
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Realizzare buffer scrittura [c/c++]

Messaggio da targzeta »

:D

Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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?

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6631
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Realizzare buffer scrittura [c/c++]

Messaggio da targzeta »

Hai già scartato il memory-mapperd I/O (mmap(2)) ?

Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
robbybby
Linux 4.x
Linux 4.x
Messaggi: 1223
Iscritto il: sab 16 dic 2006, 10:48
Slackware: 13.1 / 64 bit
Kernel: 3.3.x
Desktop: KDE 4.4.5
Località: Fra Trantor e Terminus

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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().

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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

Mario Vanoni
Iper Master
Iper Master
Messaggi: 3174
Iscritto il: lun 3 set 2007, 21:20
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey
Località: Cuasso al Monte (VA)

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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"

Avatar utente
robbybby
Linux 4.x
Linux 4.x
Messaggi: 1223
Iscritto il: sab 16 dic 2006, 10:48
Slackware: 13.1 / 64 bit
Kernel: 3.3.x
Desktop: KDE 4.4.5
Località: Fra Trantor e Terminus

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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.

Avatar utente
Mercyful
Linux 1.x
Linux 1.x
Messaggi: 196
Iscritto il: ven 25 lug 2008, 18:20
Nome Cognome: Ilario Pittau
Slackware: 13.0
Kernel: 2.6.29.6-generic
Desktop: xfce 4.6
Località: Torino

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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!

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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 \:D/

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6631
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Realizzare buffer scrittura [c/c++]

Messaggio 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.

Rispondi