Relazione finale di Sistemi Real-Time La Loggia Salvatore Collotta Mario Cos’è un sistema Real-time? x(t) Sistema Real-time Ambiente y(t+Δ) E’ un sistema in cui la correttezza dipende non solo dai risultati che si ottengono in uscita, ma anche dal tempo entro cui tali risultati sono ottenuti. Cos’è un sistema Real-time? x(t) Sistema Real-time Ambiente y(t+Δ) TEMPO: la validità dei risultati prodotti da un processo di elaborazione non dipende soltanto dalla correttezza delle singole operazioni, ma anche dal tempo entro cui tali risultati sono ottenuti. REALE: la risposta del sistema agli eventi esterni deve avvenire durante l’evolversi degli eventi stessi, e quindi il tempo interno di sistema deve essere misurato secondo un riferimento temporale uguale a quello dell’ambiente in cui il sistema opera. I sistemi real-time vengono solitamente distinti in due tipi: HARD: un processo real-time è di tipo hard se la violazione della propria deadline comporta un effetto catastrofico sul sistema. SOFT: un processo real-time è di tipo soft se la violazionedella propria deadline non compromette il corretto funzionamento del sistema. In tal caso il processo non è caratterizzato da una scadenza rigida, e può essere completato anche oltre il tempo specificato dalla sua deadline. Real-time ≠ velocità Un sistema real-time non è un sistema veloce!!! τ1 τ2 Raddoppiando la velocità, si ha una deadline miss: Deadline miss Analisi di fly.c Elaborazione : “TZE-TZE” La storia della mosca attaccata dall’insetticida più potente al mondo. Utilizzeremo per testare il comportamento dei task fly: S.Ha.R.K. • E’ un kernel real - time (open source) creato dalla Scuola Superiore S.Anna. Analizziamo il codice: #define YMENU 10 /* spazio menu schermata shark */ #define XMIN 50 /*posizioni limite #define XMAX 600 lungo le ascisse #define YMIN 100 e le ordinate*/ #define YMAX 450 #define VEL 5 /* velocità lineare (= 5) */ #define ANG 30 /* angolo massimo sterzata (30) */ #define D 5 /* raggio mosca */ #define ESC 27 /* codice ASCII del tasto ESC */ #define MAX_P 30 /* max numero di mosche */ #define FLYGROUP 1 double tick = 1.0; /* tick = 1 ms */ int fly_period = 40000; /* task periodico */ int fly_wcet = 1000; /* task tempo di esecuzione nel caso peggiore */ PID pid; sem_t mutex; void draw_fly(int x, int y, int c) { sem_wait(&mutex); grx_disc(x, y, D, c); /*disegna un cerchio*/ sem_post(&mutex); } void sangue(int x, int y) { sem_wait(&mutex); grx_disc(x,y,D,RED); /*coordinate,diametro e colore*/ sem_post(&mutex); } TASK fly(void *arg) /*crea il task*/ { int x, y; int ox, oy; int dx, dy, da; /*da= direzione obliqua*/ int teta, col; int outx, outy; double r; /* angolo */ int i = (int)arg; x = ox = (XMIN+XMAX)/2; y = oy = (YMIN+YMAX)/2; teta = 0; col = 2 + i; /* colore fly */ while (1) { da = rand()%(2*ANG) - ANG; /* da = [-ANG,ANG] */ teta += da; /*sterzata casuale rand()*/ if (teta > 360) teta -= 360; /*per ottenere valori compresi tra 0 e 360*/ if (teta < 0) teta += 360; /*per ottenere valori compresi ra 0 e 360*/ r = (double) teta * PI / 180.; /*si ottiene il valore dell'angolo*/ dx = (float)(VEL * cos(r)); /*distanza percorsa lungo x*/ dy = (float)(VEL * sin(r)); /*distanza percorsa lungo y*/ x += dx; /*aggiornamento*/ y += dy; /*aggiornamento*/ outx = (x >= XMAX) || (x <= XMIN); /*valori oltre i quali si esce dal rett.*/ outy = (y >= YMAX) || (y <= YMIN); /*valori oltre i quali si esce dal rett.*/ if (outx || outy) { sangue (ox,oy); /*ox,oy coordinate del punto di impatto con il rettangolo*/ myexit=1; return 0; } draw_fly(ox, oy, 0); draw_fly(x, y, col); ox = x; oy = y; grx_line ((XMIN+XMAX)/2,YMIN+30,(XMIN+XMAX)/2,YMIN+300,RED); grx_line ((XMIN+XMAX)/2+70,YMIN+100,(XMIN+XMAX)/2-70,YMIN+100,RED); task_endcycle(); } } /* funzione chiamata nel momento in cui il sistema esce */ void byebye(void *arg) { grx_close(); cprintf("Bye Bye!\n"); } /****************************** MAIN ******************************/ int main(int argc, char **argv) { HARD_TASK_MODEL m; char c; /**** carattere da tastiera ****/ int i = 0; /**** numero di task creati ****/ TIME seme; /* usata per inizializzare il “seme”, var temporale */ /**** Setta la funzione di chiusura (BYE-BYE) ****/ sys_atrunlevel(byebye, NULL, RUNLEVEL_BEFORE_EXIT); /**** inizializzazione grafica ****/ if (grx_init() < 1) { sys_abort(1); } if (grx_open(640, 480, 8) < 0) { cprintf("GRX Err\n"); sys_abort(1); } /**** scenario ****/ grx_rect(XMIN-D-1, YMIN-D-1, XMAX+D+1, YMAX+D+1, 14); grx_text("Simulation of Random Flies", XMIN, YMENU+10, 13, 0); grx_text("SPACE crea una mosca TZE-TZE", XMIN, YMENU+20, 12, 0); grx_text("ESC exit to DOS" , XMIN, YMENU+30, 12, 0); /**** Il programma attende uno “spazio” per creare una mosca ****/ c = keyb_getch(BLOCK); /**** casuale ****/ seme = sys_gettime(NULL); srand(seme); do { if ((c == ' ') && (i < MAX_P)) { hard_task_default_model(m); hard_task_def_ctrl_jet (m); hard_task_def_arg (m, (void *)i); hard_task_default_model(m) hard_task_def_wcet (m, fly_wcet); hard_task_def_ctrl_jet(m) hard_task_def_mit fly_period); Valori di(m,default per il modello Model (periodic Se chiamata il Kernel può chiedere hard_task_def_group (m, FLYGROUP); task, altri= 0). informazioni per il task. hard_task_def_usemath (m); pid = task_create("fly", fly, &m, NULL); if (pid ==hard_task_def_arg(m,a) NIL) { grx_close(); Setta un void * argomento passato al task. Il perror(“Non è possibile creare la mosca"); valore di default è NULL. sys_abort(1); } task_activate(pid); hard_task_def_wcet(m,w)i++; Setta il Worst Case Execution } Time a w. c = keyb_getch(BLOCK); hard_task_def_mit(m,p) Setta il Minimo tempo di interarrivo (MIT) del hard_task_def_group(m,g) } while (c != ESC); modello p. =1 Setta il gruppo dei task g. Nel nostro caso ( perché hard). sys_end(); hard_task_def_usemath(m) return 0; Dichiara che il task usa un puntatore aritmetico } a float. /*--------------------------------------------------------------*/ ANALISI DEL FILE: initfile.c File di inizializzazione del sistema Sono 2 funzioni che servono ad inizializzare il sistema. Queste funzioni registrano i seguenti livelli: livello EDF (Earliest Deadline First) livellp RR (Round Robin) livello CBS (Costant Bandwidth Server) livello Dummy Possono accettare questi modelli di task: HARD_TASK_MODEL SOFT_TASK_MODEL NRT_TASK_MODEL IL TICK è settato a 0 Inizio del codice: initfile.c #include "kernel/kern.h" #include "modules/edf.h" #include "modules/cbs.h" #include "modules/rr.h" #include "modules/dummy.h" #include "modules/sem.h" #include "modules/hartport.h" #include "modules/cabs.h" Port: task per scambiare messaggi #include "drivers/keyb.h" /*+ sysyem tick in us +*/ #define TICK 0 /*+ RR tick in us +*/ #define RRTICK 10000 TASK __init__(void *arg) { struct multiboot_info *mb = (struct multiboot_info *)arg; KEYB_PARMS kparms = BASE_KEYB; Alla fine di ogni modulo di schedulazione, viene creato e attivato un task. Il corpo di questo task è generalmente chiamato __init__(), e provvede all’inizializzazione dei più comuni device usati, come ad es. la tastiera. HARTPORT_init(); keyb_def_ctrlC(kparms, NULL); keyb_def_map(kparms,itaMap); KEYB_init(&kparms); __call_main__(mb); return (void *)0; } Quando un sistema parte, una delle cose che bisogna fare prima di entrare nel modello multitask è inizializzare le risorse e le tecniche di schedulazione che verranno usate dalle applicazioni. Per fare ciò il kernel chiama la funzione __kernel_register_levels__. La funzione ritorna un valore di tick (in microsecondi) che è il tempo che sarà usato per programmare l’interrupt periodico del PC. Tipi di valori di ritorno vanno da 250 a 2000 ms. TIME __kernel_register_levels__(void *arg) { struct multiboot_info *mb = (struct multiboot_info *)arg; EDF_register_level(EDF_ENABLE_ALL); CBS_register_level(CBS_ENABLE_ALL, 0); RR_register_level(RRTICK, RR_MAIN_YES, mb); dummy_register_level(); SEM_register_module(); CABS_register_module(); return TICK; } FINE ENNA – 18 giugno 2003