Velocità del loop Mega 2560

Si, ho visto il tuo test e anche il mio risultato è pressochè uguale.

Non sono convinto al 100%, quando monti due motori identici 1600cc su un auto che pesa 1000Kg e una che ne pesa 2000Kg non possono dare le stesse prestazioni quando le metti in strada, secondo me abbiamo provato la velocità delle ruote con le 2 auto sollevate da terra.

Comunque mi prenderò una Uno e li voglio provare a pieno carico.

per ora grazie
ciao

lo speed test è chiaramente un buon test ma imho non è veritiero di talune situazioni: non perchè sia fatto male ma perchè è studiato in modo differente e pertanto lascia dei dubbi.

Se il dubbio è: il processore dell'UNO è più lento del processore del Mega la risposta è chiaramente NO... ma probabilmente non c'era neanche bisogno di stare qui a discutere: è banale la cosa, la frequenza è uguale, l'operazione di nop per definizione occupa la cpu in un ciclo di clock... non c'è altro da inventarsi...
In probabilità, ma senza curiosare molto sui manuali atmel, possono esistere delle operazioni assembly che richiedono un ciclo in più o in meno nei due processori ma le differenze, ammesso che ci siano, saranno del tutto secondarie.
Ma allora se il processore è pressochè uguale la uno va come la mega? No: dipende da cosa ha da fare il processore in più rispetto al programma: la mega ha più porte da controllare (ed imho tanto tanto incidono i timer però attendo di fare le prove stasera). Oppure il compilatore fa delle cose "impreviste" nelle due versioni: purtroppo i primi programmi fatti da lestro e da me testati saranno pure "congetture" ma hanno evidenziato che il compilatore fa delle ottimizzazioni "non scontate" e che lo stesso codice su due board differenti porta a risultati nettamente differenti....probabilmente non per colpa dei tempi di esecuzione del codice nostro ma per i tempi di gestione (codice degli interrupt, controllo delle porte... non so)

qsecofr:
In probabilità, ma senza curiosare molto sui manuali atmel, possono esistere delle operazioni assembly che richiedono un ciclo in più o in meno nei due processori ma le differenze, ammesso che ci siano, saranno del tutto secondarie.

Premesso che il tallone d'Achille degli AVR è proprio il fatto che molte istruzioni richiedono 2-3 cicli macchina, il che abbassa non poco la velocità media rispetto ai 16 Mips teorici @16 MHz, però il core del 2560 è praticamente lo stesso del 328 con 4 istruzioni assembly in più, tutte le altre sono praticamente identiche come uso e cicli macchina.
Lo stesso speed test evidenzia bene la cosa non tanto sulla nop quanto su funzioni complesse come la itoa() che sono pesanti da eseguire e richiedono molti cicli macchina, il tempo di esecuzione è lo stesso.

Ma allora se il processore è pressochè uguale la uno va come la mega? No: dipende da cosa ha da fare il processore in più rispetto al programma: la mega ha più porte da controllare (ed imho tanto tanto incidono i timer però attendo di fare le prove stasera).

Infatti ho ipotizzato la presenza di ulteriori processi di sistema, ovvero gestione di interrupt e funzioni di base, non presenti sulla UNO che pesano sul ciclo della 2560.
Intanto un dato certo, ho fatto il test dello sketch vuoto, lo stesso che ho usato sulla UNO, sulla 2560 ed ecco la prima sorpresa, la velocità è "solo" 998 Kz, un calo sensibile però non è certo questo che incide sulla velocità generale.
Posso pure confermare il dato rilevato da Pablos con lo sketch di Tuxduino, pure sula mia 2560 gira a circa metà velocità, e questo si che è preoccupante perché da un punto di vista teorico non dovrebbe essere possibile.
Per capirci qualcosa tocca analizzare l'assembly del programma compilato per la UNO e quello per la 2560, per i test ho utilizzato l'IDE 1.0.3 con il compilatore di serie.

astrobeed:
Posso pure confermare il dato rilevato da Pablos con lo sketch di Tuxduino, pure sula mia 2560 gira a circa metà velocità, e questo si che è preoccupante perché da un punto di vista teorico non dovrebbe essere possibile.
Per capirci qualcosa tocca analizzare l'assembly del programma compilato per la UNO e quello per la 2560, per i test ho utilizzato l'IDE 1.0.3 con il compilatore di serie.

questa sera spero di trovare il tempo per fare due prove: vediamo qualcosa di assembler... ma non sarà facile: il cliclo di "cont++" fatto sul programma lestro che ho provato ieri sera veniva ottimizzato... o meglio veniva proprio tolto tant'è che 65000 incrementi impiegavano 0 microsecondi mentre sommando una variabile (contenuto 1) il compilatore non poteva ottimizzare e segnava diversi microsecondi... come avrebbe dovuto essere.
L'altra prova è di staccare gli interrupt che non sono essenziali al codice o meglio staccare tutti i timer tranne lo 0.
Inoltre non so cosa succeda sugli i/o... ossia quando alzo un pin di arduino lui occupa cicli di clock per spostare questo dato sul PORTx oppure è una cosa hardware che funziona indipendentemente?... qui ho un dubbio.
Una cosa comunque per me è abbastanza chiara: c'è un overhead più grande sul mega ma il fatto che noi misuriamo tempi doppi non significa che l'uno sia il doppio più veloce... in pratica quando misuriamo con i programmi di tuxduino o lestro i tempi misuriamo un (imho) 20% di nostro codice ed un 80% di overhead: però i ns programmi sono ben più seri di un ciclo vuoto: in questi casi diluiamo questo overhead e quindi le differenze tra mega e uno si assottigliano paurosamente.... non so se mi sono spegazzato...

al contrario, l'overhead del mega lo senti di più più usi le sue periferiche: la digitalWrite è molto più lenta dell'uso dei registri per via dei check. Ora, su una mega hai più check da fare (o meglio, più registri su cui cercare quello che ti serve), quindi più overhead. un loop vuoto, con interrupt al minimo, dovrebbe dare l'identico risultato, salvo black magic del compilatore

astrobeed:
Intanto un dato certo, ho fatto il test dello sketch vuoto, lo stesso che ho usato sulla UNO, sulla 2560 ed ecco la prima sorpresa, la velocità è "solo" 998 Kz, un calo sensibile però non è certo questo che incide sulla velocità generale.
Posso pure confermare il dato rilevato da Pablos con lo sketch di Tuxduino, pure sula mia 2560 gira a circa metà velocità, e questo si che è preoccupante perché da un punto di vista teorico non dovrebbe essere possibile.
Per capirci qualcosa tocca analizzare l'assembly del programma compilato per la UNO e quello per la 2560, per i test ho utilizzato l'IDE 1.0.3 con il compilatore di serie.

Fiuuu ... mi era sorto il dubbio di aver generato 4 pag di congetture non avendo strumenti adatti :fearful:

lesto:
al contrario, l'overhead del mega lo senti di più più usi le sue periferiche: la digitalWrite è molto più lenta dell'uso dei registri per via dei check. Ora, su una mega hai più check da fare (o meglio, più registri su cui cercare quello che ti serve), quindi più overhead. un loop vuoto, con interrupt al minimo, dovrebbe dare l'identico risultato, salvo black magic del compilatore

si hai ragione: per l'operazione di i/o puro si (digital read/write)... però in un programma ci sono anche chiamate a funzioni, calcoli, stringhe... quando non ci infiliamo addirittura dei delay. In questo senso penso che nel 99% dei casi di questo overhead aggiuntivo del mega non ce ne freghi assolutamente un piffero.... poi sicuramente per la legge di murphy quell'1% è l'1% che ti tiene sveglio la notte e non ti permette di terminare il programma XD
Mi piacerebbe sapere per esempio ripetendo allo sfinimento un lcd.print (che è un'operazione pesantina proprio sull'i/o) in quanto consiste la differenza tra uno e mega.... il protocollo hitaci prevede che il display abbassi qualcosa per capire se ha ricevuto il dato?

Usa il mio esempio (quello con testThis) e nella funzione di test al posto della Serial.print metti una lcd.print("HALLO WORLD") o simile.

credo che in quei casi sei limitato dalla velocità del protocollo.

la cosa migliore IHMO è quella che ha fatto astro con l'oscilloscopio.

anche le operazioni come millis() mi aspetto che siano più lente se la mega ha più timer, e forse anche la gestione delle varie Seriali, anche se attutita dal fatto che molte cose sono HW.

quello che voglio capire è se invece a puro operazioni CPU (somme e moltiplicazioni) ci sono differenze tra la UNO e la MEGA, a causa di aventuali interrupt "di base" differenti, o differenti ottimizzazioni del compilatore (ma quì non so se la MEGA è un target differente per il compilatore...), insomma cose nascoste al'utente anche più smaliziato. un buon test da questo punto di vista potrebbe essere lo skecth che scrissi per testare i tempi del GPS, usa pesanti operazioni matematiche (sin, cos, tan, atan, etc...)

link al codice: arduinoSketch/GPS_test.ino at master · lestofante/arduinoSketch · GitHub

Ho scoperto dove è il collo di bottiglia, è la gestione della seriale, se si elimina la serial.begin il ciclo del conteggio viaggia a oltre 500 kHz, se si attiva la serial.begin la velocità crolla a meno di 128 kHz, il valore è inteso come ciclo costituito dalla cnt++ e la if, ovviamente non tiene conto della fine con relativo invio sulla seriale.

unsigned int cnt = 0;
const unsigned int CNT_MAX = 65000;

unsigned long prevMillis = 0;

Sketch usato per il test, commentando/decommentando opportunamente le varie PORTB = 0xxx tramite il DSO misuro la durata dell'impulso positivo che a sua volta rappresenta il tempo di esecuzione di una singola porzione del programma.
void setup() {
    Serial.begin(115200);
    pinMode (13, OUTPUT);
}


void loop() {
    PORTB=0xff;
    cnt++;
    //PORTB=0x00;

    //PORTB=0xff;

    if (cnt > CNT_MAX)  {
        //Serial.println(millis() - prevMillis);
        prevMillis = millis();
        cnt = 0;
    }
    PORTB=0x00;
}

Come confronto di valori tra UNO e MEGA2560 ho questi risultati riferiti alla singola riga CNT++ e la IF

UNO MEGA2560

cnt++ 688.5 ns 688.5 ns

if 313 ns 313 ns

Mi pare ovvio che i tempi di esecuzione delle singole righe sono identici sia sulla UNO che sulla MEGA 2560, la differenza enorme è sul tempo del ciclo completo della loop con seriale attiva,sulla UNO dura 3.69 us e sulla MEGA2560 dura 7.75 us, disattivando la seriale sulla MEGA2560 il tempo del ciclo crolla a solo 1.95 us.
Adesso tocca capire perché attivare la seriale, e solo la prima, porta questo rallentamento sull'esecuzione del ciclo.

Ricorda che il main.c di Arduino è così:

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

quindi se c'è la seriale controlla il serialevent; a parte controllare i vari interrupt.

PaoloP:
quindi se c'è la seriale controlla il serialevent.

Questo lo so benissimo, quello che non quadra è perché ci deve mettere oltre 3us in più rispetto alla UNO per fare la stessa cosa, di UART inizializzata ce n'è solo una, le altre tre sono inattive, posso capire che ci vuole qualche ciclo macchina in più per verificare quali UART sono attive, ma qui parliamo di oltre 50 cicli macchina in più.
Tocca controllare il core per capire dove sta il "problema" e vedere se è possibile porvi un rimedio.

ahahh si inizia a fare una domanda "innocua" e si finisce a debuggare il core... sarà felice Pablos :grin:

lesto:
ahahh si inizia a fare una domanda "innocua" e si finisce a debuggare il core... sarà felice Pablos :grin:

Diciamo che adesso è scattata la molla della curiosità, in realtà non credo che questo sia un reale problema, stiamo usando piccoli sketch mirati per esaltare il "difetto", in una normale applicazione qualche us in più sull'esecuzione della loop hanno impatto zero sul totale del programma.
Però potrebbe essere che si annidano altre sorprese nascoste, quindi indagare male non fa :grin:

lesto:
ahahh si inizia a fare una domanda "innocua" e si finisce a debuggare il core... sarà felice Pablos :grin:

:smiley:

ahahh si inizia a fare una domanda "innocua" e si finisce a debuggare il core... sarà felice Pablos smiley-mr-green

Ahahah ... Sisi sono felice ora che si è scoperta una causa :grin:, grazie ad uno strumento che ha permesso di farlo senza debug seriale e grazie ad Astro, in fondo io la serial una volta finito il lavoro la levo, mi serve solo per i debug.
Purtroppo sarà meno felice quello che nel suo programma ne avrà bisogno penalizzando il rendimento.

ciao

A proposito dell'influenza della seriale sulle prestazioni, vorrei sottolineare i risultati che ho ottenuto nel mio sketch di prova: tra baud rate di 9600 e 115200 c'è una differenza significativa.
Va ricordato però che nelle ultime versioni di Arduino anche la trasmissione seriale è fatta via interrupt, e diventa bloccante solo nel momento in cui il buffer di trasmissione è pieno, quindi in realtà se si trasmettono "pochi" (1) byte alla volta, l'impatto complessivo dovrebbe essere molto limitato.

(1) ora vado a vedere la dimensione del buffer di trasmissione.

PS: e adiamo con un altro sketch di test... :slight_smile:

In HardwareSerial.cpp abbiamo:

#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else
#define SERIAL_BUFFER_SIZE 64
#endif

quindi sulla UNO / 2009, con 2K di RAM, i buffer di ricezione e invio della seriale hardware hanno dimensione 64 byte.

Quello che non ho capito se Astro dice che il serial.begin crea un rallentamento, perchè questo non fa cambiare nulla??

unsigned long prevMillis=0;
 const long CNT_MAX=100000;
 unsigned long cnt=0;
 unsigned long memo[10];
 byte count_memo_pos=0;
 
void setup() {
delay(2000);
//Serial.begin(9600); //<<< se lo commento o decommento il risultato non cambia 
prevMillis = millis();
}
void loop(){
  
    cnt++;
    if (cnt > CNT_MAX){     
        memo[count_memo_pos]= millis() - prevMillis;
        count_memo_pos++;
        cnt = 0;
        if(count_memo_pos==10) read_memo();
        prevMillis = millis();
    }
}

void read_memo(){
  Serial.begin(9600);  
  
  for (byte i = 0; i < 10; i++){
       Serial.println((String)i + " "+ (String)memo[i]);
  }        
}

qui il begin lo faccio dopo aver salvato 10 dati e quando li vado a leggere.
Bho mistero ... sembra che il programma in qualche modo lo veda

Da questi dati che ha prelevato Astro con precisione

con seriale attiva sulla MEGA2560 dura 7.75 us, disattivando la seriale sulla MEGA2560 il tempo del ciclo crolla a solo 1.95 us.

tra 7.75 e 1.95 c'e' un rapporto di valore 4, stai a vedere che una volta scritto serial.begin il sistema mi va a controllare tutte e 4 le seriali.
Posso aver detto una fesseria ma la coincidenza è strana.