From 18598db8d7f2ea072ae8f77ffdbefad1384cbcae Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 16 Jun 2007 16:22:30 +0000 Subject: [PATCH] Correzioni varie, aggiunte not sui vantaggi di {{{poll}}} su {{{select}}} ed iniziata la trattazione di ''epoll''. --- fileadv.tex | 114 +++++++++++++++++++++++++++++++----------- listati/ppoll_means.c | 2 +- ringraziamenti.tex | 6 +-- sockctrl.tex | 10 ++-- 4 files changed, 94 insertions(+), 38 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index c3936d9..87e7bc1 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -170,8 +170,7 @@ effettuare una lettura,\footnote{per essere precisi la funzione ritorner accadere che \func{select} riporti il relativo file descriptor come leggibile, ma una successiva \func{read} si blocchi.} il secondo, \param{writefds}, per verificare la possibilità effettuare una scrittura ed il -terzo, -\param{exceptfds}, per verificare l'esistenza di eccezioni (come i dati +terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i dati urgenti \itindex{out-of-band} su un socket, vedi sez.~\ref{sec:TCP_urgent_data}). @@ -357,17 +356,6 @@ indica un'attesa indefinita, mentre un valore nullo comporta il ritorno immediato (e può essere utilizzato per impiegare \func{poll} in modalità \textsl{non-bloccante}). -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \includestruct{listati/pollfd.h} - \end{minipage} - \normalsize - \caption{La struttura \structd{pollfd}, utilizzata per specificare le - modalità di controllo di un file descriptor alla funzione \func{poll}.} - \label{fig:file_pollfd} -\end{figure} - Per ciascun file da controllare deve essere inizializzata una struttura \struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La struttura, la cui definizione è riportata in fig.~\ref{fig:file_pollfd}, @@ -381,6 +369,17 @@ tutto indipendenti da quelli in uscita (che vengono restituiti in \var{revents}) non è necessario reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a meno di non voler cambiare qualche condizione. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includestruct{listati/pollfd.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{pollfd}, utilizzata per specificare le + modalità di controllo di un file descriptor alla funzione \func{poll}.} + \label{fig:file_pollfd} +\end{figure} + Le costanti che definiscono i valori relativi ai bit usati nelle maschere binarie dei campi \var{events} e \var{revents} sono riportati in tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono @@ -444,11 +443,30 @@ valore nullo indica che si indica un errore nella chiamata, il cui codice viene riportato al solito tramite \var{errno}. +L'uso di \func{poll} consente di superare alcuni dei problemi illustrati in +precedenza per \func{select}; anzitutto, dato che in questo caso si usa un +vettore di strutture \struct{pollfd} di dimensione arbitraria, non esiste il +limite introdotto dalle dimesioni massime di un \itindex{file~descriptor~set} +\textit{file descriptor set} e la dimensione dei dati passati al kernel +dipende solo dal numero dei file descriptor che si vogliono controllare, non +dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor + set} può essere più efficiente di un vettore di strutture \struct{pollfd}, + qualora si debba osservare un solo file descriptor con un valore molto alto + ci si troverà ad utilizzare inutilmente un maggiore quantitativo di + memoria.} + +Inoltre con \func{select} lo stesso \itindex{file~descriptor~set} \textit{file + descriptor set} è usato sia in ingresso che in uscita, e questo significa +che tutte le volte che si vuole ripetere l'operazione occorre reinizializzarlo +da capo. Questa operazione, che può essere molto onerosa se i file descriptor +da tenere sotto osservazione sono molti, non è invece necessaria con +\func{poll}. + Abbiamo visto in sez.~\ref{sec:file_select} come lo standard POSIX preveda una variante di \func{select} che consente di gestire correttamente la ricezione dei segnali nell'attesa su un file descriptor. Con l'introduzione di una implementazione reale di \func{pselect} nel kernel 2.6.16, è stata aggiunta -anche una analoga funzione che svolga lo stesso ruolo per \func{poll}. +anche una analoga funzione che svolga lo stesso ruolo per \func{poll}. In questo caso si tratta di una estensione che è specifica di Linux e non è prevista da nessuno standard; essa può essere utilizzata esclusivamente se si @@ -489,13 +507,49 @@ puntatore ad una struttura \struct{timespec}, gli altri argomenti comuni con risultati illustrati in precedenza. -% TODO accennare a ppoll vedi articolo LWN http://lwn.net/Articles/176750/ +\subsection{L'interfaccia di \textit{epoll}} +\label{sec:file_epoll} + +\itindbeg{epoll} + +Nonostante \func{poll} presenti alcuni vantaggi rispetto a \func{select}, +anche questa funzione non è molto efficiente quando deve essere utilizzata con +un gran numero di file descriptor,\footnote{in casi del genere \func{select} + viene scartata a priori, perché può avvenire che il numero di file + descriptor ecceda le dimensioni massime di un \itindex{file~descriptor~set} + \textit{file descriptor set}.} in particolare nel caso in cui solo pochi di +questi diventano attivi. Il problema in questo caso è che il tempo impiegato +da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al +numero di file descriptor osservati, non a quelli che presentano attività. + +Quando ci sono decine di migliaia di file descriptor osservati e migliaia di +eventi al secondo,\footnote{il caso classico è quello di un server web di un + sito con molti accessi.} l'uso di \func{poll} comporta la necessità di +trasferire avanti ed indietro da user space a kernel space la lunga lista +delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si +aggiunge il fatto che la maggior parte del tempo di esecuzione sarà impegnato +ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo +per determinare quali di essi (in genere una piccola percentuale) sono +diventati attivi. In una situazione come questa l'uso delle funzioni classiche +dell'interfaccia dell'\textit{I/O multiplexing} viene a costituire un collo di +bottiglia che degrada irrimediabilmente le prestazioni. -%\subsection{L'interfaccia di \textit{epoll}} -%\label{sec:file_epoll} -% placeholder ... +Per risolvere questo tipo di situazioni è stata creata una nuova +interfaccia,\footnote{l'interfaccia è stata creata da Davide Libernzi, ed è + stata introdotta per la prima volta nel kernel 2.5.44, ma la sua forma + definitiva è stata raggiunta nel kernel 2.5.66.} detta \textit{epoll}, il +cui concetto fondamentale è quello di restituire solamente le informazioni +relative ai file descriptor osservati che presentano una attività, evitando +così tutti le problematiche appena illustrate. + + + + + +\itindend{epoll} % TODO epoll +% \section{L'accesso \textsl{asincrono} ai file} \label{sec:file_asyncronous_access} @@ -541,13 +595,11 @@ sar accesso ai file; per questo motivo Stevens chiama questa modalità \textit{signal driven I/O}. -In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select} -che, quando vengono usate con un numero molto grande di file descriptor, non -hanno buone prestazioni. % TODO aggiungere cenno a epoll quando l'avrò scritta - In tal caso infatti la maggior parte del loro tempo -di esecuzione è impegnato ad eseguire una scansione su tutti i file descriptor -tenuti sotto controllo per determinare quali di essi (in genere una piccola -percentuale) sono diventati attivi. +Questa è un'altra modalità di gestione I/O, alternativa all'uso di +\itindex{epoll} \textit{epoll}, che consente di evitare l'uso delle funzioni +\func{poll} o \func{select} che, come illustrato in sez.~\ref{sec:file_epoll}, +quando vengono usate con un numero molto grande di file descriptor, non hanno +buone prestazioni. Tuttavia con l'implementazione classica dei segnali questa modalità di I/O presenta notevoli problemi, dato che non è possibile determinare, quando i @@ -1016,7 +1068,7 @@ numero di file che sono cambiati. \index{file!inotify|)} - +% TODO inserire anche eventfd (vedi http://lwn.net/Articles/233462/) @@ -2083,8 +2135,8 @@ mappatura che gi \itindend{memory~mapping} -\subsection{L'I/O diretto fra file descriptor con \func{sendfile}} -\label{sec:file_sendfile} +\subsection{L'I/O diretto fra file descriptor} +\label{sec:file_sendfile_splice} Uno dei problemi @@ -2092,8 +2144,12 @@ NdA \href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html} {\texttt{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}} -% TODO documentare la funzione sendfile +% TODO documentare la funzione sendfile +% TODO documentare le funzioni tee e splice +% http://kerneltrap.org/node/6505 e http://lwn.net/Articles/178199/ e +% http://lwn.net/Articles/179492/ +% e http://en.wikipedia.org/wiki/Splice_(system_call) % i raw device diff --git a/listati/ppoll_means.c b/listati/ppoll_means.c index ac5d835..bf8f24c 100644 --- a/listati/ppoll_means.c +++ b/listati/ppoll_means.c @@ -1,5 +1,5 @@ sigset_t origmask; sigprocmask(SIG_SETMASK, &sigmask, &origmask); -ready = select(nfds, &readfds, &writefds, &exceptfds, timeout); +ready = poll(&fds, nfds, timeout); sigprocmask(SIG_SETMASK, &origmask, NULL); diff --git a/ringraziamenti.tex b/ringraziamenti.tex index 84d2aee..d852d17 100644 --- a/ringraziamenti.tex +++ b/ringraziamenti.tex @@ -32,9 +32,9 @@ GaPiL. In ordine rigorosamente alfabetico desidero citare: Infine, vorrei ringraziare il Firenze Linux User Group (FLUG), di cui mi pregio di fare parte, che ha messo a disposizione il repository CVS su cui era -presente la prima versione della Guida, lo spazio web e tutto quanto è -necessario alla pubblicazione della guida e Truelite Srl, che fornisce il -nuovo repository SVN ed il sistema di tracciamento dei sorgenti su +presente la prima versione della Guida, lo spazio web, e Truelite Srl, che +fornisce il nuovo repository SVN, tutto quanto è necessario alla pubblicazione +della guida ed il sistema di tracciamento dei sorgenti su \href{http://gapil.truelite.it/sources} {\texttt{http://gapil.truelite.it/sources}}. diff --git a/sockctrl.tex b/sockctrl.tex index 9c8c95f..454aece 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -3163,11 +3163,11 @@ quantit Si usa molto spesso \const{TCP\_CORK} quando si effettua il trasferimento diretto di un blocco di dati da un file ad un socket con \func{sendfile} - (vedi sez.~\ref{sec:file_sendfile}), per inserire una intestazione prima - della chiamata a questa funzione; senza di essa l'intestazione potrebbe - venire spedita in un segmento a parte, che a seconda delle condizioni - potrebbe richiedere anche una risposta di ACK, portando ad una notevole - penalizzazione delle prestazioni. + (vedi sez.~\ref{sec:file_sendfile_splice}), per inserire una intestazione + prima della chiamata a questa funzione; senza di essa l'intestazione + potrebbe venire spedita in un segmento a parte, che a seconda delle + condizioni potrebbe richiedere anche una risposta di ACK, portando ad una + notevole penalizzazione delle prestazioni. Si tenga presente che l'implementazione corrente di \const{TCP\_CORK} non consente di bloccare l'invio dei dati per più di 200 millisecondi, passati i -- 2.30.2