Newsgroup: it.hobby.elettronica.digitale
Titolo: Timed task list

Navigando su Internet mi sono imbattuto in questa pagina:
http://www.rmbconsulting.us/jump-tables-via-function-pointer-arrays-in-cc
C'è un paragrafo che si chiama proprio "Timed task list" dove c'è un
codice
d'esempio per la gestione di una lista di task da eseguire ad
intervalli regolari.
Sinceramente io non ho capito come funziona. Dice che bisogna attivare
un
interrupt che incrementa la variabile tick ad ogni IRQ. Essendo una
variabile
unsigned char, varia da 0 a 255 con wraparound.
All'interno del main() questa variabile, se non nulla (quindi 255
volte su 256
intervalli di IRQ), viene decrementata.
Che senso ha?

 Che senso ha?
Cos�, ad occhio, penso che venga usata solo come flag di IRQ avvenuto.
L'ISR la mette a 1 e il main la rimette a zero decrementandola.
Se � davvero cos� devo dire che � fatto in modo un po' oscuro da 
capire (bastava mettere ticks = 0 invece di ticks--), oltre che bug 
prone.
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org

 prone.
E' un vecchio trucchetto per aumentare l'efficienza.
Assegnare una costante a una variabile e' leggermente
piu' lento e occupa un byte di codice in piu' rispetto
a un incremento o decremento, almeno in molte cpu risc.
In realta' dipende anche da quanto e' furbo il compilatore,
molti tradurrebbero tick = 0 con uno xor con la variabile
stessa, che in termini di efficienza e' equivalente a un
decremento.
In questi casi secondo me e' meglio favorire la leggibilita'
del sorgente che cercare di risparmiare 100 nS su magari
millisecondi di esecuzione.

 L'ISR la mette a 1 e il main la rimette a zero decrementandola.
Non e' quello il motivo. E' una questione di sicurezza
e generalita': Se tick e' diverso da 0, significa che e' passato
*almeno* un IRQ di tick  (tick++, non tick=1!) e quindi va controllato 
se un evento della lista va gestito.
Se pero' nel frattempo (non so' quanto tempo predono le singole
funzioni nella lista; supponi che una prenda per absurdo 5,10 o 100 
tick...) uno o piu' tick hanno tempo di entrare, ne devo tenere conto...
Certo, ci sono sistemi migliori :-)
A.

 Certo, ci sono sistemi migliori :-)
Sì, decisamente sì.

 riparla al prossimo "momento giusto".
Dipende ... posso usare diverse strategie, visto che ogni volta
calcolo il tempo trascorso rispetto al tick corrente, ne posso
tenere conto nella mia funzione, se serve, ad esempio compensando
il jiiter di tempo.
A.

 a un incremento o decremento, almeno in molte cpu risc.
Beh, in realt� dipende molto dalla CPU e dal compilatore, non lo darei 
come "trucco generico".
Per esempio, sulle CPU che uso io prende lo stesso tempo.
Ed inoltre, anche se si risparmiasse 1 ciclo di clock, non mi sembra che 
sia questa gran ottimizzazione, in confronto alla difficile leggibilit�.
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org/

80196@12Mhz ha scritto:

Pi� che sistemi migliori, ci sono sistemi che funzionano, questo, fatto 
in questo modo, non funziona.
Se ho una routine che dura parecchio, e che quindi mi fa perdere 
parecchio tempo, al giro dopo tick sar� molto maggiore di 1.
Esso viene solo decrementato di 1 per�, per cui, se al giro dopo ho solo 
routine veloci, mi ritrovo a decrementare tick prima che effettivamente 
sia passato 1 tick. Alla routine che misura il tempo viene passato 
sempre tick (che contiene ancora un valore elevato) e quindi si misurano 
dei tempi sbagliati e si eseguono le callback ad intervalli non corretti.
Se nessuno resetta tick questo sistema non funziona.
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org/

 dei tempi sbagliati e si eseguono le callback ad intervalli non corretti.
E' *ovvio* che questo sistema ha dei limiti e ci sono
soluzioni migliori, ma e' comuque un sistema funzionante,
mettendo delle condizioni al contorno e determinando
un valore di tick adeguato alla propria applicazione.
BTW, il codice non e' mio, per cui e' un discorso
sui generis... un sistema a liste linkate e ordinate
sarebbe piu' efficiente, ma comunque sempre un sistema
di timer software ha dei limiti e delle latenze da calibrare.
A.

 A.
A me continua a sembrare che non funzioni.
Se volevano tenere conto dei tick multipli, bastava mettere tick a 0 una 
volta visto che era != 0.


 pu� saperlo ed eseguir� le callback come se lo fossero.
Yes, penso che questo sia lo scopo :-)
infatti e' un "Timed task"  ovvero uno scheduler di
processi da eseguire ciclimante....
 > Se volevano tenere conto dei tick multipli, bastava mettere tick a 0
 > una volta visto che era != 0.
Presumo che la logica che sta' sotto � che ad ogni determinato
perido di tempo (tick) deve essere associata una azione:
se per qualche caso una o piu' funzioni hanno sforato il
tempo di tick (e quindi tick > 1), devo comunque esguire le
funzioni che avrebbero dovute essere fatte a quei tick.
Se azzero tick, mi perdo questa funzione!
Ovviamente non si parla di genenerare segnali real-time:
questo e' piuttosto un soft-scheduler che garantisce
l' esecuzione anche con jiiter di diverse funzioni.
Queste situazioni di sforamento non devono essere la norma,
se no il sistema non sta' in piedi.
a.

 sia questa gran ottimizzazione, in confronto alla difficile leggibilità.
Pensa che una volta il bravo programmatore faceva ben di peggio,
per esempio codice automodificante, penso che la stessa parola
spieghi la perversione! Ovviamente parliamo di architettura di Von
Neumann senza nessuna protezione e in linguaggio macchina
ai tempi delle memorie a nuclei magnetici.
Comunque anch'io ho fatto le mie belle str...ate in C, per
esempio eseguire una funzione puntata da un puntatore
ad un array auto di char nel quale prima costruivo il codice
al volo.

 se no il sistema non sta' in piedi.
il limite dello sforamento e' il wrap dopo 255 tick non serviti,
ma se sei _certo_ di restare entro questo limite, il sistema sta in
piedi perfettamente, ritardando semplicemente i task che non ha potuto
eseguire al momento giusto (che ovviamente possono essere ritardati).
saluti
-- 
  lowcost

 se no il sistema non sta' in piedi.
Sono d'accordo che *in generale* il sistema possa funzionare come lo 
descrivi. Sei per� intervenuto per far notare che il codice *specifico* 
indicato funzionava come dici.
A me continua a sembrare di no, poi parlando sui generis siamo d'accordo.


 indicato funzionava come dici.
Yes, funziona cosi

 cooperativo ... pio o meno  ;-)
Ho capito quello che intendi, ma per favore mi puoi analizzare in 
dettaglio allora il codice per indicarmi dove sbaglio?
Io ho capito che:
- se tick vale pi� di 1, significa che le callback sono durate parecchio
- tick viene allora decrementato di 1
- Si calcola il tempo dall'ultima chiamata alle callback
- Si eseguono le callback
A questo punto tick vale ancora un numero maggiore di zero, sebbene il 
questi tick non siano passati davvero.
Se si riparte dall'inizio e si ricalcola il tempo otteniamo di 
rieseguire delle callback anche se il tempo non � scaduto.
Dove sbaglio?


 Dove sbaglio?
Da nessuna parte...
l' assunto del codice (non entro nel merito che si poteva fare meglio ) 
e' che devi gestire un task allo scadere di un evento di tempo (tick).
Ora, avendo usato il modulo per la determinazione del tempo
(cosa ORRENDA), devi per forza processare OGNI singolo tick
ovvero, non puoi perdere neanche un evento.
Da qui il decremento 'singolo' dei singoli ticks.
Poi si usa una variabile di appoggio, "time"
che stando a quanto scritto:
"The infinite loop checks for a non-zero tick value,
  decrements the tick variable and computes the elapsed
  time since the program started running."
Dovrebbe mantenete il tempo di sistema in modo 'assoluto'
(rolla comunque entro 256 ticks), di questo dovrebbe
occuparsi la funzione computeElapsedTime(tick),
che non e' mostrata,ma assumiamo che sia ok.
E' questa variabile 'time' che accumula il tempo
trascorso, quindi puoi avere temporizzazioni da
1 a 255 tick totali (Al massimo: ma potrebbe essere
castrata a 100, per esenpio...)
Questo tanto per discutere, anche se io avrei usato un
approccio diverso ;-)

80196@12Mh ha scritto:

Ok, ma sarai d'accordo con me che la computeElapsedTime(), non pu� far 
altro che prendere per buono il valore di tick che gli viene passato.
Non pu� sapere se sono davvero trascorsi i tick che gli si passano 
oppure no.
Quindi i tempi calcolati non possono che essere sbagliati (a volte), che 
� quello che mi preme far notare.
Faccio un esempio che si capisce meglio.
Ho un evento che deve essere eseguito ogni 3 tick e la variabile tick 
vale 4.
Viene decrementata e vale 3. La computeElapsedTime(), non pu� far altro 
che sommare 3 al tempo totale.
Quando viene fatto il controllo sul modulo, si vede che � un multiplo di 
3 e la callback viene eseguita. Essa per� dura un po', tanto da far 
entrare un altro incremento di tick che quindi torna a valere 4.
Dato che tick � uguale a prima vengono rifatte le stesse operazioni, con 
la conclusione che la callback viene nuovamente chiamata, anche se in 
realt� doveva essere chiamata una volta ogni 3 tick.
Questa condizioni si autosostiene e porta alla chiamata della callback 
pi� frequentemente di quanto voluto.
E' per questo che dico che il codice, per come � scritto, non funziona.
Sono d'accordo che l'intento era di farlo funzionare come la pensi tu, 
ma l'implementazione � pesantemente buggata.


 
Non direi, stante le premesse: e' una implementazione povera,
su questo siamo d'accordo, e' anche critica, ma non mi
pare bacata!
bye

 sistema non puo' eseguire quato richiesto in termini di performance.
Non � esatto.
Il sistema pu� essere *mediamente* poco carico, ma basta che una sola 
volta sfori, per far s� che vada in uno stato che genera errori a 
catena stabilmente (le callback vengono chiamate pi� frequentemente 
rispetto a quanto dovrebbero da l� in poi).
Faccio notare che tutto questo meccanismo, nel tuo primo post, l'hai 
definito "una questione di sicurezza".
E se � stato inserito per sicurezza, dovrebbe proprio gestire 
correttamente il caso sporadico in cui *ogni tanto* le callback durano 
troppo senza effetti collaterali drastici come invece avviene.
Per questo motivo, per me � bacato.


 troppo
A me pare che il sistema sia proprio mirato a ci�. Pensaci meglio.
Lascia perdere i bit del contatore, se si esauriscono vuol dire che il
sistema � sottodimensionato pi� di due ordini di grandezza, che non �
pochissimo.
Questo tipo di gestione del contatore ti d� la possibilit�, per quanto con
un ritardo che l'applicazione ti deve consentire di tollerare, di gestire
picchi di lavoro enormi senza perdere un task. Come sempre, dipende
dall'applicazione. Se sbagli i fondamentali, � giusto che affondi.