Análisis de Buffer Cache

Anuncio
Análisis de Buffer Cache
• Ubicación en el sistema operativo.
SYSTEM STRUCTURE
Other application programs
nroff
cpp
who
a.out
Kernel
comp
cc
sh
date
Hardware
as
wc
Id
vi
Other
ed
grep
programs
application
Lower Level File System Algorithms
namei
alloc free
ialloc ifree
iget iput bmap
buffer allocation algorithms
getblk brelse bread breads bwrite
Diagrama de bloque del Kernel del Sistema
user programs
libraries
trap
User Level
Kernel Level
system call interface
file subsystem
buffer cache
process
inter-process
comunication
control
scheduler
subsystem
memory
management
character
block
device drivers
Kernel Level
Hardware Level
hardware control
hardware
Process States and Transitions
user
running
1
sys call
or interrupt
kernel
running
return
Interrupt,
interrupt
return
2
schedule
process
sleep
asleep
4
wakeup
3
context switch
permissible
• Los procesos van a dormir cuando esperan la
ocurrencia de algún evento.
• Ejemplo :
- Parte de un proceso que espera por un recurso :
while(buffer locked)
sleep( hasta buffer unlocked);
set buffer locked; /* lo toma y pone candado */
......
- Parte de un proceso que libera un recurso de uso
exclusivo :
......
set buffer unlocked;
wakeup ( a los que esperan por buffer unlocked);
.....
Multiple Processes Sleeping on a Lock
time
Proc A
Proc B
Proc C
Buffer locked
Sleeps
Buffer locked
Sleeps
Buffer is unlocked
Ready to run
Buffer locked
Sleeps
Wake up all sleeping procs
Ready to run
Ready to run
Runs
Buffer unlocked
Lock buffer
Sleep for arbitrary
reason
Runs
Buffer locked
Sleep
Ready to run
Runs
Buffer locked
Sleep
Wakes up
Unlocks Buffer
Wake up all sleeping procs
Context switch, eventually
Ready to run
Buffer cache
(escondite, oculto)
• Estructura en memoria primaria, para minimizar el
acceso a discos.
• El kernel no lee o escribe directamente a disco.
• Se llama también pool de buffers (grupo a se
compartido)
buffer de
proceso
pool de buffer
disco
• Se intenta mantener el mayor tiempo posible
"buenos datos" en el cache.
• Se posterga la escritura física disco, lo mayor
que sea posible.
• También se intenta predecir lecturas (precache) para cargar con datos que serán
ocupados más adelante.
• Se emplear un header y una zona de memoria
para los datos.
número lógico
Estado
Puntero a datos
identifica unívocamente
una porción del disco
apunta al buffer propiamente tal (*)
}
}
cola de colisiones en tabla de hash
lista de libres
• (*) aquí se copia, en memoria, un bloque del
disco
Estado
• Se puede estar locked o unlocked (ocupado o
libre).
• Datos válidos.
• Delayed - write (está marcado como viejo ).
• El kernel está leyendo o escribiendo este
buffer.
• Un proceso está esperando que este buffer
quede unlocked.
Algorithm for Buffer Allocation
Algorithm getblk
input: file system number
block number
output: locked bufffer that can now be used for block
{while (buffer not found)
{
if (block in hash queue)
{
if (buffer busy ) /* scenario 5 */
{
sleep (event buffer becomes free);
continue /* back to while loop */
}
mark buffer busy /* scenario 1*/
remove buffer from free list;
return buffer;
}
else
{
/* block not on hash queue */
if (there are no buffers on free list ) /* scenario 4 */
{
sleep ( event any buffer become free );
continue;
/* back to while loop`*/
}
remove buffer from free list;
if (buffer marked for delayed write) { /*scenario 3 ( se
marca como viejo) */
asynchronous write buffer to disk;
continue;
/* back to while loop */
}
/* scenario 2 -- found a free buffer */
remove buffer from old hash queue;
put buffer onto new hash queue;
return buffer;
}
}
}
/*** Fin del algoritmo ***/
Algorithm for Releasing a Buffer
algorithm brelse
input: locked buffer
output: none
{
wakeup all procs; event, waiting for any buffer to become free;
wakeup all procs; event, waiting for this buffer to become free;
raise processor execution level to block interrupts:
if (buffer contents valid and buffer not old)
enqueue buffer at end of free list
else
enqueue buffer at beginning of free list
lower processor execution level to allow interrupts;
unlock (buffer);
}
Algorithm for Writing a Disk Block
algorithm bwrite
/* Block write */
input: buffer
output: none
{
initiate disk write;
if ( I/O synchronous )
{
sleep( event I/O complete );
release buffer (algorithm brelse);
}
else if ( buffer marked for delayed write)
mark buffer to put at head of free list;
}
• En write asincrónico, se inicia la
escritura, pero no se espera que la
operación se complete.
• En escritura asincrónica, el driver de
disco, interrumpe invocando a brelse.
Algorithm for Reading a Disk Block
algorithm bread
/* block read */
input : file system block number
output: buffer containing data
{
get buffer for block (algorithm getblk);
if ( buffer data valid)
return (buffer):
initiate disk read;
sleep( event disk read complete );
return ( buffer );
}
• El proceso que lee un bloque : llama a bread
i) Obtiene a través de getblk un buffer locked
ii) En caso que deba leer desde disco, va a
dormir. Es despertado por el driver de disco.
iii) Debe liberar bloque cuando ya no lo
necesita.
Algorithm for Block Read Ahead
(Pre Cache )
algorithm breada
/* block read and read ahead */
input: (1)
file system block number for inmediate read
(2)
file system block number for asynchronous read
output: buffer containing data for inmediate read
{
if ( first block not in cache )
{
get buffer for first block (algorithm getblk);
if (buffer data not valid )
initiate disk read;
}
if ( second block not in cache )
{
get buffer for second block (algorithm getblk);
if (buffer data valid )
release buffer ( algorithm brelse );
else
initiate disk read;
/* (****) */
}
if ( first block was originally in cache )
{
read first block (algorithm bread);
return buffer;
}
sleep (event first buffer contains valid data);
return (buffer);
}
• (****) En escritura asincrónica el driver de disco
debe liberar el recurso (con brelse) una vez
completa la operación.
getblk(4)
• Scenario 1 in Finding a Buffer : buffer on hash queue
a) Search for Block 4 on First Hash Queue
hash queue headers
blkno 0 mod 4
........
28
4
64
blkno 1 mod 4
........
17
5
97
blkno 2 mod 4
........
98
50
10
blkno 3 mod 4
........
3
35
99
freelist header
•
•
•
•
Está en hash
Si está unlocked: lo toma colocando locked.
Lo remueve de los libres
Retorna buffer locked
b) Remove Block 4 from Free List
hash queue headers
blkno 0 mod 4
........
28
4
64
blkno 1 mod 4
........
17
5
97
blkno 2 mod 4
........
98
50
10
blkno 3 mod 4
........
3
35
99
freelist header
• Al colocar locked: Impide a otros procesos,
que lo requieran, que puedan avanzar en
modo kernel. Si intentan accesarlo deben
dormir.
• Nota : se usa hash abierto. Las colisiones se
resuelven en una lista doblemente enlazada
circular. (permite pasar elementos a otras
colas )
getblk(18)
• Second Scenario for Buffer Allocation
a) Search for Block 18: Not in Cache
hash queue headers
blkno 0 mod 4
........
28
4
64
blkno 1 mod 4
........
17
5
97
blkno 2 mod 4
........
98
50
10
blkno 3 mod 4
........
3
35
99
freelist header
• No está en cache, ya que no está en tabla de hash
• Se remueve el primero de lista de libres.
• Si no está marcado para escritura postergada, lo marca
ocupado (locked).
• Lo remueve de antigua posición en tabla de hash (si es
necesario)
• lo coloca en posición correcta
b) Remove First Block from Free List, Assign to 18
hash queue headers
blkno 0 mod 4 ........
28
4
64
blkno 1 mod 4 ........
17
5
97
blkno 2 mod 4 ........
98
50
10
blkno 3 mod 4 ........
freelist header
35
99
18
getblk(18)
• Third Scenario for Buffer Allocation
a) Search for Block 18, Delayed Write Blocks on
Free List
hash queue headers
blkno 0 mod 4 ........
28
blkno 1 mod 4 ........
17
blkno 2 mod 4 ........
blkno 3 mod 4 ........
delay
freelist header
4
64
5
97
98
50
10
3
35
99
delay
• No está en hash, por lo tanto no está en cache.
• Hay bloques libres. Remueve los marcados para
escritura postergada y los envía a escribir. Luego se
los inserta en la cabeza. (**).
• Se continua, hasta llegar a uno libre :
• Se lo remueve de la lista.
• Lo marca ocupado.
• Remueve de posición en tabla de hash (si es
necesario).
• lo coloca en posición correcta
b) Writing Blocks 3,5, Reassign 4 to 18
hash queue headers
blkno 0 mod 4 ........
28
blkno 1 mod 4 ........
17
blkno 2 mod 4 ........
blkno 3 mod 4 ........
writing
freelist header
64
5
97
98
50
10
3
35
99
writing
18
• Nota :
Lista de libres :
se insertan
se consumen
(cuando
son liberados)
cabeza
1
2
3
(**)
Doble cola : operaciones en ambos extremos
Cola simple
• Si se usa uno, no puede volver a emplearse hasta que
todos los demás hayan sido usados más
recientemente. (LRU, least recently used)
getblk(18)
• Fourth Scenario for Buffer Allocation
Search for Block 18, Empty Free List
hash queue headers
blkno 0 mod 4 ........
28
4
64
blkno 1 mod 4 ........
17
5
97
blkno 2 mod 4 ........
98
50
10
blkno 3 mod 4 ........
3
35
99
freelist header
• No está en hash, por lo tanto no está en
cache.
• No hay buffer en la lista de libres, por lo
tanto va a dormir.
• Debe esperar a que otro proceso invoque a
brelse.
Race for Free Buffer
time
Process A
Process B
Cannot find block b
on hash queue
No buffers on free list
Sleeps
Cannot find block b
on hash queue
No buffers on free list
Sleeps
Somebody frees a buffer: brelse
Takes buffer from free list
Assign to block b
• Contienda por un buffer libre :
Luego de despertar, debe volver a buscar, esto
soluciona carreras entre procesos para adquirir
un bloque. Pero puede producir starvation
(inanición)
getblk(18)
• Fifth Scenario for Buffer Allocation
Search for Block 99, Block Busy
hash queue headers
blkno 0 mod 4 ........
28
4
64
blkno 1 mod 4 ........
17
5
97
blkno 2 mod 4 ........
98
50
10
blkno 3 mod 4 ........
3
35
99
busy
freelist header
• Está en hash, pero ocupado.
• Luego de despertar debe volver a buscar.
Race for a Locked Buffer
time
Proc A
Proc B
Proc C
Allocate buffer
to block b
Lock buffer
Initiate I/O
Sleep until I/O done
Find block b
on hash queue
Buffer locked, sleeps
Sleep waiting for
any free buffer
(scenario 4)
I/O done, wake up
brelse() : wake up others
Get buffer previously
assigned to block b
reassign buffer to block b
buffer does not contain
block b
start search buffer
Sistema de Archivos
( nivel usuario)
(nivel biblioteca)
• En un nivel abstracto un programador requiere abrir
un archivo, por su nombre, antes de escribir o leer
en él.
• fp = fopen(nombre,modo)
nombre lógico,
nombre interno, modo : "r", "w", "a"
• c=getc(fp)
• putc(c,fp)
• fclose(fp)
• fscan ( fp, control, arg1, arg2, .....);
• fprintf ( fp, control, arg1, arg2, .....);
• fgets ( línea, MAXLINE, fp );
• fputs ( línea, fp );
• ungetc ( c, fp);
• fp es puntero a estructura de tipo FILE :
FILE *fopen(), *fp;
• se requiere esta declaración en una función que
manipule archivos.
• Las funciones anteriores, algunas son macros, están
definidas en el archivo estándar stdio.h .
• Por esta razón, debe plantearse, previo a su uso :
#include <stdio.h>
• Buscar en : /usr/include/stdio.h
Observaciones :
• fopen :
- Si se abre archivo que no existe, para escribir o
agregar al final, se crea si es posible.
- Si se abre archivo existente para escritura, se
sobreescribe.
- Si se abre para lectura un archivo que no existe, se
produce un error. También si no se tiene permisos, o
si por alguna razón no se puede crear, abrir, leer o
escribir se produce error, retorna puntero : NULL
(definido en stdio.h)
• getc :
- Retorna el siguiente caracter, EOF al final del
archivo.
• stdin, stdout, stderr :
- Son punteros a archivos predefinidos (son
constantes), normalmente el terminal del
usuario.
• fclose :
- flush ("tirar la cadena") el buffer del usuario.
- Pasa zona de memoria del usuario al sistema
operativo.
- Permite reusar el puntero a archivo.
• exit( entero ):
- Rutina estándar de biblioteca, que provee un
valor de retorno al programa. (error level en
DOS)
- Por convenio valor 0 implica desarrollo
normal, diferente de 0 avisa all ambiente e
externo que se produjo situación anormal.
- exit llama a fclose para cada archivo abierto,
y luego invoca a _exit , que produce término
inmediato sin salvar contenido de buffers
(flushing)
• Ver 7.7 y 7.8 en K.R. cat, fgets, fputs.
Implementación Bibiloteca
Llamados al sistema
•
•
•
•
•
•
•
•
n_read = read ( fs, buf, n);
n_write = write ( fs, buf, n);
fd = open (nombre, modo);
fd = creat (nombre, permisos);
close (fd);
unlink ( nombre );
borra del directorio
lseek (fd, offset, origen );
fd entero descriptor del archivo, describe con un
número un archivo en el sistema.
Observaciones :
• buf es el buffer de usuario
char buf [ BUFSIZE ] ;
• En lectura, se retorna número actual de bytes
transferidos. Puede ser menor que n ( nº
solicitado). Retorno
indica fin de archivo.
Retorno -1 indica error de algún tipo.
• En escritura, se retorna número de bytes
transferidos. Si no es igual al solicitado es
condición de error.
• n puede ser 1 (se denomina "caracter a caracter " o
unbuffered )
• n puede ser un bloque de cache (o físico). Este
valor está en stdio.h : BUFSIZ
• Discusión tamaño buffer : Pike, Kernighan pág.
203.
• Ver implementación de copy K.R. 8.2
getchar (unbuffered) K.R. 8.2
getchar (buffered) K.R. 8.2
• open : retorna descriptor de archivo; -1 si no puede
abrir . modo : 0 read; 1 write ; 2 read and write
• creat : permisos en octal
rwx dueño
0755
rx
grupo
rw
0644
rx
otros
r
r
- retorna -1 si no puede crear
- Si existe, lo deja de largo cero
- Un archivo recién creado, queda abierto para
escritura (independiente de permisos) K.R. 8.3
• lssek : - Acceso aleatorio
- Se posiciona dentro del archivo. ( se
prepara para leer o escribir)
- Retorna en long, la posición corriente. Si
falla -1.
offset
offset
origen = 0
offset
origen = 2
origen = 1
posición corriente
• Ejemplos : K. R. 8.4
• Ejemplos de programas con llamados al sistema :
cp
K.R. 8.3 ; K. Pike : pág. 206 y 207
• Estructura FILE :
_ptr
_cnt
buffer
_base
_flag
corriente
_fd
• _cnt : indica los caracteres que quedan
• get :predecrementa _cnt
Si es -1, setea EOF
Toma caracter corriente
Posiciona _ptr en siguiente caracter.
• _flag :
octal
reading 01
writing 02
unbuffered 04
buffer asignado 010
EOF 020
ERROR 040
• Tabla descripción de archivos de usuario :
fd
0
1
2
3
stdin
stdout
stderr
tipo FILE
_NFILE-1
_oib
#define _BUFSIZE 512
#define _NFILE 20 /* #files that can be handled */
typedef struct _iobuf {
char
*_ptr; /* next caracter position */
int
_cnt;
/* number of caracters left */
char
*_base; /* location of buffer */
int
_flag;
/* mode of file access */
int
_fd;
/* file descriptor */
} FILE ;
extern FILE _iob[_NFILE];
#define stdin
(&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
#define
#define
#define
#define
#define
#define
#define
#define
_READ 01
_WRITE
_UNBUF
_BIGBUF
_EOF 020
_ERR 040
NULL 0
EOF (-1)
/* file open for reading */
02
/* file open for writing */
04
/* file is unbuffered */
010
/* big buffer allocated */
/* EOF has occurred on this file */
/* error has occurred on this file */
________________________________________________
FILE -iob[_NFILE = {
( NULL, 0, NULL, _READ, 0), /* stdin */
( NULL, 0, NULL, _WRITE, 1), /* stdout */
( NULL, 0, NULL, _WRITE | _UNBUF , 2), /* stderr */
};
#include <stdio.h>
#define PMODE0644
/* R/W for owner; R for others */
FILE *fopen(name,mode) /* open file, return file ptr */
register char *name, *mode;
{ register int fd;
register FILE *fp;
if (*mode !='r' && *mode !='w' && *mode != 'a' ) {
fprintf (stderr, "illegal mode %s opening %s \n",mode,
name);
exit(1);
}
for (fp = _iob; fp < _oib + _NFILE; fp ++)
if (( fp -> _flag & (_READ | _WRITE )) = = 0)
break;
if ( fp > _oib + _NFILE) /* no free slots */
return (NULL);
if (*mode = = 'w') /* access file */
fd = creat(name, PMODE);
else if ( *mode = = 'a' ) {
if (( fd = open(name,1))= = -1)
fd = creat(name,PMODE);
lseek( fd, 0L ,2 );
} else
fd = open (name, 0);
if ( fd = = -1 ) /* couldn't access name */
return(NULL);
fp -> _fd = fd ;
fp -> _cnt = 0 ;
fp -> _base = NULL;
fp -> _flag & = * ( _READ | _WRITE ) ;
fp -> _flag |= (*mode = = 'r' ) ? _READ : _WRITE;
return(fp);
} /*** Fin del Programa ***/
#define getc(p) (--(p)->_cnt >=0 ? *(p) -> _ptr++ \
& 0377 : _fillbuf(p))
#define getchar() getc(stdin)
#define putc(x,p)
(--(p)->_cnt >=0 ? *(p) -> _ptr++ \
= (x) : _flushbuf((x)p))
#define putchar(x)
putc(x,stdout)
#include <stdio.h>
_fillbuf(fp)
/* allocate and fill input buffer */
register FILE *fp;
{ static char smallbuf[_NFILE]; /* for unbuffered I/O */
char *calloc();
if (( fp -> _flag & _READ )= = 0 || ( fp -> _flag &(_EOF |
_ERR)) !=0 )
return(EOF);
}
while ( fp -> _base = = NULL) /* find buffer space */
if ( fp -> _flag & _UNBUF) /* unbuffered */
fp->_base = &smallbuf[fp -> _fd];
else if (( fp -> _base=calloc(_BUFSIZE,1))= =NULL)
fp->_flag |= _UNBUF; /* can't get big buf */
else
fp->_flag |= _BIGBUF; /* got big one */
fp->_ptr = fp->_base;
fp->_cnt = read(fp->_fd, fp->_ptr, fp->_flag &_UNBUF ? 1 :
_BUFSIZE;
if (--fp->_cnt <0 ) {
if (fp->_cnt= = -1)
fp->_flag |= _EOF;
else
fp->_flag |= _ERR;
fp->_cnt=0;
return(EOF);
}
return(*fp->_ptr++ & 0377); /* make char positive*/
/*** Fin del Programa ***/
Descargar