Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Accorgimenti per scrivere codice in modo efficiente

Raccolta di codici sorgenti

Moderatore: Foto UtentePaolino

1
voti

[1] Accorgimenti per scrivere codice in modo efficiente

Messaggioda Foto Utentelemure64 » 2 mag 2021, 12:13

Ciao Forum,

Vorrei fare una specie di punto della situazione delle mie competenze, che non sono elevate dato che programmo per hobby, sono un dilettante e come tale relativamente isolato dal contatto con il "fare" in squadre di persone più esperte (per non parlare di come trovare letteratura adatta se non spulciando in rete). Soffro inoltre di una serie di imprinting acquisiti all'epoca delle CPU 8088 con compilatori il cui livello di ottimizzazione non era quello di oggi, le abitudini erano diverse e così via. La mia enorme resistenza a cambiare abitudini ha fatto il resto del pasticcio :D

Per dare un'idea del tipo di cose che vorrei sapere prendo spunto dal progettino su Arduino di cui ho parlato altrove.

1) Sono abituato all'idea che passare variabili a una funzione implica copiarle sullo stack e che questo è più lento che usare variabili globali. Per questo motivo con Arduino (sperando di imparare a usare anche dei micro) ho la tendenza a creare variabili globali sia per il passaggio di argomenti sia per esempio per gli indici nei loop, così evito anche l'allocazione delle variabili locali. Beninteso sono coscientissimo dei pericoli di questo approccio (perché ovviamente tendo a riutilizzare le variabili di quel genere e posso sempre dimenticare di aver chiamato in un ciclo "for" una funzione che le usa a sua volta, disastro garantito) e quando scrivo cose che devono girare su PC e la velocità non è un problema non mi faccio alcuno scrupolo a privilegiare modularità e chiarezza. Ma su un micro è diverso, o almeno credo sia diverso. Almeno per le funzioni più critiche tendo a fare così. Vorrei avere un criterio per capire quando è il caso e quando no, possibilmente evitando strumenti di profilazione; queste sono cose che vengono dopo e non sostituiscono un approccio intelligente.

2) Altro ordine di problemi è che non so cosa fa il compilatore e mi spiego tramite un altro problema che ho trovato. Vorrei fermare l'esecuzione per periodi molto brevi inferiori al ms e non volendo contare sul timer interno, ho creato una funzione che si limita a incrementare una variabile per un certo numero di cicli, da tarare poi in fase di verifica. Ma mi è preso il sospetto che il compilatore si accorga che quella variabile incrementata (ovviamente globale, anche per tentare di ingannarlo rispetto al problema di cui sto parlando) non fa niente, non è usata da niente, possa accorgersene e saltare a pie' pari la compilazione di una funzione che non fa nulla. Per quanto ne so, nell'ambito delle variabili locali a una funzione se ne accorge e non compila le parti inutili, ma non è sempre quello che si vuole :D

3) Tipi. Altro dilemma tipico che incontro sempre è che molto spesso ho valori piccoli che stanno benissimo in un "uint8_t", ma altrettanto spesso sono limiti superiori nei cicli "for". Per quanto ne so i contatori di GCC sono sempre tipo int o long e nel caso di cui sto dicendo il compilatore è costretto a creare una o due variabili temporanee nascoste convertendo tutto in intero o nel più piccolo tipo che possa usare per i contatori. Inutile dire che vorrei sapere se è davvero così, cosa accade e come regolarmi per bilanciare velocità e spazio.

Sono solo esempi, non chiedo la risposta ai problemi specifici anche se qualsiasi osservazione generale che da essi possa nascere è ovviamente benvenutissima. Li ho esposti solo per permettere di tarare possibili risposte. Chiedo se c'è un po' di materiale e letteratura in cui questi problemi vengano trattati e in cui siano codificate una serie di buone regole per scrivere bene senza fare acrobazie con costrutti troppo dipendenti dall'hardware, dato che non vorrei avvicinarmi troppo al silicio se così posso dire.

Cosa posso leggere di utile? Grazie moltissime per qualsiasi suggerimento e lettura consigliata.
Avatar utente
Foto Utentelemure64
675 3 6
Stabilizzato
Stabilizzato
 
Messaggi: 382
Iscritto il: 23 giu 2020, 12:26

2
voti

[2] Re: Accorgimenti per scrivere codice in modo efficiente

Messaggioda Foto UtenteGioArca67 » 2 mag 2021, 17:29

1) non vedo particolari problemi a parte quanto già scritto

2)
delayMicroseconds() ?
volatile xxxx_t zzz; zzz viene messa subito in memoria e non subisce ottimizzazioni
asm volatile("" : "+g" (i) : :); dentro un loop o __asm__ volatile... a seconda se usi -ansi

3) lo standard C C++ prevede la promozione a int di interi di dimensione inferiore a int per poi eseguire le operazioni matematiche, consente però anche al compilatore di ottimizzare come vuole e ricorda che non usi GCC o G++ ma avr-gcc che è specifico per quelle MCU, e che dovrebbe ottimizzare l'uso dei registri e delle operazioni elementari sulla dimensione di base dei registri (8 bit per atmega328) quindi avr-gcc dovrebbe accorgersi che non serve usare 2 registri
e quindi compilare i++ con

inc r24
ovvero adi r24,0x01

ed in vari casi l'ottimizzazione funziona come anche riportato in vari forum

O_/
Avatar utente
Foto UtenteGioArca67
287 2 5
Frequentatore
Frequentatore
 
Messaggi: 275
Iscritto il: 12 mar 2021, 9:36

3
voti

[3] Re: Accorgimenti per scrivere codice in modo efficiente

Messaggioda Foto Utenteluxinterior » 2 mag 2021, 18:07

1) Potresti dichiarare static la variabile dentro la funzione.In questo modo finisce nel data segment e non sullo stack e mantiene il valore assegnato.
Tutto sommato il passaggio di variabili sullo stack non è che porti via chissà che tempo se vuoi ottimizzare puoi usare un puntatore: una sola variabile con cui accedere a tutto quello che vuoi.

2) Mio parere: in un sistema embedded mai e poi mai arrestare l'esecuzione anche per pochi us con dei cicli anche perché se ti cambiano la frequenza del clock devi ritarare tutti i cilci. Se non hai un sistema operativo ti conviene usare la programmazione a stati il processo in attesa abbandona l'esecuzione e rientra periodicamente per controllare la fine del periodo di attesa.

3) Secondo me non puoi prescindere dalle dimensioni dei registri del micro In questo caso devi necessariamente interessarti all'HW. Non conosco Arudino ma se iil micro è 8bit la variabile uint8_t sarebbe l'ideale. Comunque sono cose a cui spesso pensano i compilatori che ottimizzano al meglio l'uso dei registri per gestire la variabile.
Avatar utente
Foto Utenteluxinterior
3.127 2 4 8
Expert EY
Expert EY
 
Messaggi: 1834
Iscritto il: 6 gen 2016, 17:48

1
voti

[4] Re: Accorgimenti per scrivere codice in modo efficiente

Messaggioda Foto UtenteGioArca67 » 2 mag 2021, 20:05

Se non hai SO non hai processi e thread.
Avatar utente
Foto UtenteGioArca67
287 2 5
Frequentatore
Frequentatore
 
Messaggi: 275
Iscritto il: 12 mar 2021, 9:36

2
voti

[5] Re: Accorgimenti per scrivere codice in modo efficiente

Messaggioda Foto UtentedrGremi » 2 mag 2021, 21:51

GioArca67 ha scritto:Se non hai SO non hai processi e thread.

Per sistemi monocore e molto "scarsi" come arduino puoi usare i protothread, mentre in chip nuovi come l'STM32H745ZIT6 sono veramente multicore. Puoi avere processi e thread anche senza sistema operativo.

Comunque nell'ottica di una libreria bisogna decidere il rapporto tra ottimizzazione e manutenibilità. Non esagererei con le variabili globali. Personalmente (ma poi ognuno dirà la sua) se non serve ottimizzare non si deve ottimizzare, quello si fa solo se le performance non sono adeguate. Inoltre (ovviamente dipende dal caso) a volte è preferibile comunque non ottimizzare troppo il codice e o ottimizzare il compilatore, oppure fare un upgrade del microcontrollore. Anche perché i costi di progettazione spesso sono i maggiori, quindi accorciare i tempi di sviluppo è un grossissimo vantaggio.

lemure64 ha scritto:ho la tendenza a creare variabili globali sia per il passaggio di argomenti sia per esempio per gli indici nei loop

Sinceramente non lo farei. Per gli indici nei loop proprio no, mentre per il resto o usi i puntatori (che magari dichiari come constant). Inoltre prediligerei una programmazione orientata agli oggetti.

lemure64 ha scritto:ho creato una funzione che si limita a incrementare una variabile per un certo numero di cicli, da tarare poi in fase di verifica

Questo anche non lo farei proprio, il risultato è non deterministico e soprattutto il codice non va tarato. Deve funzionare.
Come già detto da GioArca delayMicroseconds è una valida soluzione.

lemure64 ha scritto:Chiedo se c'è un po' di materiale e letteratura in cui questi problemi vengano trattati e in cui siano codificate una serie di buone regole per scrivere bene senza fare acrobazie con costrutti troppo dipendenti dall'hardware, dato che non vorrei avvicinarmi troppo al silicio se così posso dire

Vedo se riesco a trovare qualche guida carina (può essermi utile anche da spammare altrove). Comunque possiamo iniziare da
  • non usare variabili globali, soprattutto col C++ se ne ha sempre meno bisogno;
  • se possibile usare librerie standard (non reinventare la ruota);
  • programmazione orientata agli oggetti;
  • non creare classi/funzioni "dio" in modo da rendere il codice riutilizzabile;
  • non pensare subito all'ottimizzazione;
  • scegliere uno stile di codice e seguirlo pedissequamente (magari anche usando una funzione dell'editor per auto indentare soprattutto se si lavora in più persone).

Comunque oltre tutte queste "pippe" se funziona devi essere soddisfatto, poi in programmazione di micro si fanno un sacco di "porcate" che a volte sono quasi necessarie e in un altro contesto non sarebbero accettabili.

lemure64 ha scritto:vorrei sapere prendo spunto dal progettino su Arduino di cui ho parlato altrove

Potresti iniziare pubblicandolo, le ottimizzazioni le farai con calma (magari così a tempo perso gli si da una occhiata e può saltare fuori qualche suggerimento da lì). Non penso nessuno ti criticherà per quello che scrivi se non in maniera costruttiva (e se non è così mi dispiace per loro) e nessuno in nessun caso ti metterà "alla gogna".
Io il primo codice che ho fatto visionare ad altri devo essere sincero mi vergognavo, ma alla fine col senno di poi me ne sarei dovuto fregare. Si impara (e soprattutto su molte cose sono scuole di pensiero, per dire io ti ho detto programmazione orientata agli oggetti, ci saranno in molti che non saranno d'accordo, soprattutto per i micro) :D
Avatar utente
Foto UtentedrGremi
1.094 4 9
Master
Master
 
Messaggi: 645
Iscritto il: 20 nov 2019, 19:49

1
voti

[6] Re: Accorgimenti per scrivere codice in modo efficiente

Messaggioda Foto UtenteGioArca67 » 3 mag 2021, 9:28

drGremi ha scritto:Per sistemi monocore e molto "scarsi" come arduino puoi usare i protothread, mentre in chip nuovi come l'STM32H745ZIT6 sono veramente multicore. Puoi avere processi e thread anche senza sistema operativo.


Sull'STM32H7 gira freeRTOS per le funzionalità di gestione dei task/thread/processi

Protothread implementa uno scheduler minimale
Avatar utente
Foto UtenteGioArca67
287 2 5
Frequentatore
Frequentatore
 
Messaggi: 275
Iscritto il: 12 mar 2021, 9:36


Torna a Firmware e programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti