Ottimizzare Linux per dispositivi mobili e server (1)

Ci sono molti piccoli accorgimenti che si possono adottare per adattare il nostro sistema Linux all’uso che lo aspetta, che si tratti di un sistema desktop o di un server.

Martin Michlmayr ha pubblicato un paio di articoli su come ottimizzare Linux per l’uso su dispositivi embedded (NSLU2 nel caso specifico): per la riduzione della memoria occupata e per il funzionamento su memorie flash.

Ma molti consigli valgono anche in generale per migliorare le prestazioni di Linux, sia su dispositivi portatili che non. Ne traduco qui alcuni e mi permetto di aggiungerne altri che possono tornare utili, con un’occhio all’uso desktop e uno all’uso server.

Accesso al disco

Linux ha un ottimo sistema di gestione dei dischi, ma di default offre funzionalità che migliorano l’affidabilità e la tracciabilità delle operazioni, perfette per un server, ma costose per le prestazioni su un PC desktop, un portatile o un palmare/cellulare.

Atime

Una di queste è l’atime dei file: viene memorizzata su disco la data e ora dell’ultimo accesso al file. Questa funzione è utile in rarissimi casi, pertanto si può disattivare senza problemi, perché causa una scrittura su disco per ogni lettura effettuata. Sui normali dischi si guadagna in prestazioni, mentre sulle memorie flash si guadagna anche in durata del supporto (le scritture sono limitate su questi dispositivi). Per disattivarlo è sufficiente modificare (da utente root) il file /etc/fstab aggiungendo l’opzione “noatime” ai vari mount-point.

Commit time

Sempre in questo file possiamo modificare il tempo di commit di ext3, in modo da effettuare meno scritture su disco, e da scrivere più dati in un colpo solo, migliorando le prestazioni. Di default sono 5 secondi, ma possiamo alzarlo a 2 minuti (120 secondi). In questo caso lo svantaggio è che se salta la corrente quando i dati non sono ancora stati scritti se ne perderanno di più. Il mio consiglio è di avere sempre un UPS (un gruppo di continuità) anche piccolo (500-650 VA sono sufficienti per reggere 5-10 minuti, dipende dal carico del vostro PC) ed evitare sia questo problema che quello delle sovratensioni che si verificano ogni tanto e che bruciano alimentatori.

fstab

Andiamo quindi a vedere come modificare il nostro /etc/fstab

# /etc/fstab: static file system information.#

# <file system> <mount point>   <type>  <options>                     <dump>  <pass>

proc            /proc           proc    defaults                        0       0

/dev/hda1       /               ext3    defaults,errors=remount-ro,noatime,commit=120 0       1
/dev/hda3       /home           ext3    defaults,noatime,commit=120     0       2
/dev/hda4       /usr            ext3    defaults,noatime,commit=120     0       3
/dev/hda2       none            swap    sw                              0       0

syslog

Possiamo anche modificare syslog perché bufferizzi i log prima di scriverli su disco. Sui normali dischi questo può ridurre la frammentazione, oltre a evitare di scrivere continuamente su disco pochi bytes, mentre sulle memorie flash il vantaggio è lo stesso del noatime: si prolunga la vita della flash. Lo svantaggio è che se il computer ha un crash (molto raro, ma può succedere) o se manca la corrente si perdono i dati dei log degli ultimi minuti. Quindi non attivatelo se state testando nuovi kernel instabili, moduli proprietari del kernel o driver per X o per qualsiasi cosa giri coi permessi di root e vi servono log affidabili. Su un server potrebbe essere addirittura conveniente togliere il buffering già presente su alcuni file.

Il file da modificare, in questo caso, è /etc/syslog.conf e basta aggiungere un trattino (il normale “meno”) prima del nome del file di log. Ecco un esempio:

#  /etc/syslog.conf     Configuration file for syslogd.#

# First some standard logfiles.  Log by facility.

#auth,authpriv.*           /var/log/auth.log
*.*;auth,authpriv.none    -/var/log/syslog
#cron.*                    /var/log/cron.log
daemon.*                  -/var/log/daemon.log
kern.*                    -/var/log/kern.log
lpr.*                     -/var/log/lpr.log
mail.*                    -/var/log/mail.log
user.*                    -/var/log/user.log

Questo è un pezzo del file standard della Debian. Come vedete alcuni file hanno già il trattino davanti, e vengono bufferizzati. Si tratta solitamente di log meno importanti, per cui non è necessario avere un riscontro preciso nei file, mentre, ad esempio, il file di log delle autorizzazioni (quello che vi scrive “root ha fatto login alle 02:37:21 del 25 dicembre”) viene scritto direttamente su disco per motivi di sicurezza. Qui tale log è disattivato.
Le prestazioni guadagnate in questo caso non sono granché, quindi questa modifica ha senso solo su dispositivi con flash memory: palmari, cellulari, media-center e simili, dove interessa poco avere log precisi ed aggiornati. Si può invece aggiungere (o decommentare nel caso della Debian) una sezione apposita che vada a scrivere i log su una console non utilizzata. Io uso quella in Alt-F12:

#
# I like to have messages displayed on the console, but only on a virtual
# console I usually leave idle.
#
daemon,mail.*;\
        news.=crit;news.=err;news.=notice;\
        *.=debug;*.=info;\
        *.=notice;*.=warn       /dev/tty12

In questo modo c’è un riscontro diretto in tempo reale con i più importanti servizi di sistema. Su un server si può addirittura lasciare attiva quella console di default, in modo da vedere i messaggi di log semplicemente accendendo il monitor, senza fare login.

Memoria

Nei PC moderni ormai la memoria si spreca. Non è raro avere 1, 2 o addirittura 4 Gb di RAM, soprattutto se il PC è in dual-boot con Windows per giocare.

SWAP

Allora la cosa migliore da fare è usare tale memoria e limitare al minimo l’uso della swap e del disco in generale, molto più lento della RAM. Nei kernel 2.6 c’è un parametro apposta per indicare al sistema quanto deve usare la swap: /proc/sys/vm/swappiness

Basta fare un cat di tale file per vederne l’impostazione, e con un echo regolare la quantità che vogliamo:

~# cat /proc/sys/vm/swappiness
60

Se vogliamo ridurre al minimo l’uso della swap (a scapito dei buffer e delle cache dei file aperti) possiamo metterlo a 0, per esempio su un sistema desktop in cui si passa spesso da un’applicazione all’altra. Se vogliamo che il sistema metta in swap più memoria possibile possiamo metterlo a 100, per esempio su un server dove ci sono alcune applicazioni che vengono lanciate ogni tanto (i backup) e quindi possono essere messe in cache, mentre vogliamo massimizzare i buffer per avere più dati possibili in memoria in ogni momento (per esempio le pagine web da servire ai client). Basterà quindi un:

echo 10 >/proc/sys/vm/swappiness

per abbassare senza esagerare la tendenza allo swap. Possiamo rendere permanente questa modifica aggiungendo al file /etc/sysctl.conf questa riga:

vm/swappiness = 10

In questo file si possono inserire tutte le modifiche da fare al boot a qualsiasi cosa si trovi sotto /proc/sys come vedremo tra poco.

Cache in scrittura

A metà tra l’uso della memoria e quello del disco viene il laptop_mode, un sistema per impostare il sistema per l’uso minimo del disco. Ormai la sintassi per le modifiche è chiara, quindi andiamo a vedere direttamente come modificare sysctl.conf e quali parametri possiamo impostare:

vm/laptop_mode = 5
vm/dirty_writeback_centisecs = 12000
vm/dirty_expire_centisecs = 12000
vm/dirty_ratio = 95
vm/dirty_background_ratio = 20

Il primo parametro indica dopo quanti secondi, dal risveglio del disco causato da una lettura, iniziare una scrittura. Impostato a 0 disattiva il laptop_mode. Impostato troppo basso può rallentare la lettura per effettuare la scrittura. Qui l’abbiamo impostato a 5 secondi. Abbastanza da permettere di finire la lettura, e abbastanza poco da permettere al disco da tornare a dormire presto. Può essere utile, assieme ai parametri successivi, per l’uso con le flash memory per ridurre le scritture al minimo e migliorare le prestazioni, soprattutto se si ha una buona quantità di RAM.

dirty_writeback_centisecs specifica ogni quanto il kernel deve controllare se ci sono dati da scrivere, in centesimi di secondo. dirty_expire_centisecs specifica dopo quanto tempo i dati da scrivere devono fisicamente essere scritti sul disco. Conviene impostare questi due valori con lo stesso numero. Qui il kernel controlla ogni 120 secondi (2 minuti) se ci sono dati da scrivere e, se ci sono, li scrive su disco. Su un notebook, per far dormire il più possibile il disco, si può impostare a 15-20 minuti, stando attenti al livello della batteria.

dirty_ratio specifica quale percentuale della memoria usare per i dati in attesa. Possiamo impostarlo molto alto, in quanto i dati vengono comunque scritti su disco se la memoria serve per altro. dirty_background_ratio specifica la percentuale di memoria occupata dai dati in attesa alla quale il processo di scrittura si può fermare. Col parametro che abbiamo impostato sopra il sistema cercherà di scrivere dati su disco almeno finché questi non occuperanno il 20% o meno della memoria disponibile.

Questi parametri hanno senso su un portatile o su un dispositivo con memoria flash, ma possono aiutare anche a ridurre la frammentazione dei file su dischi con poco spazio libero (mentre su dischi con molto spazio libero il kernel ha un sistema di allocazione che riduce automaticamente la frammentazione man mano che si usa il disco).

Ridurre la memoria occupata

Naturalmente ha poco senso avere 1 Gb di memoria e lanciare decine di daemon in background senza usarli mai. Conviene quindi “spegnerli” ed attivarli solo quando servono. Per questa modifica bisogna capire, almeno a grandi linee, come funziona il sistema di init di Linux.

Al boot il primo software ad essere eseguito, dopo il kernel, è init, che legge il file /etc/inittab e ne lancia i vari script in base alle informazioni che vi trova. Tra questi c’è l’attivazione del runlevel di default, che in Debian è sempre il 2. Il livello 0 significa “spegnimento”, il livello 1 “monoutente”, il livello 6 “riavvio”. I livelli da 3 a 5 sono personalizzabili, ma per i nostri usi li considereremo equivalenti al livello 2. Quindi dovremo impostare i daemon che ci servono perché partano (start, quindi S) ai livelli da 2 a 5, e perché si fermino (kill, quindi K) ai livelli 0, 1 e 6, mentre impostaremo quelli che usiamo poco (apache, MySQL e Postgres, per esempio, se saltuariamente sviluppiamo per il web) perché siano K (kill) a tutti i livelli. Li avvieremo manualmente quando ci servono. In Debian possiamo usare update-rc.d per automatizzare il tutto, e avremo a disposizione anche alcune opzioni che ci semplificano la vita:

update-rc.d -f apache2 remove
update-rc.d -f mysql remove
update-rc.d -f postgresql-8.2 remove

I nomi da usare per i vari servizi li trovate guardando come si chiamano i file in /etc/init.d.

Questa forma (remove) cancella tutti i link di avvio e di stop del servizio, che quindi andrà sia avviato che fermato a mano prima di spegnere il computer. Dobbiamo quindi ripristinare lo spegnimento dei servizi allo shutdown/reboot/single-user:

update-rc.d apache2 stop 20 0 1 2 3 4 5 6 .
update-rc.d mysql stop 20 0 1 2 3 4 5 6 .
update-rc.d postgresql-8.2 stop 20 0 1 2 3 4 5 6 .

Buona parte degli script di avvio/fermata dei daemon tiene traccia del funzionamento di un daemon, quindi non darà alcun warning allo shutdown. Attenzione al punto alla fine delle righe!

Conclusioni

Si chiude qui questo primo articolo sull’ottimizzazione di Linux. Ci sono molti altri piccoli e grandi accorgimenti adottabili. Li vedremo nella prossima puntata.

  • Maurizio

    Puoi segnalarmi dei tips per velocizzare i render 3D con Applicazioni tipo Maya. Oppure dirmi dove posso guardare, lavoro in un studio grafico e sto migrando la RenderFarm su Debian, ho fatto tutto, ma le prestazioni sono scarse se equiparate a windows, e questo non è accettabile, quindi dipenderà sicuramente dal mio tuning, che praticamente non c’è, ho spento solo l’interfaccia grafica.
    Se potessi indicarmi la strada te ne sarei grato.
    Grazie
    Maurizio

  • Ciao,

    mi spiace, ma non ho mai avuto a che fare con applicazioni di questo tipo, quindi posso solo fare ipotesi su cosa potresti fare.

    Se Maya usa le OpenGL per il rendering puoi controllare se hai installato il pacchetto libgl1-mesa-glx.
    Se non ce l’hai, probabilmente tutto il rendering viene fatto via software, e quindi si appoggia solo al processore, con routine nemmeno tanto ottimizzate.

    Se installi quel pacchetto, e hai una scheda video supportata (Intel, ATI Radeon fino alla X850 con i driver free o oltre con i driver fglrx, o altre supportate), praticamente tutto il rendering dovrebbe venire spostato sulla GPU, anche con X disattivato.

    Se non hai una scheda supportata, ma un processore successivo al Pentium Pro, puoi provare libgl1-mesa-swx11-i686, che contiene routine ottimizzate, anche se comunque in emulazione software, per le CPU di classe 686.

  • Maurizio

    Grazie della risposta, sei molto gentile. Rispondo alle tue questioni, cosi magari quando hai tempo e voglia puoi indirizzarmi, capisco che sei molto impegnato.
    > mi spiace, ma non ho mai avuto a che fare con applicazioni di questo tipo, quindi posso solo fare ipotesi su cosa potresti fare.
    >
    > Se Maya usa le OpenGL per il rendering puoi controllare se hai installato il pacchetto libgl1-mesa-glx.
    NO, viene fatto via software, come dici sotto.

    > Se non ce l’hai, probabilmente tutto il rendering viene fatto via software, e quindi si appoggia solo al processore, con routine >nemmeno tanto ottimizzate.
    Come potrei ottimizzarle, se vale la pena secondo te?

    Volevo chiederti qualcosa riguardo allo swappines, per questo tipo di applicazione considerando che ho due Gb di ram, è meglio un valore basso?
    Grazie!
    Saluti

  • Se Maya non usa le libGL non hai possibilità di fare niente, purtroppo. Se usa le sue librerie per il rendering l’unica cosa che puoi fare, essendo software closed source, è chiedere ai suoi programmatori di darti una versione ottimizzata per la tua configurazione.

    Forse puoi risolvere usando software come CUDA, ma onestamente non so se si possa usare anche per programmi che non lo prevedono.

    Per quanto riguarda la swappiness, se la macchina è dedicata (quasi) solo a quello la lascerei al default di 60.

  • Ciao Alex, grazie alla tua guida invece ho risolto un problema di tutt’altro tipo.

    In seguito ad uno sbalzo di tensione, il mio sistema è andato in palla e mi ha creato un sacco di problemi specialmente con i dischi scsi.
    X non partiva manco a piangere in cinese. Una shell da recovery mode ti usciva una volta ogni mille riavvii.

    Alla fine ho dovuto disattivare totalmente il kernel log daemon in quanto durante il boot mi si piantava sempre fisso li’.

    Un’altra operazione utile è stata quella di impostare a 0 il valore in fstab per tutte le partizioni, lasciando 1 solo alla partizione dedicata al boot.

    Per il momento riesco ad avviare il sistema normalmente e quindi sono tornato subito operativo e avro’ tutto il tempo di studiare le VERE cause e poter rimediare :D

    Bel blog davvero!

    ps: salutami il tuo amico mauro, che io non lo sento da una vita! ;)