Parallelizzare gli script di avvio

Mer, 04/03/2009 - 21:05

Parallelizzare gli script di avvio

Inviato da mcortese 5 commenti

Chiunque si lasci tentare dalla sfida del momento di accorciare il più possibile il tempo di avvio della propria macchina si imbatte prima o poi nell'idea di lanciare gli script di init in parallelo.

L'impresa è apparentemente molto semplice: basta aggiungere la variabile

CONCURRENCY=shell nel file /etc/default/rcS

e il gioco è fatto.

In realtà se contemporaneamente non si ristudia anche la sequenza degli script, i risultati tarderanno a farsi notare. Se poi readahead è installato, potrebbe riservare spiacevoli sorprese...

Partiamo proprio da quest'ultimo: l'installazione di readahead piazza uno script di avvio in /etc/init.d e crea il link simbolico /etc/rcS.d/S02readahead. Fintantoché gli script delle directory /etc/rc?.d sono eseguiti in base all'ordine alfabetico del loro nome, questo script è chiamato dopo S02mountkernfs. Ciò è corretto perché readahead presume che /proc sia montato, che è esattamente ciò che fa mountkernfs.

Ma cosa succede se, avendo indicato CONCURRENCY=shell, tutti gli script con lo stesso ordine di avvio (o priorità) sono lanciati in parallelo? In questo caso readahead e mountkernfs, entrambi con priorità 02, sono eseguiti insieme e non c'è alcuna garanzia che il secondo abbia già montato /proc quando il primo ne ha bisogno.

Riorganizzazione di rcS.d

In pratica readahead deve essere lanciato dopo mountkernfs (priorità 02), ma prima di udev (priorità 03). Poiché non esiste una priorità "due e mezzo", l'unica soluzione è "promuovere" udev alla priorità 04. Ciò a sua volta impone che tutti gli script successivi che dipendono l'uno dall'altro siano anch'essi promossi a cascata: mountdevsubfs (da 04 a 05), e keymap e bootlogd (da 05 a 06).

A questo punto la sequenza è sicura, ma non ancora ottimizzata. Per ottenere qualche beneficio dall'esecuzione parallela, è necessario che ogni livello di priorità contenga il maggior numero possibile di script, in modo da massimizzare i processi che possono girano in parallelo. Ci sono sei interventi da fare per migliorare le cose:

  • hdparm e hwclockfirst dipendono solo da mountdevsubfs (priorità 05), perciò si possono spostare al livello 06;
  • ancora prima, procps non sembra dipendere da niente e può quindi essere lanciato subito dopo readahead, alla priorità 04, in parallelo con udev;
  • ifupdown-clean, module-init-tools, mtab e udev-mtab richiedono solo che il file system di root siavalidato, quindi trovano collocazione ottimale alla priorità 12, subito dopo checkroot;
  • un altro gruppo di script che vanno a braccetto è il trio x11-common, urandom e ifupdown, che richiedono un file system locale stabile, ma non hanno esigenze di rete: la priorità più logica per loro è 39, immediatamente prima di networking;
  • poiché 39 è anche la priorità predefinita di readahead-desktop e visto che questo può svolgere meglio la sua funzione di precaricamento se lo si lascia girare da solo, suggerisco di anticiparne l'esecuzione al livello 38;
  • infine, il gruppo constituito da console-screen, alsa-utils, sudo e bootmisc può appropriarsi della priorità 50.

Nota: ho saltato di proposito hwclock, perché sinceramente non ho mai capito quale funzione svolga questo script che non sia già egregiamente svolta da hwclockfirst. In ogni caso, sono riuscito a liberarmi di entrambi questi lentissimi script semplicemente delegando al kernel la lettura dell'orologio, grazie al supporto RTC.

In conclusione, ecco come dovrebbe apparire la directory /etc/rcS.d dopo la "cura", dove gli script con la stessa priorità sono indicati sulla stessa riga:

S01glibc
S02hostname  S02mountkernfs
S03readahead
S04udev
S04procps
S05mountdevsubfs
S06bootlogd  S06hdparm S06hwclockfirst  S06keymap
S10checkroot
S12ifupdown-clean  S12module-init-tools  S12mtab S12udev-mtab
S30checkfs
S35mountall
S36mountall-clean
S37mountoverflowtmp
S38readahead-desktop
S39ifupdown  S39urandom S39x11-common
S40networking
S45mountnfs
S46mountnfs-bootclean
S50alsa-utils  S50bootmisc S50console-screen  S50sudo
S99stop-bootlogd-single

Riorganizzazione di rc2.d

Soddisfatti dell'ottimo lavoro fatto su rcS.d, possiamo passare ad analizzare anche rc2.d. Qui però l'obiettivo è differente. Ciò che veramente ci interessa è raggiungere il più in fretta possibile la schermata di login, tutto il resto può seguire al ritmo che vuole.

Per semplicità, assumiamo che il login sia gestito da GDM. La configurazione di altri display manager dovrebbe essere più facile e per questo lasciata al lettore come esercizio!

La prima cosa da fare è identificare il "cammino critico" che porta il più velocemente possibile ad eseguire S30gdm. Eccolo:

 S10sysklogd -> S12dbus -> S24hal -> S30gdm
 

Aggiungerei anche S11klogd, per essere sicuri di non perdere qualche messaggio del kernel in questa fase. Tutto il resto può venire dopo, con la maggioranza degli script alla priorità 40, tranne le seguenti eccezioni:

  • system-tools-backend potrebbe servire alla sessione GDM che sta partendo, quindi gli assegniamo la priorità 31;
  • gli script saned e cups, che dipendono da avahi-daemon, vanno spostati al livello 45;
  • possiamo decidere di lasciare cron e anacron alla loro priorità predefinita di 89 perché, per loro stessa natura, svolgono funzioni che non devono necessariamente essere espletate all'avvio;
  • in coda alla seuqenza di avvio, gli ultimi script vanno leggermente riarrangiati: rmnologin e rc.local vanno eseguiti al livello 98, cioè subito prima degli "ultimissimi" script, che sono stop-bootlogd, stop-readahead ed eventualmente bootchart.

Ecco come dovrebbe apparire la directory /etc/rc2.d ottimizzata:

S10sysklogd
S11klogd
S12dbus
S24hal
S30gdm
S31system-tools-backend
S40acct  S40avahi-daemon  S40openbsd-inetd  S40ssh
S45cups  S45saned
S89anacron  S89cron
S98rc.local  S98rmnologin
S99bootchart  S99stop-bootlogd  S99stop-readahead

Naturalmente, la lista potrebbe cambiare di molto al variare del software installato. Ad esempio, xinetd potrebbe aver preso il posto di openbsd-inetd, etc. Inoltre avahi-daemon non è strettamente necessario: CUPS e sane funzionano anche senza!

Prima di concludere, è obbligatorio citare il pacchetto insserv che promette di fare quanto sopra in modo automatico. Sinceramente sconsiglio questo pacchetto: la sequenza riordinata da insserv, benché corretta dal punto di vista delle dipendenze, è totalmente scorrelata dalla funzione che svolge ciascuno script. Ad esempio, insserv non può sapere che vogliamo GDM attivo il più presto possibile.

Quanto sopra è il risultato dell'ottimizzazione che ho studiato sul mio sistema e che mi ha permesso di risparmiare 3 secondi all'avvio. Auguro a tutti di ottenere risultati analoghi!





Commenti

Ritratto di ntropia
#1

Inviato da ntropia il Dom, 22/03/2009 - 00:42.

Apprezzamento

C'è poco da dire: un bel lavoro.

eNjoy

Chi ha intendimento conti il numero della Bestia, perché è un numero d'uomo; e il suo numero è... rw-rw-rw-



Ritratto di paco_deb
#2

Inviato da paco_deb il Dom, 29/03/2009 - 13:36.

Integrazione guide

Indubbiamente un articolo accurato anche se questi argomenti erano già stati trattati nella guida peedUp Linux Boot - Velocizzare l'avvio di Debian in cui spiegavo come ridurre il tempo di boot.

Tra l'altro esiste un software (insserv) che in automatico analizza le dipendenze degli script e ne ristabilisce l'ordine al fine si velocizzare la procedura di startup.

Resta comunque il fatto che l'analisi e la comprensione così profonda degli script d'avvio è comunque un lavoro lodevole, senza contare sche se non sbaglio insserv non si fa carico di riorganizzare il runlevel comune (rc.S).

Sarebbe interessante a mio parere integrare gli articoli in un unica guida mirata alla completa comprensione e velocizzazione della procedura d'avvio, argomento tanto caro a chi utilizza debian su notebook.

Ciao

----------------
E.C.: scusa, non avevo notato che avevi già citato insserv, purtroppo ho il maledetto vizio di usare la lettura veloce anche quando non dovrei, principalmente per pigrizia. Smile

PS: Mi veniva da pensare che determinate modifiche potrebbero essere automatizzate mediante l'installazione di un deb, se ti interessa fammi sapere

Ciao



Ritratto di mcortese
#3

Inviato da mcortese il Lun, 30/03/2009 - 19:07.

Re: Integrazione guide

Quote:

Sarebbe interessante a mio parere integrare gli articoli in un unica guida mirata alla completa comprensione e velocizzazione della procedura d'avvio, argomento tanto caro a chi utilizza debian su notebook.

Sono d'accordo: sarebbe utilissima. Tra l'altro ho un paio di considerazioni che sono emerse dall'epoca della guida, che non ho ancora trovato il tempo di mettere giù per iscritto. Vedi, ad esempio, il prossimo commento...



Ritratto di mcortese
#4

Inviato da mcortese il Lun, 30/03/2009 - 19:19.

Bug #519520

Avete seguito i consigli della guida ma non avete ottenuto i risultati sperati? Vi sembra che l'esecuzione degli script rimanga sostanzialmente ed inesorabilmente sequenziale?

Ebbene, sappiate che la colpa non è vostra. È il frutto di una policy assurda e di uno script troppo zelante.

La spiegazione è nel bug #519520. In breve: gli script che hanno l'estensione ".sh" vengono trattati diversamente da tutti gli altri e non vengono eseguiti in parallelo.

In attesa che il baco venga risolto a monte dal manutentore del pacchetto sysv-rc, potete ricorrere a questo semplice trucchetto.

Editate il file /etc/init.d/rc e sostituite tutte le stringhe "*.sh)" con "*.sh-falso)" o qualsiasi altra stringa che non corrisponda a dei nomi di file validi.

Dopo questa sostituzione, gli script .sh non saranno trattati diversamente dagli altri.



Ritratto di mcortese
#5

Inviato da mcortese il Mer, 24/06/2009 - 11:52.

Re: Bug #519520

La versione 2.86.ds1-62 di sysvinit (appena caricata in unstable) ha corretto questo baco. Dal changelog:
Quote:

Make init.d/rc simpler by dropping support for sourcing .sh files
after the policy finally changed in 3.8.1. Update to Standards
version 3.8.1. (Closes: #339955, #519520)

In altre parole, gli script con estensione .sh non saranno trattati in modo diverso dagli altri in /etc/rcS.d...