Ecco una guida dedicata a chi vuole ridurre al minimo il tempo di avvio della propria macchina Debian. L'argomento è talmente vasto che ho dovuto suddividerlo in più puntate. Questa è la prima, come potete facilmente evincere dal titolo se non vi lasciate fuorviare dal doppio senso...
Tutto ebbe inizio nel settembre del 2008, quando due sviluppatori Intel, Arjan van de Ven e Auke Kok, tennero una presentazione alla Linux Plumbers Conference dimostrando di poter avviare un netbook (un Asus EeePC 901) in appena 5 secondi. Al di là del risultato in sé, che si può ottenere solo "manomettendo" il kernel, il server X e altri sottosistemi che pochi oserebbero toccare, la presentazione scatenò una vera e propria corsa a chi otteneva il boot più veloce.
Tra i tentativi di trasporre il risultato al mondo Debian, è particolarmente interessante quello che Phil Endecot ha descritto in un articolo su Debian Administration.
Vediamo insieme quali insegnamenti possiamo trarre sia dall'esperimento iniziale, sia dalla ricerca di Phil.
Bootchart
Iniziamo con quello che potremmo definire "passo zero", nel senso che non fa ancora parte dell'ottimizzazione vera e propria, ma è indispensabile per valutare i risultati: misurare il boot. Installiamo il programma Bootchart:
# aptitude install bootchart
Bootchart non solo cronometra quanti secondi ci mette il nostro sistema ad avviarsi, ma ci dà anche l'indicazione di quali attività consumano più tempo.
Attenzione: Bootchart non interviene nell'avvio a meno che non si passi al kernel l'argomento init=/sbin/bootchartd
. Consiglio di creare un'apposita riga di configurazione di Grub, perché è tutt'altro che facile da ricordare e da scrivere tutte le volte (magari con una tastiera italiana quando Grub si aspetta quella americana...)!
Rimando alla documentazione di Bootchart per sapere come funziona e come interpretare i grafici risultanti.
Kernel e initrd
Questo capitolo non piacerà a molti, perché, in fin dei conti, non consiglio nient'altro che di ricompilare il kernel. Chi non se la sente, salti pure al capitolo successivo!
Il kernel di Linux prevede driver per (quasi) qualsiasi hardware sia possibile collegare alla nostra macchina, solitamente sotto forma di moduli separati che se ne stanno buoni buoni in /lib/modules
e vengono caricati solo all'occorrenza. Ma cosa succede se uno di questi driver è quello che serve per pilotare, ad esempio, proprio il disco su cui risiede la directory /lib/modules
? Per non incappare in un circolo vizioso come questo, gli sviluppatori Debian creano una roba chiamata initrd o initram, cioè un disco virtuale (caricato in RAM) che il kernel, nei primi istanti della sua vita, usa come file system principale (la directory "/" per capirci). Questo contiene quel minimo di driver e di file di configurazione che permettano al kernel di accedere al file system "ufficiale". Una volta espletata questa funzione, l'initrd si dissolve nel nulla.
Non credo sia necessario dire che l'intera operazione porta via secondi preziosi: è un classico esempio di prestazioni sacrificate in nome della versatilità. Nell'ottica di uno sviluppatore Debian, che deve confezionare un pacchetto "universale" e dunque adattabile a tutto, ciò ha molto senso. Ma le cose cambiano se il nostro scopo è quello di ottimizzare il sistema per la nostra macchina, di cui conosciamo hardware e configurazione e, soprattutto, se siamo certi che questi non sono destinati a cambiare a nostra insaputa. In questo caso, un kernel compilato ad hoc, con tutti e soli i moduli che verranno effettivamente usati e senza il fardello di initrd, sarà più snello e veloce senza perdere in funzionalità.
Non è mia intenzione spiegare come si ricompila ed installa il kernel, ma piuttosto mi soffermerò su come scegliere quali driver integrare nel kernel, quali compilare come moduli e quali escludere del tutto. La teoria è semplice, la pratica un po' meno...
Driver da compilare dentro il kernel
Si avvia con un kernel generico (tipo quelli distribuiti nei pacchetti linux-image) e si lascia che faccia esattamente ciò che deve fare: cioè che si adatti all'hardware presente caricando tutti i driver di cui ha bisogno. A questo punto con il comando lsmod
si avrà l'elenco di tutti i moduli che è necessario integrare nel kernel ad hoc. Un apposito script scritto da Phil può aiutare ad associare ogni modulo alle relative opzioni di configurazione del kernel (le variabili CONFIG_*
), ma non è affidabile al 100%, quindi consiglio di rivedere a mano, driver per driver, la configurazione. Inoltre lo script tende a marcare le opzioni come "m" (compilata come modulo), mentre noi vogliamo invece "y" (integrata nel kernel).
Driver da compilare come moduli
Una volta selezionati i driver che è necessario compilare dentro il kernel, occorre pensare ai possibili dispositivi che, sebbene non presenti al momento e dunque non "catturati" da lsmod, potrebbero essere connessi in futuro. Esempi tipici sono chiavette USB, CD e DVD, stampanti, ecc. Ciascuno di questi oggetti richiede che il kernel abbia un certo numero di driver per poterlo gestire. Ad esempio, una chiavetta USB formattata sotto Windows richiederà i moduli scsi_mod, usb_storage, sd_mod per pilotare l'hardware, ma anche msdos, fat, vfat e nls_utf8 per riconoscere il file system, e così via. Confrontando l'output di lsmod
prima e dopo il collegamento di un dispositivo si ha un'idea di quali moduli sono normalmente coinvolti e quindi quali driver dovranno essere aggiunti al kernel (compilati come moduli, opzione "m").
Driver da escludere
Tutto il resto va eliminato: non sarà né integrato nel kernel (perché questo sia il più piccolo e veloce possibile) né compilato come modulo (per non allungare inutilmente i tempi di compilazione).
Gli script di init
Una volta inizializzato il kernel, caricato i moduli ed eventualmente abbandonato il disco initrd, il sistema esegue i cosiddetti script di init, responsabili di configurare lo spazio utente e lanciare i vari servizi: sono quelli che iniziano con S nelle directory /etc/rcS.d
e poi /etc/rc2.d
.
L'ottimizzazione di queste directory è stata trattata in una guida specifica, ormai resa obsoleta dall'adozione di insserv per riorganizzare dinamicamente l'ordine di esecuzione. Di nuovo Debian ha scelto di privilegiare la flessibilità a scapito della performance: insserv garantisce la coerenza della sequenza d'avvio in qualsiasi combinazione di pacchetti installati, ma la sequenza che determina, seppur coerente, non è ottima (gli interessati possono trovare qualche informazione in più in questo commento).
Non potendo quindi intervenire sull'ordine degli script, vediamo almeno quali sono quelli che portano via più tempo.
udev
Questo sottosistema è talmente importante e delicato che merita un capitolo a parte, nella prossima puntata.
hwclock e hwclockfirst
Sembra incredibile, ma leggere l'orologio a pila integrato nella scheda madre del nostro PC (chiamato RTC) è un'operazione lentissima. E, cosa ancora più incredibile, gli script standard previsti da Debian lo leggono due volte! Infine, e qui rasentiamo l'assurdo, dovete sapere che non ce n'è alcun bisogno: i moderni kernel possono accedere direttamente all'RTC e impostare l'orario di sistema in base all'RTC, senza bisogno di alcun comando in spazio utente. L'opzione che fa questo si chiama CONFIG_HCTOSYS
: verificate che sia attiva con il comando
$ grep HCTOSYS /boot/config*
Se avete l'opzione attiva, potete sbarazzarvi dei due lenti e inutili script cambiando la S del loro nome in K:
# mv /etc/rcS.d/S06hwclockfirst.sh /etc/rcS.d/K06hwclockfirst.sh # mv /etc/rcS.d/S08hwclock.sh /etc/rcS.d/K08hwclock.sh
network
Lo script chiamato S...networking
attiva tutte le connessioni configurate come automatiche (keyword auto
) nel file /etc/network/interfaces
. Questo potrebbe richiedere un po' di tempo se siamo in attesa di un server DHCP che potrebbe non rispondere mai (ad esempio perché il cavo ethernet non è collegato). Al problema si può ovviare rimuovendo dal file interfaces
le righe incriminate, cioè quelle che iniziano con auto
che si riferiscono a schede di rete reali (meglio lasciare, invece, il loopback lo
). Nella maggioranza dei casi, la riga da togliere sarà semplicemente:
auto eth0
La domanda a questo punto è: ma chi "tira su" l'interfaccia di rete se questo script di avvio la salta? Se avete NetworkManager o wicd installati, lasciate che se ne occupino loro: sono fatti apposta e hanno delle logiche intelligenti, ad esempio non attivano la rete wireless se è presente quella cablata, ecc.
Se invece preferite fare a meno di questi sofisticati ma invasivi gestori di connessione e avete le idee chiare su quali interfacce volete attivare all'avvio, consiglio di inserire degli opportuni comandi nel file /etc/rc.local
che viene eseguito dopo tutti gli altri initscript. Ecco l'esempio più classico:
# Tira su la connessione wired: ifup eth0
Altri script
L'ultima considerazione potrà sembrare banale: più script ci sono, più tempo durerà l'avvio. Quindi rimuovete tutti i pacchetti che non servono. Far partire Apache ad ogni avvio perché una volta ogni sei mesi potremmo voler provare come si vede una pagina PHP è uno spreco! Tenere installato un MTA solo per smistare la posta di cron è ugualmente ingenuo!
Infine, ricordate che un pacchetto rimosso ma non "purgato" mantiene i suoi file di configurazione, compresi gli script di init. Questo vuol dire che lo script parte, si accorge che gli eseguibili non sono più installati ed esce. Ma intanto ha invocato una bash, ha creato e distrutto un certo numero di processi, ha aggiunto output ai file di log, ecc. Ecco come liberarsi di tutti i file di configurazione in eccesso:
# aptitude purge '~c'
Conclusioni
Ai più attenti non sarà sfuggito che il tema principale di questa guida è come versatilità e prestazioni siano mutualmente esclusive. La ricetta della velocità è dunque rinunciare a un po' della prima per avere più delle seconde.
Nella prossima puntata parleremo diffusamente di udev e vedremo che questo non fa eccezione: non è che l'ennesimo esempio di come negi anni abbiamo appesantito il nostro sistema al fine di rendere la vita più semplice per l'utente.
Commenti
Inviato da marcosan il Mar, 31/05/2011 - 08:34.
Re: Avvio in x secondi (parte prima)
Ottima prima parte per far partire prima la nostra macchina
Non sono un appassionato dei tempi di avvio...ma qualche accorgimento lo adottero`!
Guida chiara e precisa, come sempre!
Ciao,
Marco
"La matematica e' l'arte di dare lo stesso nome a cose diverse."
H.Poincare (1854-1912).
Inviato da paolo il Sab, 04/06/2011 - 03:02.
Re: Avvio in x secondi (parte prima)
Ottimo ottimo, proviamo subito qualcosa, grazier per la guida!
Paolo Mainardi
CTO Twinbit http://www.twinbit.it
Vice Presidente -- ILDN - Italian Linux DIstro Network
Inviato da Anubi_Debian_3 il Sab, 02/07/2011 - 12:15.
Re: Avvio in x secondi (parte prima)
Grazie per la guida
Ricordo ancora quella mia vecchia discussione del forum che ti ha dato l'idea.