Newsgroup: it.hobby.elettronica.digitale
Titolo: Gestire i buffer

Ciao,
 
spesso capita che si utilizzino delle librerie già pronte, fornite ad 
esempio assieme all'IDE, al compilatore oppure ancora sviluppate da 
terzi. Parlo di C.
 
Questo per dire che metterci mano non è così immediato, per motivi di 
licenza o anche solo per evitare di disallinearsi con le future versioni.
 
Supponiamo di avere un array di interi, es. 1000 byte.
Questo array deve essere trasmesso via TCP ma prima va codificato in un 
certo modo.
 
Dovrò quindi passare il mio array alla funzione di codifica, che mi 
chiede un buffer dove restituirmi i dati, es. 2000 byte.
 
Poi passo quest'ultimo alla funzione di trasmissione TCP, che anche lei 
ha un altro buffer, es. 1500 byte.
 
Morale: per trasmettere 1000 byte ne devo allocare 1000+2000+1500 = 4500!
 
 
Secondo me senza intervenire sulle varie funzioni, non c'è nulla da fare 
perché giustamente ciascuna vuole la propria area di memoria (del resto 
chi le ha scritte non sapeva che avrebbero collaborato assieme...).
 
E' così oppure mi perdo qualche barbatrucco per poter risparmiare un po' 
di RAM?
 
Grazie!
Marco

 di RAM?
...
 
Ne so poco di C ma di solito per certe moli di dati si creano
strutture delle quali si trasmettono i puntatori e non i contenuti tra
funzioni.
Con l'operatore unario "&" otieni l'inditizzo di partenza del vettore
o della variabile in memoria.
 
es:
 
indirizzo = &variabile
 
restituisce l'address in memoria di variabile.
L'operatore complementare è "*" che rende il valore puntato.
 
Piccio.

 L'operatore complementare è "*" che rende il valore puntato.
 
 
Il puntatore fa comunque riferimento a un'area di memoria. Quando passi 
un "array" stai di fatto passando il puntatore al primo elemento (per 
questo occorre passare anche la dimensione dell'array).
 
Ma il punto è: a quale area di memoria stiamo facendo riferimento?
 
Probabilmente la mia domanda era un po' retorica: è ovvio che a meno di 
forti ottimizzazioni se una funzione deve elaborare dei dati 
(modificandoli) avrà un output su un'area diversa da quella di input.
 
Insomma, la migliore (a seconda dei casi, ci sarebbero anche altri 
problemi) soluzione sarebbe quella di avere un unico buffer su cui fare 
tutte le operazioni. Ma questo presuppone che tutte le funzioni 
coinvolte siano pensate per questo tipo di soluzione.
 
Il che è evidentemente impossibile se sviluppate indipendentemente!
 
Marco
 
 

 di RAM?
 
Purtroppo è così, non c'è una soluzione generica.
 
L'unica cosa che mi viene da dire è che, per esempio, lo stack di rete 
potrebbe essere zero-copy, ovvero potrebbe usare il buffer in ingresso 
direttamente per l'invio, senza fare una copia.
 
Questo approccio usa meno memoria, ma ha altri problemi: per esempio il 
buffer passato in ingresso non può essere toccato fintanto che l'invio 
non è terminato (oppure la chiamata alla funzione di invio è bloccante 
fintanto che non termina).
 
Un'altra cosa che puoi fare per ridurre l'occupazione di memoria, visto 
che stai usando TCP, è quella di spezzare il tutto in operazioni con 
buffer più corti, e invece di fare una sola send da 2k, ne fai per 
esempio 10 da 200byte. Al ricevitore arriverà sempre lo stesso flusso di 
dati, magari con un pizzico di latenza in più.
 
Alla fine, come sempre, si tratta di trovare il giusto compromesso.
 
Ciao!

 dati, magari con un pizzico di latenza in più.
 
 
Yes. Faccio già così :)
Anche perché la velocità di trasferimento non è importante.
 
Grazie!
Marco
 

Il 18/12/2012 17:35, Marco Trapanese ha scritto:
 > E' così oppure mi perdo qualche barbatrucco per poter risparmiare un 
 > po' di RAM?
 
Non so quanto siano flessibili le tue funzioni, ma in alcuni casi sono 
riuscito a risparmiare un buffer intermedio allocandolo nello stack.
 
unsigned char data[100];  /* I dati dell'applicazione */
void send_message(void) {
   unsigned char msg[200]; /* Il buffer intermedio sullo stack */
   len = encode_data(data, sizeof data, msg, sizeof msg);
   send(msg, len);
}
 
unsigned char fifoout_buf[200];  /* La FIFO d'uscita */
void send(unsigned char *msg, size_t msg_len)
{
   while(msg_len--) push_out(*msg++);
}
 

 }
 
 
Mumble... non capisco una cosa: come fai a essere sicuro che quando 
viene chiamata send_message c'è spazio a sufficienza nello stack?
Io solitamente i buffer li alloco staticamente (o se preferisci a 
livello globale) così da avere ben chiaro quanto pesano in memoria.
 
Nello stack ci lascio solo le variabili di servizio.
 
Comunque la soluzione che ho adottato è stata quella di mettere mano 
alle funzioni così da rendere possibili delle chiamate iterative 
(esattamente come il discorso del buffer di scrittura TCP, suggerito 
anche da Francesco).
 
Ciao
Marco
 
 

 alle funzioni cosï¿œ da rendere possibili delle chiamate iterative


 stack a disposizione?
 
 
Concordo che i casi particolari si gestiscono di conseguenza e con buon 
senso.
 
 
Ciao!
Marco