Newsgroup: it.comp.lang.c
Titolo: Per esperti! Applicazione Real-Time

Il problema (adeguatamente semplificato) e' il seguente:
voglio far eseguire un certo blocco di istruzioni in tempo reale, ma la
massima "risoluzione" di tempo che riesco a leggere e' di 55
millisecondi, ossia 18.1 letture al secondo. Questo utilizzando la
funzione "clock()" inclusa in "bios.h" (io uso il compilatore Watcom
C/C++ 11.0 sotto WIN95).
In pratica le istruzioni fondamentali che ho usato sono:
-----------------------------------------------------------------
incremento = 200;   // Passo di incremento in millisecondi
tempo_che_voglio=0;
clock_iniziale=clock();
while (!fine)
{
  /*   Aspetta senza fare niente    */
  while ((clock()-clock_iniziale)<=tempo_che_voglio) ;
  tempo_che_voglio+=incremento;
  /*  e qui ci metto le righe di codice che devono andare in tempo reale
*/
}
-----------------------------------------------------------------
Il problema come gia' accennato consiste nel fatto che non posso far
scendere incremento sotto una certa soglia,pena la perdita del
real-time. Io avrei altresi' bisogno di passi di incremento dell'ordine
del millisecondo.
Un'altra cosa che non mi piace e' quel ciclo di attesa che non esegue
nessuna istruzione (se ben ricordo si dovrebbe chiamare "Attesa
Attiva"); sarebbe molto piu' elegante trovare il sistema di bloccare il
processo in esecuzione e risvegliarlo al momento opportuno (il che
dovrebbe permettere anche un maggior tempo di CPU per gli altri processi
in esecuzione), ma purtroppo non ho la minima idea di come poterlo fare.
Ricordo in ogni caso che il codice e' scritto in C e NON posso usare il
C++.
Grazie a tutti per l'eventuale aiuto.
Marco Casini.
casi...@sunto.ing.unisi.it

in esecuzione), ma purtroppo non ho la minima idea di come poterlo fare.
si risolve scrivendo uno scheduler per il multitasking cooperativo ... e il
giuoco é fatto !!
Avresti così diversi processi ognuno dei quali decide quando passare la
palla agli altri.
Ai tempi del DOS si usava moltissimo per applicazioni di una certa "qualità"
ed io personalmente ricordo di averne scritto uno. ( Non é difficile )
Ciao

C/C++ 11.0 sotto WIN95).
Mmmh...io credo che sia piu' semplice scalare l'everest in
maglietta e pantofole; sono curioso di vedere quali soluzioni
vengono proposte....

 in esecuzione), ma purtroppo non ho la minima idea di come poterlo fare.
In questo caso, devi lavorare in multitask: il lavoro che ti serve puo'
essere effettuato da un task periodico, che esegue il calcolo e si blocca;
verra' poi svegliato da un interrupt lanciato dal contatore.
Penso che la cosa piu' semplice sia comunque utilizzare un kernel
real-time precostruito: se ne trovano molti che implementano algoritmi di
schedulazioni adatti alle applicazioni real-time (come EDF o RM), e
riprogrammano il timer del PC in modo da ottenere la risoluzione temporale
che ti serve. Se ti interessa, dai un'occhiata ad 
http://hartik.sssup.it
il kernel HARTIK fa proprio al caso tuo: e' una libreria linkabile a
programmi C, che si occupa di effettuare per te tutto il lavoro "sporco"
(gestione del timer, delle interruzioni, schedulazione dei processi...).
La risoluzione temporale ottenibile e' molto migliore del millisecondo, ma
e' comunque settabile dal programmatore.
Ha librerie che permettono di fare I/O, gestisce schede sonore SB16 e
schede di rete 3com Vortex, e fa tante altre cose.
Puo' funzionare in modo reale (se hai il Watcom C) o in modo protetto (con
Watcom o DJGPP). Sono disponibili i sorgenti e sta sotto GPL. Se ti
interessi di real-time, vale senz'altro la pena di dare un'occhiata (e con
questo faccio un po' di pubblicita' al prodotto...)
Se pensi che il kernel possa essere interessante o se hai dei commenti,
fammelo sapere tramite mail.
					Ciao,
						Luca
N.B.: se vuoi fare real-time serio, scordati windows95 :(

 
Se ti riferisci al fatto di voler usare WIN95, sono d'accordo con te: e'
impossibile! Non e' solo un problema di leggere il timer: anche ammesso di
fare polling su un timer che scatta ad ogni millisecondo (ma si puo'
riprogrammare il contatore del PC sotto win95?), c'e' tutto un problema di
scheduling e gestione delle risorse.
Una soluzione comunque esiste: riavviare Win95 in modalita' DOS, e
scriversi un programmino che si riprogrammi il timer e, se serve,
implementi quel poco di multiprogrammazione che serve alle applicazioni
real-time
			Ciao,
				Luca

Dimenticavo:
Naturalmente win95 non é un SO che ti garantisca alcunchè circa il real
time;
per cui DEVI andare a DOS.

in esecuzione), ma purtroppo non ho la minima idea di come poterlo fare.
Con la precisione di QueryPerformance&cc, non c'e`, che io sappia,
alcun modo.
Puoi invece ottenere questo effetto, su hardware appositamente
equipaggiato (non necessariamente coincidente con tutto e solo
l'hardware che ti supporta le QueryPerformance&cc), usando i
"multimedia timers".  La precisione massima nominale dei timer
multimedia e` pero` di 1 millisecondo, quindi non sufficiente se
hai veramente bisogno, come dici, di _intervalli_ di 1 millisecondo!
Non mi addentro dunque nella spiegazione relativa ai mm timer,
ma, dove una precisione inferiore puo` bastare (e, onestamente,
su Win95 e` difficile _in pratica_ che tu ottenga davvero una
precisione ripetibile inferiore al millisecondo!!!), essi hanno il
vantaggio di potere programmare "eventi", una tantum ovvero
periodici, che eseguono callback a tue funzioni (puoi dunque,
ad esempio, bloccare il thread principale su di un mutex, e
segnalare quel mutex dalla tua funzione al callback del timer).
Va comunque segnalato che "eventi periodici di timer con
ritardo d'evento di 10 millisecondi o meno consumano una
porzione significativa delle risorse di CPU"; non e` detto,
insomma, a seconda del tuo esatto schema d'uso, che vi
sia un sostanziale beneficio rispetto al "busy waiting", o
"spin lock" che dir si voglia, che puoi usare con QueryPerf&cc.
Real-time, e normale multitasking, sono in effetti concetti
poco compatibili fra loro; Windows non ti garantisce in ogni
caso il real-time, ma piu` ti ci avvicini (ad esempio, usando
un thread di elevata priorita` per le tue operazioni real-time),
piu` ti allontani dalla normale operazione multitasking.
La commutazione fra task, infatti, richiede un certo ritardo;
questo ritardo non va necessariamente calando col tempo
al tasso a cui crescono le velocita` delle CPU, perche`, con
questa crescita di velocita`, tendono ad aumentare le
dimensioni di cache, e altro stato da salvare e recuperare
per-thread.  La base del tempo reale` e` la _ripetibilita`_,
la _garanzia_ che i ritardi fra l'inizio e la fine di una data
operazione saranno _sempre_ di un certo X piu` o meno
un epsilon molto piccolo; le cache, e ancor piu` la memoria
virtuale, come anche altri aspetti della multiprogrammazione,
introducono tendenzialmente fenomeni di "aleatorieta`" dal
punto di vista del singolo task.  I normali sistemi operativi
(Windows, Unix, VMS, OS/2, ecc ecc) ottimizzano una
qualche combinazione di throughput e tempo medio di
risposta -- le necessita`, invece, di ottimizzare il tempo
_massimo_ di risposta, o minimizzare la variabilita` del
tdr, conducono a progettare kernel molto diversi, sistemi,
appunto, specializzati per il (vero) real-time.
Cio` non toglie che sia possibile affrontare con sistemi
operativi "generali"  alcuni occasionali compiti "quasi"
real-time... il _vero_ real-time e` un'altra cosa, ma, se
le esigenze di "real" sono relativamente modeste, non
e` escluso che ci si possa avvicinare.  In molti casi,
girare in "kernel-mode" (device driver, VxD, ecc) puo`
migliorare certi aspetti di ripetibilita`, ad esempio.
Alcuni sistemi (Windows/NT, Windows/CE, Linux)
soffrono di minori "irripetibilita`", quindi sono piu`
adatti a questo "quasi-real-time-ma-non-proprio"
rispetto ad altri "fortemente irripetibili" (Windows/95,
ad esempio, e` pessimo da questo punto di vista,
almeno per le operazioni user-mode; non so dirti
quanto ripetibili risultino i ritardi in Win95 in operazioni
kernel-mode, VxD ecc).
Alex

mi é venuto in mente che c' é un modo per organizzarti un real time facendo
convivere Windows95 che é concettualmente molto semplice ma tecnicamente
complesso ... ma fattibile.
Partendo dalla considerazione che il multitasking di Windows viene fatto a
Sw e considerando che le architetture 80386/486/Pentium ti permettono una
schedulazione ad Hw ( utilizzando risorse del processore all' uopo
predisposte ) é possibile scrivere uno scheduler che utilizza il meccanismo
Hw del processore, nel quale Windows95 venga visto come il "Task" meno
importante ( il task "idle" per intenderci );
Tale componente Sw dovrebbe ovviamente partire prima di windows e dare a
Windows un bel po di servizi ....
Tutto sommato, credo sarebbe meglio utilizzare qualcosa di già fatto !!
Altra cosa: il processore Pentium ha un registro a 64 bit leggibile con
opportune istruzioni ASM ( o in codice binario se eventualmente non
supportate dal compilatore ) che ti danno una risoluzione pazzesca ( nell'
ordine dei 100ns );
Se il tuo task é vivo può apprezzare quindi questi tempi, se invece é
soltanto ready ( window95/NT non garantiscono nulla ) non hai modo di
assicurarti circa la ripetibilità dei risultati.
ciao

Hai perlomeno due possibilità per ottenere una maggiore risoluzione del
1/18 di secondo 'standard':
- riprogrammare il timer di sistema per interrompere la CPU con una
interruzione a maggore frequenza (si arriva a frequenze che ti abbassano
notevolmente il millisecondo di intervallo)
- usare un'altro 'orologio', denominato Orologio CMOS di sistema a tempo
reale,
presente sui PC 286+ (cioè non sugli 8088-86)
Per eliminare l'Attesa Attiva (necessario per un 'serio' programma
real-time), basta che intercetti l'interruzione opportuna (nel primo caso
la 08h (IRQ0) o, ancora meglio la 1ch dato che l'hanno prevista
appositamente); nel secondo caso, leggermente più complicato, la ... (non
la ricordo a memoria, ma è associata a IRQ8 del secondo PIC, ciè del
secondo interrupt controller).
Evidentemente tutto ciò implica una serie di dettagli tecnici abbastanza
articolati (sono quasi certo però che si possa fare il tutto anche in C++),
per cui, se hai bisogno, fammelo sapere sul NG e invierò codice.
C I A O

in esecuzione), ma purtroppo non ho la minima idea di come poterlo fare.
Se non lo fa il sistema operativo mi sa che e' un po' difficile. Se crei un
altro thread che si preoccupa di aspettare il tempo definito comunque hai un
thread che va in un ciclo di attesa ed il problema si ripresenta.
Ciao.
Antonio Donatiello

 ordine dei 100ns );
Se ti stai riferendo al TimeStamp counter del pentium (leggibile con
un'istruzione non documentata ma comunque supportata da quasi tutti i
compilatori assembler), questo e' utilizzabile solo leggendone il valore
"a polling" (non puo' essere utilizzato per sollevare interruzioni) e
quindi obbliga ad usare cicli di attesa attiva. Notare che cio' funziona
solo se il task che fa attesa attiva e' l'unico presente nel sistema (o e'
quello a priorita' piu' alta...).
Mi hanno detto che WinNT ha uno scheduler a priorita' fissa POSIX
compliant, che potrebbe essere usato allo scopo.
Rimango comunque dell'idea che la cosa piu' semplice sia tornare al buon
vecchio MS DOS e implementare un semplice ma efficace multitask su di
esso. (Si trovano migliaia di tasker piu' o meno real-time che girano
sotto DOS, come per esempio HARTIK, di cui ho parlato in un precedente
post).
				Ciao,
					Luca


......ZAC.....
beh... se proprio vogliamo farci del male .... ti posso segnalare anche
l'istruzione assembler RDTSC (...funziona solo su proc. Pentium...) che ti
ritorna il valore di un contatore a 64 bit che viene incrementato ad ogni
ciclo di clock! Cio significa, teoricamente, una risoluzione di 1 diviso
"frequenza della cpu" che ad esempio su un P200 e di 5 ns.
una seconda possibile soluzione (.. un po' OT visto che e' assembler ..) che
ti vorrei proporre e' data da questo breve codice che io onestamente non ho
capito.....(..chi c'e' alla porta 0x61?!?).... ma ti posso dire che sembra
funzionare correttamente...
void MyDelay (unsigned long microsec) {
unsigned long appo;
  for(appo = (microsec+14)/15+1; appo; appo--) {
    asm in al,0x61
    asm and al,0x10
    asm mov ah,al
GIRO:
    asm in al,0x61
    asm and al,0x10
    asm cmp al,ah
    asm je GIRO
  }
}
Ciao Andrea
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
per rispondere rimuovere NOSPAM dall'indirizzo
to reply please remove NOSPAM from the address
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
** La nuvoletta del Ragioniere e' ben poca cosa se confrontata con
l'anticiclone del Programmatore! **

voglio far eseguire un certo blocco di istruzioni in tempo reale, ma ..
Usare Win9x mi sembra volersi fare male. Presumo che tu voglia usare un
windows per avere gratis altro software che ci possa girare. Se cosi' non
e', e tu hai veramente bisogno di tempi cosi' stetti usa un RTOS.
Se ti accontenti dei 10 millesecondi spesso (ma non sempre), e vuoi usare un
windows per motivi tuoi, NT te li *garantisce*. Certo non devi usare un 486
con 24 Mb di RAM. 
Se vuoi andare al millisecondo, NT dovrebbe farcela, ma deve usare i trucchi
del mestiere, ovvere andare sul multithread, con il thread di lavoro che ha
una alta priorita' (non usare il real time se non conosci BENE il S.O.
n.d.p.), e usare Sleep et simila (lascia perdere le funzioni che hai usato
che fanno uso della coda dei messaggi).
Prova a fare un esperimento con codice del tipo:
void MioThreadAdAltaPRiorita(void)
{
	int Valzer = 1000;
	int tempo = GetCountTick();
 
	while(1000--)
	{
		Sleep(0);
	}
 
	tempo = GetCountTick() - tempo;
	StampaDaQualcheParte(tempo);
}
e provalo mettendo la macchina sotto stress.
Facci sapere a che tempi arrivi.
+++
Se hai soldi da buttare, e ti serve necessariamente usare NT, esistono
versioni di NT real time.
Se hai soldi da buttare e ti basta usare un simil NT, esistono RTOS con API
simili a NT (Direi quello della Pharl Lap).
Se sei un Kamikaze, e devi necessariamente usare un Windows, scriviti il tuo
bel drive Kernel, e vai ad interferire con lo scheduler di NT. Metodo
sconsigliato se non ti chiami Cutler o Salomon.
Papero a Te.
--- (Elimina il papero per le repliche) ---