Repository 32bit  Forum
Repository 64bit  Wiki

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.

Realizzare buffer scrittura [c/c++]

Messaggioda FireEater » sab lug 18, 2009 15:39

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
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

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

Messaggioda targzeta » sab lug 18, 2009 16:14

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
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6189
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

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

Messaggioda Mario Vanoni » sab lug 18, 2009 18:10

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 lug 18, 2009 18:34, modificato 1 volta in totale.
Mario Vanoni
Iper Master
Iper Master
 
Messaggi: 3174
Iscritto il: lun set 03, 2007 20:20
Località: Cuasso al Monte (VA)
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey

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

Messaggioda targzeta » sab lug 18, 2009 18:13

:D

Emanuele
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6189
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

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

Messaggioda FireEater » sab lug 18, 2009 19:19

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
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

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

Messaggioda targzeta » sab lug 18, 2009 19:53

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

Emanuele
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6189
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

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

Messaggioda robbybby » dom lug 19, 2009 10:56

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
robbybby
Linux 3.x
Linux 3.x
 
Messaggi: 1177
Iscritto il: sab dic 16, 2006 10:48
Località: Fra Trantor e Terminus
Slackware: 13.1 / 64 bit
Kernel: 3.3.x
Desktop: KDE 4.4.5

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

Messaggioda FireEater » dom lug 19, 2009 11:49

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
Avatar utente
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

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

Messaggioda Mario Vanoni » dom lug 19, 2009 17:00

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 Vanoni
Iper Master
Iper Master
 
Messaggi: 3174
Iscritto il: lun set 03, 2007 20:20
Località: Cuasso al Monte (VA)
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey

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

Messaggioda FireEater » dom lug 19, 2009 18:43

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
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

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

Messaggioda robbybby » dom lug 19, 2009 20:15

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
robbybby
Linux 3.x
Linux 3.x
 
Messaggi: 1177
Iscritto il: sab dic 16, 2006 10:48
Località: Fra Trantor e Terminus
Slackware: 13.1 / 64 bit
Kernel: 3.3.x
Desktop: KDE 4.4.5

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

Messaggioda Mercyful » lun lug 20, 2009 18:54

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/fidD851DBC7C8DBBDFFDE85A1DA6C1BF3FABB9EC5CD.aspx?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/aa260969(VS.60).aspx
Ciao!
Avatar utente
Mercyful
Linux 2.0
Linux 2.0
 
Messaggi: 196
Iscritto il: ven lug 25, 2008 17:20
Località: Torino
Nome Cognome: Ilario Pittau
Slackware: 13.0
Kernel: 2.6.29.6-generic
Desktop: xfce 4.6

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

Messaggioda FireEater » mar lug 21, 2009 11:28

@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
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

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

Messaggioda targzeta » mar lug 21, 2009 11:32

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
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6189
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

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

Messaggioda FireEater » mar lug 21, 2009 11:54

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.
Avatar utente
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

Prossimo

Torna a Programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti