1.10: gestione dell'i/o - vito asta · 1.10.4 hardware di i/o (cont.) funzioni realizzate...

35
1.10.1 1.10: Gestione dell'I/O Hardware di I/O Interfaccia applicativa Sottosistema di I/O del Kernel Block buffer cache Scenario operativo (dalla richiesta di I/O all'operazione hardware) Prestazioni

Upload: others

Post on 29-May-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

1.10.1

1.10: Gestione dell'I/O● Hardware di I/O

● Interfaccia applicativa

● Sottosistema di I/O del Kernel

● Block buffer cache

● Scenario operativo (dalla richiesta di I/O all'operazione hardware)

● Prestazioni

1.10.2

Hardware di I/O● Enorme varietà di dispositivi di I/O

● Concetti di base:

– Controller (o host adapter)● Microprocessore dedicato + firmware + RAM privata

– Porta di I/O (registro del controller; punto di connessione e di comunicazione, visibile sul bus di I/O)

– Bus di I/O (es. PCI bus, ISA bus etc.)● Bus = insieme di segnali su fili comuni + un protocollo di interazione

● L'accesso ai dispositivi di I/O si realizza tramite le porte di I/O● Le porte hanno

– Indirizzi di I/O (logici e fisici a un tempo ­  non sono traslati dalla MMU), usati da istruzioni specifiche di I/O

● es., 80x86:             b = in(addr);        out(b, addr);– Indirizzi mappati in memoria (memory­mapped I/O), usati dalle normali 

istruzioni di accesso alla memoria

1.10.3

Hardware di I/O (Cont.)● Schema hardware del bus di un PC:

1.10.4

Hardware di I/O (Cont.)● Funzioni realizzate tramite le porte di I/O del controller:

– Inviare comando al dispositivo

– Leggere stato del dispositivo

– Inviare dati al dispositivo

– Leggere dati dal dispositivo.

● Registri tipici di un controller (ciascuno da 1 a 4 byte):

– CSR ­­  Control (write) and Status (read) Register

– DATA (in + out)

● Segnali (sul bus di I/O) per generare interrupt alla CPU

● Circuiteria e segnali sul bus per gestire trasferimenti DMA

– Spesso esiste un apposito circuito, il DMAC (DMA Controller), con un certo numero di canali DMA che possono essere utilizzati da vari controller di periferica

1.10.5

Hardware di I/O (Cont.)● Rappresentazione possibile dei registri di un controller (memory­

mapped I/O):

struct device {

char CSR; /* lettura: status; scrittura: control */char DATA; /* data in / out */

};

struct device *dev = CONTROLLER_START_ADDRESS;● Tre modalità di interazione/sincronizzazione CPU ­  periferica:

– Polling● Preferibile se il tempo risposta dispositivo è breve rispetto al tempo 

commutazione processi (stampanti veloci con grosso buffer)– Interrupt (byte a byte)

● Il tempo di risposta del dispositivo è lungo (linee seriali, connessioni WAN)

– DMA + interrupt● Trasferimento grossi volumi di dati ad alta velocità (I/O nastri, dischi).

1.10.6

Polling● Polling: basato su interazione continua attraverso il registro CSR

– Bit command-ready e write, nel Control Register– Bit busy e error, nello Status Register

● Scenario (caso di una scrittura):– la CPU determina stato del dispositivo: testa continuamente il bit busy nel 

registro status per aspettare che il dispositivo sia pronto all'I/O  (loop di busy­wait)

while(dev->CSR & SR_BUSY);

– alza il bit  write, invia valore in data-out; quindi alza il bit command-ready (c'è un comando pronto nel CSR, da eseguire)

dev->CSR |= CR_WRITE;dev->DATA = value;dev->CSR |= CMD_READY;

– il controller alza immediatamente il bit  BUSY, legge il CSR e trova il comando write; legge allora il valore dal registro DATA e lo invia alla periferica fisica

– al termine, il controller abbassa il bit command-ready, posiziona il bit error a 0 nel CSR, abbassa il bit  busy (pronto ad accettare un nuovo comando).

1.10.7

Interrupt● Segnale di Interrupt Request per generare interrupt alla CPU, azionato 

dalla periferica.

● Scenario: come per il polling, ma

– Non c'è il ciclo continuo iniziale (la CPU interviene solo in seguito a un interrupt di fine operazione precedente)

– al termine, il controller (oltre alle altre operazioni) alza la linea di Interrupt Request.

● La CPU salva il contesto attuale e passa il controllo a una routine di servizio dell'interrupt (interrupt handler), ad un indirizzo fisso in memoria– Vettore di interrupt (interrupt vector) per il dispatching dell'interrupt allo 

handler giusto.

● Lo interrupt handler serve il dispositivo, quindi esegue una istruzione di "ritorno dall'interrupt"

1.10.8

Interrupt (Cont.)● Interrupt:

– Mascherabili, per ignorare o ritardare alcuni interrupt● Meccanismo basato sulla priorità degli interrupt (rispetto alla priorità 

hardware della CPU)– Non mascherabili (solo alcuni, per situazioni di particolare gravità)

● Il meccanismo degli interrupt è usato anche per eccezioni, trap e chiamate di sistema.

1.10.9

Interrupt (Cont.)● Assegnazione degli interrupt in un PC:

1.10.10

Interrupt (Cont.)

Ciclo di I/O ad interrupt: 

1.10.11

DMA● Utilizzato per evitare l'I/O programmato (interazione con registri CSR e 

DATA per ciascun byte o parola da trasferire) per trasferimenti di dati grossi e/o veloci (ad es. per I/O su disco).

● Attraverso il controller di DMA, cortocircuita la CPU per trasferire dati direttamente tra il dispositivo di I/O e la memoria.

● Rappresentazione possibile dei registri di un controller (memory­mapped I/O):

struct device {

char CSR; /* lettura: status; scrittura: control */char DATA; /* data in / out */int ADDR; /* indirizzo iniziale di RAM da/a cui trasferire dati */int COUNT; /* contatore dei byte da trasferire */

};

struct device *dev = CONTROLLER_START_ADDRESS;

1.10.12

DMA● Scenario (caso di una lettura):

– la CPU carica il registro count  col numero di byte da trasferire, e il registro addr con l'indirizzo iniziale del buffer di memoria in RAM

dev->COUNT = byte_count;dev->ADDR = buffer_address;

– alza il bit  read, nel registro control; quindi alza il bit command-ready (c'è un comando pronto nel CSR, da eseguire)

dev->CSR |= CR_READ;dev->CSR |= CMD_READY;

– il controller alza immediatamente il bit  busy, legge il CSR e trova il comando read; legge dai registri  count e addr i valori specificati; con l'ausilio del controller di DMA, trasferisce il numero di byte specificati a partire dall'indirizzo specificato

– al termine, il controller abbassa il bit command-ready, posiziona il bit error a 0 nel CSR, abbassa il bit  busy (pronto ad accettare un nuovo comando), e alza la linea di Interrupt Request per segnalare la fine dell'operazione e la disponibilità dei dati in memoria.

1.10.13

DMA (Cont.)● Sei passi base per la realizzazione di un trasferimento in DMA:

1.10.14

Interfaccia Applicativa di I/O● Le chiamate di sistema orientate all'I/O tendono a virtualizzare i vari dispositivi, 

raggruppandoli in classi generiche e offrendo al programmatore un'interfaccia quanto più possibile omogenea

● Lo strato dei device driver  (device driver layer) nasconde al Kernel le differenze tra diversi controller.

●  Molti S.O. forniscono una chiamata di sistema scappatoia (escape system call), per passare comandi specifici da un'applicazione a un device driver; questi comandi sono definiti dal driver (p.es. un comando FORMAT per formattare dischi rigidi o floppy disk)– Unix: ioctl(2) ­­   ioctl(fd, cmd, argp);

● fd = file descriptor dello special file (periferica)● cmd = una costante, definita nel device driver, che specifica un comando● argp = puntatore a una struttura di dati con gli argomenti relativi a cmd.

● Possibili categorie di dispositivi:– A flusso di caratteri, a blocchi di dati, orientati alle reti– Sequenziali o ad accesso casuale– Lettura­scrittura, sola lettura, sola scrittura– Condivisi o ad uso esclusivo

1.10.15

Interfaccia Applicativa di I/O (Cont.)● Unix/Linux realizzano una completa virtualizzazione delle periferiche, 

che sono viste come file; pertanto la programmazione di base di una periferica è identica a quella di un normale file su disco.

● Periferica = special file

– L'inode contiene tre informazioni essenziali:● Tipo file (special file di tipo carattere, blocco)● MDN (Major Device Number), mdn (Minor Device Number)

– MDN individua una categoria di periferiche, gestite da uno stesso device driver

– mdn individua la specifica unità della categoria data.

1.10.16

Dispositivi a Carattere, a Blocco, di Rete● I dispositivi a blocco (block devices) includono dischi e unità a nastro

– I comandi includono read(), write(), seek()

– È possibile la mappatura in memoria di file (es. Linux)

– Unix: accessibili in modo diretto (raw I/O, raw mode), cioè con trasferimento diretto da periferica a buffer utente, o attraverso una cache di Kernel (block buffer cache)

● I dispositivi a carattere (character devices) includono tastiere e schermi, mouse, porte seriali– I comandi includono get(), put()

● In Unix, continuano a chiamarsi read() e write()– Per i dispositivi di tipo tty (linea utente), l'edizione di linea (line editing) può 

essere supportata a livello di strati di libreria utente, o di sottosistemi nel Kernel, chiamati dai device driver (è il caso di Unix).

1.10.17

Dispositivi a Carattere, a Blocco, di Rete (Cont.)● I dispositivi di rete sono differenti dagli altri tipi visti, ed hanno quindi la 

loro specifica interfaccia– Unix: formalmente sono dispositivi di tipo carattere (tipo file nell'inode)

● Non vengono quasi mai utilizzati in modo diretto da applicazioni a livello utente: si trovano in basso ad una pila di moduli funzionali

● Unix and Windows/*  includono il supporto per una interfaccia socket (socket interface), interfaccia di programmazione de facto standard– Insieme di primitive, implementate come chiamate di sistema o talvolta 

come API di libreria

– Separa i protocolli di rete dagli aspetti di uso operativo delle reti

disp. di rete

protocolli

interf. di prog.  

appl. utente  

Device driver e/o modulidel Kernel  

1.10.18

Supporto del Kernel● A seconda del tipo di dispositivo, il Kernel può offrire:

– Nessun supporto● es. Unix: interfaccia grafica X.11 ­  interamente gestita a livello 

applicazione utente (previa autorizzazione ad accedere a certe porte di I/O)

– Supporto limitato alla porta di I/O● es. Unix: linee seriali (/dev/ttyS0, etc.) ­  il Kernel fornisce un device 

driver per letture e scritture di caratteri, ma nessun supporto per gestione modem, stampanti seriali, mouse seriali etc.

– Supporto totale● es.: dischi, interfacce di rete ­  il Kernel fornisce un device driver e uno o 

più moduli che si occupano in toto della gestione della periferica e della strutturazione e gestione dei dati.

1.10.19

Supporto del Kernel (Cont.)

● N.B. ­  tra l'applicazione e il Kernel ci può essere uno strato di librerie di sistema, a livello utente.

Applicazioni

Moduli sistema

Device driver

Periferica fisica

User level

Kernel

Hardware

1.10.20

Supporto del Kernel (Cont.)● Esempio ­  struttura del kernel di Linux:

1.10.21

Sottosistema di I/O del Kernel● In generale, il Kernel fornisce diversi servizi comuni per l'I/O, raggruppati 

 in un insieme di moduli funzionali che costituiscono il (sotto)sistema di I/O del Kernel:– Vista canonica delle periferiche ­  i device driver hanno come compito 

principale quello di  nascondere le peculiarità dei dispositivi, che rimangono circoscritti all'interno del driver, offrendo al resto del Kernel una "vista canonica" delle varie periferiche.

–  Scheduling dell'I/O ­  codice per ordinare in modo ottimale le richieste di I/O, attraverso code di dispositivo; disponibile come insieme di routine che possono esssere utilizzate dai device driver.

–  Bufferizzazione ­  memorizzare dati in memoria del kernel mentre vengono trasferiti

● per compensare differenze di velocità tra dispositivi hardware (es. tra disco e RAM, etc.)

● per compensare incompatibilità di dimensione di trasferimento (es. poter scrivere o leggere 10 byte a/da un file su disco).

– Caching ­  una memoria veloce che mantiene una copia dei dati delle periferiche

● Fondamentale per le prestazioni del sistema, e in particolare del file system: lo hit ratio della cache dei dischi è tipicamente dell'85%.

1.10.22

Sottosistema di I/O del Kernel (Cont.)–  Spooling ­  accumulare e gestire l'output per una periferica

● Necessario se il dispositivo può servire solo una richiesta alla volta (es., job di stampa)

● N.B. ­  in Unix, lo spooling di stampa è gestito con programmi a livello utente.

– Prenotazione di periferica ­  fornisce un accesso esclusivo ad una periferica● Chiamate di sistema per allocazione e  deallocazione, o apertura 

esclusiva● N.B. ­  pericolo di deadlock.

1.10.23

Sottosistema di I/O del Kernel (Cont.)● Sottosistema di I/O del Kernel Unix 4.3BSD:

1.10.24

Block Buffer Cache● Block buffer cache ­  sistema di caching delle operazioni di I/O di tutti i 

dispositivi di tipo blocco (in pratica, tutti i dischi). Comune a tutti gli Unix. Consiste (nel caso Unix classico) di

– Un insieme di blocchi di RAM, di dimensione pari a un multiplo (variabile) di blocchi logici di un file system

– Un array di strutture di controllo, denominate buffer header:  struct buf buf[], ciascuna identificata da una terna:

● (MDN+mnd) del dispositivo (membro b_dev)● Numero di blocco iniziale (del dispositivo) (b_blkno)

a cui si aggiungono l'indirizzo e dimensione del buffer associato (che può essere variabile) (b_addr, b_count)

● In Linux, la quantità di memoria dedicata alla cache varia dinamicamente, e tende a utilizzare tutta la memoria RAM disponibile (non reclamata dai processi o dal Kernel)

– In altri sistemi Unix, è determinata dinamicamente al momento del bootstrap (come frazione della memoria totale disponibile) e poi rimane costante.

1.10.25

Block Buffer Cache (Cont.)● I buffer header (o più brevemente buffer) per blocchi non attualmente in 

uso (cioè non interessati a operazioni di I/O pendenti) sono mantenuti in diverse liste collegate:

– Buffer usati recentemente, collegati in ordine LRU (LRU list)

– Buffer non usati recentemente, o senza un contenuto valido (AGE list)

– Buffer vuoti, senza memoria RAM associata (EMPTY list).

● Tutti i buffer in uso sono invece inseriti in una delle code di transazioni pendenti associate ai vari driver di dispositivo; tali code sono iniziate da un'apposita struttura struct iobuf (ce n'è almeno una per ogni driver): struct iobuf d_tab;

● Una richiesta di transazione è memorizzata nella stessa struct buf, precisando un ulteriore dato: il senso del trasferimento (membro b_flags, che vale B_READ o B_WRITE)

● I buffer (in uso o no) associati a blocchi di periferica sono mantenuti in un sistema di hash list, per rapidità di ricerca, mediante l'uso di un array di puntatori a buffer: struct hbuf hbuf[ ];

1.10.26

Block Buffer Cache (Cont.)● Per gestire queste liste, ogni struct buf ha due coppie di puntatori: b_forw, 

b_back (hash list) e av_forw, av_back (liste AGE, LRU, EMPTY; oppure lista delle transazioni pendenti di un driver).

struct buf{

int b_flags; /* B_READ or B_WRITE, etc. */struct buf *b_forw; /* headed by hbuf[] */struct buf *b_back; /* " */struct buf *av_forw; /* position on the free lists, */struct buf *av_back; /* if not B_BUSY */dev_t b_dev; /* major+minor device name */unsigned b_bcount; /* transfer count */caddr_t b_addr; /* core address */daddr_t b_blkno; /* first block # on device */...

};

1.10.27

Block Buffer Cache (Cont.)● Quando un blocco è richiesto da una periferica, viene cercato nella cache:

– Se il buffer corrispondente viene trovato, viene usato, senza bisogno di I/O fisico

– Altrimenti, viene scelto un buffer dalla AGE list, o se questa è vuota, dalla LRU list.

● Il buffer scelto viene "ribattezzato", cioè associato al nuovo blocco● Se il buffer ribattezzato contiene dati che devono essere scritti su disco, la 

scrittura non è più procrastinabile e viene avviata ora (in generale, le scritture vengono rimandate sempre all'ultimo momento).

● Vantaggi:

– Velocizzazione dell'I/O, data dalla cache

– Possibilità di leggere/scrivere in quantità arbitrarie

– Non è necessario bloccare in memoria processi interessati a operazioni di  I/O (il DMA è sempre indirizzato verso memoria del Kernel, non swappabile).

– Le operazioni di scrittura sono senza attesa: il sistema memorizza i dati nella cache, e restituisce immediatamente il controllo al processo. La scrittura effettiva avviene il più tardi possibile.

1.10.28

Block Buffer Cache (Cont.)struct hbuf  

struct buf 

struct iobuf  

hbuf[ ]  bhash(dev,blkno) 

LRU list

b_forw, b_back

av_forw, av_back

av_forw

N.B. ­  per ogni lista,  i puntatori tra strutture di inizio lista e ultimo elemento non sono mostrati;la AGE list non è mostrata.

d_tab   d_tab   d_tab  

1.10.29

Scenario Operativo● Per servire un processo che vuole leggere un insieme di dati da file su 

disco:

– Determinare la periferica che contiene il file– Traslare numero di blocco logico del file in numero di blocco del disco– Lettura fisica dei dati del blocco da disco in un buffer della block buffer cache– Mettere i dati a disposizione del processo richiedente– Restituire il controllo al processo.

1.10.30

Scenario Operativo (Cont.)● Processo che legge un insieme di dati da file su disco ­  caso Unix:

– Processo utente: ● chiamata alla funzione read()   trap ­  la CPU passa in System mode

– Kernel ­  codice di servizio della read():● Controlla legalità degli argomenti, e li passa al modulo di gestione dei file

– Modulo Kernel di gestione dei file:● Determina dispositivo che contiene il file: consultare la mount table● Trasla nome del file in rappresentazione interna: da path a inode ­  routine 

namei()  (al momento della open())● Determina il numero di blocco logico del file che contiene gli N byte richiesti 

dal processo utente● Trasla numero di blocco logico del file in numero di blocco del disco logico, 

blkno: routine  bmap()● Prende MDN, mdn del disco logico;● Routine bread(): seleziona un blocco della  block buffer cache, liberandolo 

se necessario (cioè se era occupato), e lo associa alla terna <MDN, mdn, blkno>;

1.10.31

Scenario Operativo (Cont.)● Prepara una struttura dati struct buf con la richiesta di I/O, inserendo in 

essa:– MDN, mdn– blkno– indirizzo RAM del blocco della Kernel cache (dove i dati dovranno 

essere scritti) e dimensione della richiesta, in byte– tipo operazione: B_READ  (lettura)

● Chiama la routine d_strategy() del device driver, passando come argomento la struttura dati preparata

– Device driver del disco:● Inserisce la struct buf  nella coda di richieste del driver, secondo l'algoritmo 

di scheduling del disco utilizzato;– Modulo Kernel di gestione dei file ­  routine bread():

● Attende il completamento dell'operazione: il processo va a dormire;

1.10.32

Scenario Operativo (Cont.)Più tardi, la richiesta viene servita, e i relativi comandi inviati al controller; al termine 

dell'operazione scatta  l'interrupt di fine DMA (dati disponibili).

– Device driver del disco, routine d_intr():● Controlla eventuali errori● Rimuove la struct buf dalla coda● Risveglia il processo interessato

– Scheduler di CPU:● Ridà la CPU al processo interessato all'I/O

– Modulo Kernel di gestione dei file ­  routine bread() (ora risvegliata):● Restituisce la struct buf, che ora punta ai dati nella block buffer cache

– Codice di servizio della read()● Copia gli N byte richiesti, dal blocco della cache nel buffer del processo 

utente (copia da memoria a memoria)● Esegue l'istruzione per terminare il codice di servizio della trap; la CPU torna 

in User mode– Processo utente: riprende il controllo.

1.10.33

Gestione degli Errori● Il S.O. può recuperare e gestire errori di vario tipo: periferica non 

disponibile (es. CD­ROM o floppy disk), errori di scrittura o di  lettura

– N.B. ­  quando è utilizzata la cache del Kernel per l'I/O su disco, Unix non può recuperare errori di scrittura: le scritture fisiche sono ritardate al massimo, e quando avvengono è tipicamente troppo tardi per notificare il processo interessato (che potrebbe aver già terminato, e quindi non esistere più).

● Molti S.O. ritornano un codice di errore (attraverso le chiamate di sistema) in caso di errore di I/O ­  es., Unix/Linux: errno– Se la chiamata di sistema fallisce, ritorna invariabilmente ­1 e la variabile 

esterna errno contiene un codice di errore specifico.

● I file di log di sistema memorizzano messaggi specifici sui problemi incontrati.

1.10.34

Prestazioni● L'I/O è un elemento di gran peso per le prestazioni globali di un sistema

– Impegna, oltre ai processori periferici, anche la CPU:● Codice dei moduli di I/O del Kernel● Codice dei device driver

– Context switch dovuti agli interrupt

– Copia di dati (da/a buffer utente, block buffer cache, RAM privata dei controller, etc.)

– Il traffico di rete può essere particolarmente pesante, per sua natura.

1.10.35

Prestazioni (Cont.)● Linee guida per migliorare le prestazioni:

– Ridurre il numero di context switch

– Ridurre le copie di dati

– Ridurre la frequenza degli interrupt, usando● Trasferimento di dati in grossi quantitativi alla volta● Controller intelligenti● Polling, ove opportuno (cioè ovunque i loop di busy­wait possono 

essere minimizzati)– Usare controller di DMA intelligenti per aumentare il numero di operazioni 

concorrenti (sfruttare al massimo il parallelismo del sistema)

– Implementare primitive direttamente in hardware, ovunque possibile

– Bilanciare bene (tuning del sistema) le prestazioni di CPU, memoria, bus, e I/O, per massimizzare il throughput globale: se uno di questi elementi è sovraccarico, gli altri restano parzialmente inattivi.