Go Down

Topic: Verificare SRAM utilizzata (Read 4130 times) previous topic - next topic

pablos

#30
Nov 22, 2012, 10:43 am Last Edit: Nov 22, 2012, 10:47 am by pablos Reason: 1
bhe direi che non è poco considerato che sono solo 2 misere var

scusa quei numeri indicano lo spazio rimasto?
sbaglio o è meglio dichiararle globali?


grazie
no comment

leo72

No, indicano l'occupazione (vedi la scritta xx% full tra parentesi).
Nel caso in oggetto meglio locali che globali.

astrobeed


bhe direi che non è poco considerato che sono solo 2 misere var


Sono due variabili che occupano 12 byte visto che la seconda è una stringa di 11 caratteri, infatti la differenza tra i due metodi è 9 byte ed è dovuta all'uso di puntatori, che vanno creati e usano memoria, per indirizzare i dati locali che si trovano nel heap e non occupano ulteriore spazio.
Da notare che se si richiamano molte funzioni annidate, ciascuna con variabili locali, c'è il rischio di andare in overflow heap con il conseguente possibile crash del programma oltre alla perdita di dati.
Su mcu di livello superiore esistono appositi interrupt per gestire queste condizioni di errore run time, sugli AVR non è previsto nulla di simile.

leo72


Da notare che se si richiamano molte funzioni annidate, ciascuna con variabili locali, c'è il rischio di andare in overflow heap con il conseguente possibile crash del programma oltre alla perdita di dati.

E' il rischio che si corre scrivendo funzioni ricorsive, che cioè richiamano sé stesse: ad ogni chiamata, si gonfia l'heap  :smiley-sweat:
In un computer con 4 GB di RAM non te ne accorgi, ma qui sì.

astrobeed


E' il rischio che si corre scrivendo funzioni ricorsive, che cioè richiamano sé stesse: ad ogni chiamata, si gonfia l'heap  :smiley-sweat:
In un computer con 4 GB di RAM non te ne accorgi, ma qui sì.


Vero, però mi viene il dubbio che il gcc-avr, per le mcu 8 bit, non permette la ricorsività delle funzioni proprio per via delle limitate dimensioni dello stack/heap, non sono sicuro al 100% mi ricordo di averlo letto da qualche parte e non ho mai verificato se è realmente così.
Se non hai info sicure in merito più tardi provo in pratica con uno sketch con funzione ricorsiva sia per vedere se è realmente possibile, sia per testare il reale limite prima del heap overflow.

leo72

Non ho info in merito.
Più tardi provo anch'io.

Nel frattempo segnale questa OTTIMA pagina:
http://www.nongnu.org/avr-libc/user-manual/malloc.html

Si vede bene come viene usata la memoria dal compilatore.
PS:
la memoria estesa può essere usata solo su alcune MCU Atmel (vedi Atmega128 e Atmega2560). NON su Atmega328.

astrobeed


Nel frattempo segnale questa OTTIMA pagina:
http://www.nongnu.org/avr-libc/user-manual/malloc.html


Ottima pagina.
Giusto per completezza dell'informazione è da tenere presente che il modo di utilizzare la memoria non dipende completamente dal linguaggio, che comunque pone dei paletti, ma dal compilatore e le scelte fatte da chi lo ha realizzato.
Ovvero il modo di utilizzo della memoria, sia come aree che come allocazione, non è detto che sia identico tra compilatori C diversi o tra diverse release dello stesso compilatore rivolte a processori molto diversi come core/risorse.


leo72

#37
Nov 22, 2012, 11:34 am Last Edit: Nov 22, 2012, 11:45 am by leo72 Reason: 1
Sì, certo. Lì si parla del compilatore Gnu Avr-gcc che è quello usato dall'Arduino e da Atmel. Sicuramente un altro compilatore ottimizzerà in base a suoi metodi.

PS:
leggendo della ricorsione, mi par di capire che sia sconsigliata da tutti ma solo perché consuma un sacco di risorse, non tanto perché non sia implementata.
Intanto ho provato un piccolo algoritmo per calcolare la sequenza di Fibonacci in modo ricorsivo ed è andato in botto  :smiley-sweat:
Algoritmo scritto male  :smiley-roll-blue:
Questo funziona.
Code: [Select]
void setup() {
    Serial.begin(19200);
    delay(2000);
    Serial.println("Sequenza di Fibonacci");
    Serial.println(fib(20));
    Serial.println("Terminata");
}

void loop() {

}

unsigned long fib(unsigned int n)
{
    Serial.println("0");
    return n == 0 ? 0 : fib2(n, 0, 1);
}

unsigned long fib2(unsigned int n, unsigned long p0, unsigned long p1)
{
  Serial.println(p1, DEC);
  return n == 1 ? p1 : fib2(n - 1, p1, p0 + p1);
}

astrobeed


Intanto ho provato un piccolo algoritmo per calcolare la sequenza di Fibonacci in modo ricorsivo ed è andato in botto  :smiley-sweat:


Se l'ha compilato vuol dire che è supportata, che poi vada in crash è normale :)

leo72



Intanto ho provato un piccolo algoritmo per calcolare la sequenza di Fibonacci in modo ricorsivo ed è andato in botto  :smiley-sweat:


Se l'ha compilato vuol dire che è supportata, che poi vada in crash è normale :)


Era scritto male a livello di codice.
Quello che ho messo l'ho scritto con una versione ottimizzata che ho trovato in rete e che non va in botto neanche con numeri elevati. Mi suona però strano, non è crashato neanche con 100000 numeri  ]:D

astrobeed


Quello che ho messo l'ho scritto con una versione ottimizzata che ho trovato in rete e che non va in botto neanche con numeri elevati. Mi suona però strano, non è crashato neanche con 100000 numeri  ]:D


Dipende da come usi la memoria, se ad ogni iterazione vengono aggiunti dati alla fine l'heap si riempie e va in overflow, se viene solo modificato il contenuto di una, o più, variabile/i non c'è problema, da notare che lo stack non viene incrementato ad ogni iterazione pertanto non va in overflow.
Intanto abbiamo accertato che su avr-gcc la ricorsività è permessa, sicuramente da usare con discernimento e consci delle complicazioni a cui si va incontro, oltretutto ha senso usarla solo per problemi che sono ricorsivi per loro natura, come il calcolo del fattoriale, altrimenti è meglio il classico modo tramite ciclo condizionale.

astrobeed

Una nota aggiuntiva riguardo lo stack e la ricorsione, in realtà viene sempre incrementato ad ogni iterazione ricorsiva, però viene automaticamente decrementato alla fine della stessa, c'è da dire che non vale per tutti i compilatori, dipende dal livello di ottimizzazione e da quanto sono "intelligenti", quindi è anche possibile che si verifichi un errore di stack overflow dopo tot iterazioni.

leo72


Intanto abbiamo accertato che su avr-gcc la ricorsività è permessa, sicuramente da usare con discernimento e consci delle complicazioni a cui si va incontro, oltretutto ha senso usarla solo per problemi che sono ricorsivi per loro natura, come il calcolo del fattoriale, altrimenti è meglio il classico modo tramite ciclo condizionale.

E' vero che la ricorsione rende alle volte più semplice la strutturazione del codice ma un algoritmo iterativo è generalmente più rapido per cui alla fine, secondo me, conviene usare più quest'ultima tecnica che la prima.

qsecofr



Dipende da come usi la memoria, se ad ogni iterazione vengono aggiunti dati alla fine l'heap si riempie e va in overflow, se viene solo modificato il contenuto di una, o più, variabile/i non c'è problema, da notare che lo stack non viene incrementato ad ogni iterazione pertanto non va in overflow.



ma questo come avviente? ogni volta che una funzione richiama se stessa deve fare una call mettendo nello stack quantomeno il punto di ritorno della procedura...mi sbaglio?
Boo non mi capisco... comunque penso che per provare a risolvere il problema si possa provare a dichiarare globale un puntatore ad uno o due array e in setup() procedere con il malloc... qualcosa dovrebbe andare meglio anche perchè qua non abbiamo 2k ma 8... in pratica anneghiamo in un mare  :smiley-roll: di ram che non usiamo
... poi domanda... perchè questo non mi crasha il leonardo che ha solo 2,5k di ram e i led continuano a lampeggiare? ...dove sto scrivendo?
Code: [Select]
/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.

  This example code is in the public domain.
*/

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
char prova1[1000];

char *prova2;
int led = 13;

// the setup routine runs once when you press reset:
void setup() {               
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
 
  prova2 = (char *) malloc(1000 * sizeof(char));

 
}

// the loop routine runs over and over again forever:
void loop() {
  int i;
  for (i = 0; i <1000; i++)
  {  prova1[i]=0;
   
    }
for (i = 0; i <1000; i++)
  {  prova2[i]=0;
   
    }
   
   
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

leo72


qua non abbiamo 2k ma 8... in pratica anneghiamo in un mare  :smiley-roll: di ram che non usiamo

Guarda che gli Atmega328 hanno solo 2 kB di RAM, l'ho scritto diverse volte.

Quote

... poi domanda... perchè questo non mi crasha il leonardo che ha solo 2,5k di ram e i led continuano a lampeggiare? ...dove sto scrivendo?

Nella RAM. Proprio perché hai 2,5 kB di RAM, lo sketch riesce a "sopravvivere" con quel mezzo K in più.
Caricando questo sketch per controllare la memoria:
http://www.controllerprojects.com/2011/05/23/determining-sram-usage-on-arduino/
viene fuori che ci sono 363 byte ancora liberi.

Lo stesso sketch, compilato e caricato sulla mia scheda UNO, fa crashare il micro. Qui, infatti ci sono solo 2 kB di RAM.

Go Up