View Full Version : Linux: garantire periodicità in c
Consigli? immag un thread che mi faccia da contatore di tick, e per ogni tick controlla quale periodo è scaduto, come posso implementarlo?considerate anche il fatto che l'applicativo si resetterà/ammazzerà una volta ogni 10 anni...insomma deve stare sempre su, quindi un minimo ritardo.....
Si potrebbe pensare anche di gestire un fattore di correz, ma...se il ritardo fosse deterministico...insomma nn ci riesco proprio!!
Qualcuno è in grado di aiutarmi?
avevo provato con la setitimer catturando il sigalarm ma...dopo un po', nn ricordo con precisione, inizia a inviare sigalarm in modo del tutto irregolare...ovviamente la priorità del thread e del processo è massima!!! con la select...cmq ho avuto dei problemi.
Poi ho iniziato a pensare di catturare degli IRQ o leggere RTC....cosa ne pensate? qualcuno ha mai implementato qualcosa interfacciandosi con il RealTimeClock? (ovviamente sto parlando di quello HW).
HELP!!
avevo provato con la setitimer
catturando il sigalarm ma...dopo un po', nn ricordo con precisione, a inviare
sigalarm in modo del tutto irregolare...ovviamente la priorità del thread e del processo è massima!!!
con la select...cmq ho avuto dei problemi.
ilsensine
27-09-2004, 09:34
Puoi essere più preciso su quello che ti serve e sulle latenze temporali massime che puoi tollerare?
semplifichiamo il tutto...immagina un timer manager che scandisce i tick e dei oggettini timeout che si iscrivono fornendogli un periodo(il periodo min e' di 250ms)...il timer manager allo scadere di ogni tick controlla se è scaduto qualche periodo, nel caso positivo invoca il metodo treat_event del obj timeout.
circa l'errore accettabile...è tutto relativo, se avessi un errore fisso in percentuale...mi andrebbe ancora bene;inserirei un fattore di correz ma.....se l'errore è variabile.....è la fine!!
La cosa importante è che ogni oggetto time out e' preciso nell'effettuare l'azione prestabilita!!
Se il TimerManager porta un ritardo con il trascorrere del tempo nn avro + che un determinato obj timeout che ripete la sua azione periodicamente....
mi spiego meglio con un es.
supponi di dover supervisionare il funzionmento di un partiolare sottosistema, esso invia dei msg di keep elive(via socket, seriale o....) periodicamente se...dovesse scattare un periodo max il sottosistema si ritiene fuori uso....ogni volta che si riceve tale info il timer si resetta;quindi un ritardo/anticipo nn controllato...va be hai capito. Ovviament il prob è semplificato ma....rende bene l'idea!
ilsensine
27-09-2004, 22:42
Più o meno. Non mi è ancora chiaro se puoi tollerare errori sistematici. Ad esempio è un problema se invece dei tuoi 250ms ti ritrovi con dei timeout variabili tra 255 e 265? Trattandosi (se non ho capito male) di un "timeout", non dovrebbe essere un fattore critico.
Perchè mi fai questa domanda hai una soluzione? postala...magari assieme possiamo trovare una soluzione, ammettendo che esista su questa piattaforma...
Il discorso è che stiamo parlando di un errore percentuale che varia tra il 2,5% e il 7,5% a prescindere del periodo?
Quindi su un timer di 1h perderei al max 4,5 sec...non è proprio la precisione che richiedevo, su timer di questo periodo posso perdere al max 2 sec.
Mi va bene un errore ma....che sia fisso in percentuale o...quantomeno che dipenda da quache cosa; se pur riesco ad implementare il tutto con un alto errore ma che riesco a determinarlo...va benissimo, lo si gestisce in qualche modo!
ilsensine
28-09-2004, 22:37
Il problema è concettuale, non implementativo.
Da quello che ho capito, ti serve un timeout per verificare che non cessi una certa attività. Se è così, non devi curarti del timeout effettivo, purché sia _superiore_ a un _minimo_ che stabilisci: la precisione, in questo caso, non ha grande importanza. Inoltre, il periodo di timeout dovrebbe essere resettato ogni volta che rilevi un evento che stai monitorando (ad es. come accade con i watchdog hardware). Normalmente si fa così.
Per questo ti sto facendo tutte queste domande: se ti serve un timeout, non importa la precisione. Altrimenti dovresti spiegarmi meglio le tue necessità e perché hai bisogno di precisione, in quanto ci sono n modi che potrei consigliarti per fare timer più o meno precisi (e ovviamente più o meno complicati) -- ma non sono utilizzati per dei semplici rilevatori di timeout.
Quello che mi serve è un timer, per svariati usi, con la max precisione ma che si puo' avere.
ti faccio un es degli n utilizzi che dovrei farne:
supponi che esistano due sottosistemi (vediamoli come due processi) che inviano msg ogni 100ms per avvertire che stanno funzionando(insomma che stanno su), immagina che questi sottosistemi prendono informazioni da msg(miei) per agire su dispositivi HW...il mio processo deve accorgersi entro un max di 250ms(parametro configurabile da file da leggere allo start-up.. dipende dal HW) che un sottosistema nn funziona e dare gli input all'altro in modo del tutto differente(interfac diverse), considera inoltre che il sottosistema nn accetta + gli input se scadono quei famosi 250ms(in effetti sono 250+50 dove il 250 e' sempre configurabile) e tutto il sistema(tutti i processi) cade!!
In questo caso esisterà un timeout che si scrive al TimerManager con un periodo di 250ms, scaduto il quale=>Non ricezione Msg
E' ovvio che ogni qual volta mi arriva un msg io resetto il timeout ma...nn ho capito come nn puo' interessare la precisione.
Ecco come un ritardo potrebbe causare "un disastro"....
ilsensine
29-09-2004, 20:13
Ok quindi ti serve un timeout massimo perché devi poter gestire l'evento in via alternativa in tempo utile.
250ms sono un bel periodo, devi considerare però la differenza tra il timeout minimo e quello massimo. Se ad es. il minimo è 100ms e il massimo è 250, hai un ottimo margine.
Inoltre hai un piccolo problema di lock: se ti scade il timeout e decidi di processare per via alternativa, il processamento "normale" deve essere annullato.
La famiglia di funzioni che possono aiutarti nel compito sono le pthread_cond_*, che fortunatamente sono associate a un mutex che ti consente di evitare facilmente fastidiose race. Ne è stato parlato qualche giorno fa di queste funzioni, puoi cercare il thread tra quelli passati.
In sintesi quello che deve fare il tread di monitoraggio è un pthread_cond_timedwait, attendendo un evento per un periodo di timeout che stabilisci. Chi deve effettuare l'operazione, prima blocca il mutex associato alla condizione, gestisce l'evento, e "sveglia" il thread tramite pthread_cond_signal in modo da segnalare l'avvenuta corretta operazione. Se ciò non avviene entro l'istante specificato, la pthread_cond_timedwait ritornerà con un errore (ETIMEDOUT). Il resto sono dettagli implementativi (sincronizzazione, eventuale aumento della priorità nel thread di monitoraggio ecc.)
Mi sembra la strada più appropriata al tuo problema. Il resto è fare pratica con queste funzioni, che in un primo momento possono non essere intuitive per come gestiscono il mutex associato.
Conosco le primitive, la settimana prox provo a tirar su uno schizzetto di programma e ti farò sapere..
Grazie per la collaborazione
ops...anche questa primitiva non va bene, porta ritardi.
Quello che ho fatto è eliminare il timer manager e implementare un timer singolo:
il work del tread riassunto:
gettimeofday Tempo1
pthread_cond_timedwait
aspetto il time out impostato
gettimeofday Tempo2
cout Tempo2-Tempo1
Impostando un periodo di un secondo mi porta un ritardo VARIABILE, ritardo medio poco meno di 20ms(ovviamente il tread timer è stato integrato nell'applicazione con priorità max e il proc lanciato con nice -20).
Quindi anche questo tentativo sembra nn essere buono...
E' possibile che nessuno mai abbia implementato un timer su linux-intel?
Quello che mi servirebbe è un semplice timer con tre metodi
Start(periodo)
TimeOutElapsed()
Stop()
ma con alta precisione su kernel 2.4....veramente nn è possibile!
ilsensine
04-10-2004, 14:27
Originariamente inviato da cavay
Impostando un periodo di un secondo mi porta un ritardo VARIABILE, ritardo medio poco meno di 2ms
sì, prevedibile. Da quello che hai detto (timeout compreso tra un centinaio di ms fino a 250 ms) dovrebbe essere una soluzione buona.
Stai usando un kernel 2.6?
E' possibile che nessuno mai abbia implementato un timer su linux-intel?
Latenze inferiori al ms richiedono sistemi operativi hard realtime. Linux è soft realtime, con buone prestazioni in questo campo.
scusa ma...avevo commesso un errore, il ritardo era di 20 ms e nn 2.
Il kernel della macchina target è il 2.4
ilsensine
04-10-2004, 15:13
Originariamente inviato da cavay
scusa ma...avevo commesso un errore, il ritardo era di 20 ms e nn 2.
Ecco appunto. Il kernel 2.4 ha un clock di 100 hz, il 2.6 di 1000 hz.
Il semplice passaggio al kernel 2.6 ti migliora le latenze di un ordine di grandezza. Scendere sotto il ms è più complicato.
Ed utilizzando RTAI ?
http://www.aero.polimi.it/~rtai/
ilsensine
04-10-2004, 15:43
Originariamente inviato da cionci
Ed utilizzando RTAI ?
Si utilizza se è necessario un hard realtime.
Per latenze nell'ordine del paio di ms il kernel 2.6 va bene. In casi particolari anche per latenze inferiori.
Quindi su questa piattaforma la soluzione nn esiste?
Cmq....ho provato, per sfizio, sul kernel 2.6 ma....i risultati nn sono stati ecellenti; è vero che si migliora e pure di tanto ma...nn come dovrebbe!
Non so cosa siano le RTAI, mi informo un po e ...se posso e se servono le utilizzo; cmq la piattaforma è sempre linux intel kernel 2.4
ilsensine
04-10-2004, 17:04
Originariamente inviato da cavay
Cmq....ho provato, per sfizio, sul kernel 2.6 ma....i risultati nn sono stati ecellenti; è vero che si migliora e pure di tanto ma...nn come dovrebbe!
Dovrebbe assestarsi intorno a 1-3ms; imposta per il thread di controllo (e solo per quello) uno scheduling realtime (v. pthread_attr_setschedparam).
Quindi su questa piattaforma la soluzione nn esiste?
Sul kernel 2.4? Non lo vedo adatto per questa applicazione.
Puoi usare l'rtc, ma sei vincolato a tick in istanti precisi nel tempo (cioè non puoi dire "resetta il timer su questo istante" -- non che io sappia). Con l'rtc puoi ottenere accuratezze nell'ordine di (1+-0.1) us (sul kernel 2.6 e scheduler SCHED_FIFO). Se vuoi ti posto un codice di esempio.
te ne sarei veramente grato
ilsensine
04-10-2004, 17:19
Questo programma imposta un intervallo del timer (settato dalla macro DELTA -- deve essere <= 8192), e calcola la media e dev. standard di quanto si discosta dall'istante temporale atteso. Se lo esegui con i privilegi di root sul kernel 2.6, otterrai i risultati che ho citato. Anche con il kernel 2.4 puoi ottenere buone prestazioni:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/rtc.h>
#include <math.h>
#include <sched.h>
#include <string.h>
static unsigned int __us(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_usec+tv.tv_sec*1000000;
}
static void __attribute__((__noreturn__)) fail(const char *fnc) {
perror(fnc);
exit(-1);
}
#define RATE 64
#define DELTAS 1024
int main(void) {
int fd;
double sum = 0.0;
double var = 0.0;
double delta;
double deltas[DELTAS] = { 0.0, };
int dpos = 0;
const double r = 1000000.0/RATE;
unsigned int items = 0;
struct pollfd pfd;
unsigned int t1;
unsigned int t2;
int rep;
struct sched_param p;
p.sched_priority = 10;
if(sched_setscheduler(getpid(), SCHED_FIFO, &p))
perror("sched_setscheduler");
if(mlockall(MCL_CURRENT|MCL_FUTURE))
perror("mlockall");
fd = open("/dev/rtc", O_RDONLY);
if(fd<0) fail("open");
if(ioctl(fd, RTC_IRQP_SET, RATE)<0)
fail("ioctl(RTC_IRQP_SET)");
pfd.fd = fd;
pfd.events = POLLIN;
for(rep=0; rep<10; ++rep) {
ioctl(fd, RTC_PIE_ON);
poll(&pfd, 1, -1);
ioctl(fd, RTC_PIE_OFF);
}
t2 = __us();
while(1) {
t1 = t2;
ioctl(fd, RTC_PIE_ON);
poll(&pfd, 1, -1);
t2 = __us();
ioctl(fd, RTC_PIE_OFF);
delta = fabs(r-(double)(t2-t1));
sum += delta - deltas[dpos];
var += delta*delta - deltas[dpos]*deltas[dpos];
deltas[dpos] = delta;
items<DELTAS && ++items;
++dpos>=DELTAS && (dpos = 0);
!--rep && (
fprintf(stderr, "avg=%0.2f us stddev=%0.3f us\n",
sum/items, items>1 ? sqrt(var)/(items-1) : sqrt(-1.0)),
(rep = 10)
);
}
}
Grazie, ho tratto un po' di cose e implementato il TimerMenager....sembra che funzioni piuttosto bene. Devo fare ancora delle misure + serie ma...sono ottimista.
Su linux & C. del mese di giugno c'era un articolo proprio sul soft-realtime col kernel 2.4..in pratica aumentavano la risoluzione temporale modificando poche righe del kernel..aumentando la risoluzione fino a 1ms..non so se puo fare al caso tuo...posto il codice se volete..
Ciao
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.