Booster le démarrage d’Archlinux
Mon Arch boot environ en 15s, du grub au bureau. Je n’ai jamais pu atteindre un score pareil avec mes anciennes distributions, qui elles mettaient entre 30s (Debian) et 2min (OpenSuse). Le seul challenger valable est le Mac OS X du bureau qui lui boot en une vingtaine de secondes. Dans cet article je vais vous détailler ce que j’ai essayé et modifié pour parvenir à ce score. Nous sommes d’accord que la vitesse de démarrage n’est pas un facteur critique, mais j’en ai appris beaucoup sur la façon dont Arch et Linux démarrent et j’aimerais vous le partager.
Attention: J’ai écris ce guide pour les personnes qui aiment bidouiller leur système, qui sont à la recherche de la moindre optimisation et surtout qui ne pleurent pas quand quelquechose se passe mal. Je pars du principe que vous êtes confortable avec la ligne de commande. Ce billet est un récapitulatif de mes recherches sur le sujet, je m’inspire du wiki d’Archlinux ainsi que de son forum. Ah et important : faites une sauvegarde de chaque fichier modifié.
Utiliser un système de fichiers plus rapide
Il y en a beaucoup, avec leurs avantages et leurs inconvénients, dont certains plus rapide que d’autres. JFS à l’air pas mal, il est rapide, journalisé, stable et n’utilise pas beaucoup de ressouces CPU. ReiserFS et Ext4 ne sont pas mauvais non plus. Je n’ai pas eu le courage de migrer, donc je suis resté sous Ext3, mais si jamais j’ai l’occasion de formater un jour alors je choisirai JFS.
/etc/mkinitcpio.conf
Ce fichier de configuration va servir à créer un initrd qui sera chargé au démarrage et qui va servir à charger tous les modules pour votre matériel et monter les disques, ensuite il donne la main au kernel. Il est donc important de rendre ce fichier le plus petit possible. Par exemple j’ai retiré usbinput car je n’ai pas de clavier usb etc.. Allez faire un tour sur cette page du wiki d’Archlinux, la nature des différents hooks est expliquée. Dans mon cas le mkinitcpio ressemble à ça :
MODULES="" BINARIES="" FILES="" HOOKS="autodetect base udev sata filesystems"
Penser à regénerer les .img du kernel (pacman -S kernel26)
/etc/inittab
Accelère légérement le démarrage :
# # /etc/inittab # # Démarrage sur console id:3:initdefault: # once à la place de wait rc::sysinit:/etc/rc.sysinit rs:S1:once:/etc/rc.single rm:2345:once:/etc/rc.multi rh:06:once:/etc/rc.shutdown su:S:once:/sbin/sulogin -p # moins de TTY c1:2345:respawn:/sbin/agetty -8 38400 vc/1 linux c2:2345:respawn:/sbin/agetty -8 38400 vc/2 linux ca::ctrlaltdel:/sbin/shutdown -t3 -r now
/etc/rc.sysinit
Le plus gros est fait ici. Le support des RAID, LVM et disques cryptés ont été enlevés. Les reglages de l’horloge, de la langue, de la disposition du clavier et du nom d’hôte ont été placés dans ce fichier comme ça plus besoin de charger le /etc/rc.conf pour charger ces valeurs. On peut aussi faire que certains programme se lance en arriere plan pour que la suite se charge sans attendre la fin du premier (grace à l’opérateur &) et ainsi gagné quelques secondes.
#!/bin/bash # # /etc/rc.sysinit # . /etc/rc.conf . /etc/rc.d/functions echo " " printhl "Arch Linux " printhl "${C_H2}<a class="external free" title="http://www.archlinux.org" rel="nofollow" href="http://www.archlinux.org/">http://www.archlinux.org</a>" printhl "Copyright 2002-2007 Judd Vinet" printhl "Copyright 2007-2008 Aaron Griffin" printhl "Distributed under the GNU General Public License (GPL)" printsep # mount /proc, /sys and our RAM /dev /bin/mount -n -t ramfs none /dev /bin/mount -n -t proc none /proc /bin/mount -n -t sysfs none /sys # Create our default nodes that minilogd may need /bin/mknod /dev/null c 1 3 /bin/mknod /dev/zero c 1 5 /bin/mknod /dev/console c 5 1 # More initial /dev setup that udev doesn't do /bin/ln -snf /proc/self/fd /dev/fd /bin/ln -snf /proc/self/fd/0 /dev/stdin /bin/ln -snf /proc/self/fd/1 /dev/stdout /bin/ln -snf /proc/self/fd/2 /dev/stderr /bin/ln -snf /proc/kcore /dev/core /bin/mkdir /dev/pts /bin/mkdir /dev/shm # start up our mini logger until syslog takes over /sbin/minilogd # anything more serious than KERN_WARNING goes to the console # 'verbose' cmdline parameter enables more messages if /bin/grep -q " verbose" /proc/cmdline; then /bin/dmesg -n 8 else /bin/dmesg -n 3 fi # enable rtc access /sbin/modprobe rtc-cmos >/dev/null 2>&1 RTC_MAJOR=$(/bin/grep -w rtc /proc/devices 2>/dev/null); RTC_MAJOR="${RTC_MAJOR%% *}" if [ -n "$RTC_MAJOR" ]; then /bin/mkdir /dev/misc/ /bin/mknod /dev/misc/rtc0 c $RTC_MAJOR 0 /bin/ln -s /dev/misc/rtc0 /dev/rtc fi # Set clock early to fix some bugs with filesystem checks # Clock is set again later to match rc.conf if [ -f /etc/localtime ]; then /sbin/hwclock --hctosys --localtime --directisa --noadjfile fi echo > /proc/sys/kernel/hotplug if [ -x /sbin/udevadm -a -d /sys/block ]; then # We have udev and /sys appears to be mounted, use UDev stat_busy "Starting UDev Daemon" /sbin/udevd --daemon /sbin/udevadm trigger & udevstart="$(/bin/date +%s%0N)" stat_done else # Static /dev, our last resort status "Using static /dev filesystem" true fi # Load modules from the MODULES array defined in rc.conf if ! [ "$load_modules" = "off" ]; then if [ -f /proc/modules ]; then stat_busy "Loading Modules" for mod in "${MODULES[@]}"; do if [ "$mod" = "${mod#!}" ]; then /sbin/modprobe $mod & fi done stat_done fi if [ -d /proc/acpi ]; then stat_busy "Loading standard ACPI modules" ACPI_MODULES="ac battery button fan processor thermal" k="$(echo $BLACKLIST ${MOD_BLACKLIST[@]} | /bin/sed 's|-|_|g')" j="$(echo ${MODULES[@]} | /bin/sed 's|-|_|g')" #add disabled MODULES (!) to blacklist - much requested feature for m in ${j}; do [ "$m" != "${m#!}" ] && k="${k} ${m#!}" done # add disablemodules= from commandline to blacklist k="${k} $(echo ${disablemodules} | /bin/sed 's|-|_|g' | /bin/sed 's|,| |g')" for n in ${ACPI_MODULES}; do if ! echo ${k} | /bin/grep "<$n>" 2>&1 >/dev/null; then /sbin/modprobe $n > /dev/null 2>&1 & fi done stat_done fi fi # run udev uevents if /bin/pidof -o %PPID /sbin/udevd >/dev/null; then stat_busy "Loading UDev uevents" /sbin/udevadm settle stat_done udevend="$(/bin/date +%s%0N)" printhl " UDev uevent processing time: $((($udevend-$udevstart)/1000000))ms" fi # bring up the loopback interface if [ -d /sys/class/net/lo ]; then stat_busy "Bringing up loopback interface" /sbin/ifconfig lo 127.0.0.1 up & if [ $? -ne 0 ]; then stat_fail else stat_done fi fi status "Mounting Root Read-only" /bin/mount -n -o remount,ro / FORCEFSCK= [ -f /forcefsck ] && FORCEFSCK="-- -f" NETFS="nonfs,nonfs4,nosmbfs,nocifs,nocodafs,noncpfs,nosysfs,noshfs,nofuse,nofuseblk" if [ -x /sbin/fsck ]; then stat_busy "Checking Filesystems" if /bin/grep -qw quiet /proc/cmdline; then /sbin/fsck -A -T -C -a -t $NETFS $FORCEFSCK >/dev/null 2>&1 else /sbin/fsck -A -T -C -a -t $NETFS $FORCEFSCK 2>/dev/null fi fsckret=$? if [ ${fsckret} -gt 1 ]; then stat_fail if [ $((${fsckret}&2)) -eq 2 ]; then echo echo "********************** REBOOT REQUIRED *********************" echo "* *" echo "* The system will be rebooted automatically in 15 seconds. *" echo "* *" echo "************************************************************" echo /bin/sleep 15 else echo echo "***************** FILESYSTEM CHECK FAILED ****************" echo "* *" echo "* Please repair manually and reboot. Note that the root *" echo "* file system is currently mounted read-only. To remount *" echo "* it read-write type: mount -n -o remount,rw / *" echo "* When you exit the maintenance shell the system will *" echo "* reboot automatically. *" echo "* *" echo "************************************************************" echo /sbin/sulogin -p fi echo "Automatic reboot in progress..." /bin/umount -a /bin/mount -n -o remount,ro / /sbin/reboot -f exit 0 fi stat_done fi stat_busy "Mounting Local Filesystems" /bin/mount -n -o remount,rw / /bin/rm -f /etc/mtab* # make sure / gets written to /etc/mtab /bin/mount -o remount,rw / # Write /proc, /sys and /dev to /etc/mtab if [ -e /proc/mounts ]; then /bin/grep -e "/proc " -e "/sys " -e "/dev " /proc/mounts >> /etc/mtab fi # now mount all the local filesystems /bin/mount -a -t $NETFS stat_done status "Activating Swap" /sbin/swapon -a & stat_busy "Configuring System Clock" if [ ! -f /var/lib/hwclock/adjtime ]; then echo "0.0 0 0.0" > /var/lib/hwclock/adjtime & fi /bin/rm -f /etc/localtime /bin/cp "/usr/share/zoneinfo/Europe/Brussels" /etc/localtime /sbin/hwclock --hctosys --localtime --directisa stat_done if [ -f /var/run/random-seed ]; then stat_busy "Initializing Random Seed" /bin/cat /var/run/random-seed >/dev/urandom & stat_done fi stat_busy "Removing Leftover Files" /bin/rm -f /etc/nologin &>/dev/null & /bin/rm -f /etc/shutdownpid &>/dev/null & /bin/rm -f /var/lock/* &>/dev/null & /bin/rm -rf /tmp/* /tmp/.* &>/dev/null & /bin/rm -f /forcefsck &>/dev/null & (cd /var/run && /usr/bin/find . ! -type d -exec /bin/rm -f -- {} ; ) : > /var/run/utmp & # Keep {x,k,g}dm happy with xorg /bin/mkdir /tmp/.ICE-unix && /bin/chmod 1777 /tmp/.ICE-unix /bin/mkdir /tmp/.X11-unix && /bin/chmod 1777 /tmp/.X11-unix stat_done #status "Updating Shared Library Links" /sbin/ldconfig #status "Updating Module Dependencies" /sbin/depmod -A & status "Setting Hostname: Pinguin" /bin/hostname "Pinguin" & # Flush old locale settings : >/etc/profile.d/locale.sh /bin/chmod 755 /etc/profile.d/locale.sh # Set user defined locale [ -z "$LOCALE" ] && LOCALE="en_US" stat_busy "Setting Locale: en_US" echo "export LANG=en_US" >>/etc/profile.d/locale.sh stat_done stat_busy "Setting Consoles to UTF-8 mode" # UTF-8 consoles are default since 2.6.24 kernel # this code is needed not only for older kernels, # but also when user has set vt.default_utf8=0 but LOCALE is *.UTF-8. for i in $(/usr/bin/seq 0 63); do usr/bin/kbd_mode -u < /dev/vc/${i} printf "e%%G" > /dev/vc/${i} done # the $CONSOLE check helps us avoid this when running scripts from cron echo 'if [ "$CONSOLE" = "" -a "$TERM" = "linux" -a -t 1 ]; then printf "e%%G"; fi' >>/etc/profile.d/locale.sh stat_done status "Loading Keyboard Map: be-latin1" /bin/loadkeys -q -u "be-latin1" & # Adding persistent network/cdrom generated rules if [ -f "/dev/.udev/tmp-rules--70-persistent-cd.rules" ]; then stat_busy "Adding persistent cdrom udev rules" /bin/cat /dev/.udev/tmp-rules--70-persistent-cd.rules >> /etc/udev/rules.d/70-persistent-cd.rules stat_done fi if [ -f "/dev/.udev/tmp-rules--70-persistent-net.rules" ]; then stat_busy "Adding persistent network udev rules" /bin/cat /dev/.udev/tmp-rules--70-persistent-net.rules >> /etc/udev/rules.d/70-persistent-net.rules stat_done fi # Save our dmesg output from this boot if [ -f /var/log/dmesg.log ]; then /bin/rm /var/log/dmesg.log fi /bin/dmesg > /var/log/dmesg.log &
/etc/rc.conf
On peut enlever tout ce qu’on a mis en dur dans le fichier d’au dessus. Le but est de ne pas mettre les modules et daemons qu’on n’utilise pas. Charger les daemons en asynchrone ( @ ). Au niveau des modules il y a deux solutions : la première est de désactiver le MOD_AUTOLOAD et de charger les modules “à la main”. La commande hwdetect –show-modules-order vous en donnera une liste.
# # /etc/rc.conf # MOD_AUTOLOAD="no" MODULES=(ac battery button processor thermal video wmi agpgart intel-agp dcdbas hid usbhid i2c-i801 i2c-core evdev ff-memless joydev pcspkr psmouse serio_raw led-class mmc_core ricoh_mmc sdhci-pci sdhci rtc-cmos rtc-core rtc-lib output iTCO_vendor_support iTCO_wdt snd-mixer-oss snd-pcm-oss snd-hwdep snd-page-alloc snd-pcm snd-timer snd snd-hda- intel soundcore pata_acpi ata_generic ahci ata_piix sky2 mac80211 rfkill usb-storage usbhid usbcore ehci-hcd uhci-hcd vboxdrv vboxnetflt) DAEMONS=(syslog-ng @hal @fam @crond @alsa)
La deuxième solution est de laisser le MOD_AUTOLOAD tout charger. La deuxième solution est plus rapide chez moi mais pas forcément chez tout le monde.
MOD_AUTOLOAD="yes" MODULES=() DAEMONS=(syslog-ng @hal @fam @crond @alsa)
Forcer l’utilisation de modprobe pour charger les modules
#!/bin/sh # # /lib/udev/load-modules.sh # /sbin/modprobe $1 &
Recompiler le Kernel
J’étudis encore ce principe. Je ferais un billet dédier à cela car l’optimisation ne touche pas uniquement le démarrage mais l’ordinateur tout entier.
Conclusion
Voilà j’espère que ce billet a été instructif pour vous autant que ces manipulations l’ont été pour moi :)
Comme d’habitude si vous avez des questions vous savez où me joindre.