Iniciando o Slackware em 12s ou menos

A algum tempo venho fazendo alterações nos scripts de inicialização do Slackware a fim de reduzir o tempo de inicialização do sistema. Algumas desta alterações já uso a muito tempo, com resultados bastante significativos. No entanto neste texto levei o processo um pouco mais a fundo, alterando a ordem com que alguns scripts/serviços são iniciados, enviando outros para background, criando scripts para flexibilizar o controle dos serviços, alterando o gerenciamento da checagem dos sistemas de arquivos, entre várias outras mudanças.

Neste texto proponho um total de 11 modificações ao sistema que vão deste pequenas alterações aos scripts de inicialização, a outras mais complexas, como a reorganização e uso de partições no disco e recompilação do kernel. Estas mudanças resultaram na redução de 70% no tempo de inicialização do Slackware64 em meu notebook, reduzindo o tempo de inicialização de 40s para 12s, no modo texto.

Algumas mudanças requerem cautela e conhecimentos mais específicos, enquanto outras são bem simples e podem ser realizadas sem drama. Embora a necessidade de conhecimentos específicos em algumas modificações, o texto é apresentado com uma linguagem simples e detalhista.

Todos os testes foram feitos em um notebook hp dv6770se, com um disco de 7200rpm, 4GB de RAM, kernel 3.0.4, operando no modo multiusuário (modo 3), uma vez que não há muito que se possa fazer com a inicialização do ambiente gráfico. Os serviços/aplicativos habilitados nesta máquina são: httpd, sshd, svnserver, trac, cups e o VirtualBox.

1. Backup antes de começar

Este texto propõem diversas mudanças aos scripts de inicialização do sistema e na ordem de inicialização de alguns serviços, os quais podem gerar alguns efeitos indesejados. Por isto recomendo que se faça um backup do diretório /etc, caso seja necessário restaurar o sistema ao seu estado original.

Para isto basta fazer a cópia da pasta /etc, preservando as propriedades dos arquivos, diretórios e links. Um “cp -a” resolve o problema:

mkdir ~/backup
[prompt]cp -a /etc ~/backup/

Isto irá criar uma cópia de segurança do seu /etc em ~/backup/etc.

Antes de iniciar as edições nos scripts de boot, vou fazer uma rápida introdução ao processo de inicialização do Slackware, embora recomende a leitura do Slackbook para mais detalhes.

2. O Boot no Slackware

A inicialização do Slackware, bem com de todos os outros GNU/Linux, começa com o carregamento do kernel para a memória e a execução do mesmo. Este trabalho é feito pelo gerenciador de boot (Lilo ou Grub) também conhecido como “boot loader”. Em seguida o processo init, pai de todos os processos, é executado e se encarrega do restante do trabalho.

O init lê as informações no arquivo /etc/inittab, o qual descreve quais processos serão executados durante a inicialização e operação do sistema. A primeira linha do /etc/inittab, linha “id”, define o runlevel do sistema, por padrão o modo multiusuário, modo 3. O quadro abaixo destaca algumas seções do inittab, referidas aos diferentes runlevels, como referência.

...

# Default runlevel. (Do not set to 0 or 6)
id:3:initdefault:

# System initialization (runs when system boots).
si:S:sysinit:/etc/rc.d/rc.S

# Script to run when going single user (runlevel 1).
su:1S:wait:/etc/rc.d/rc.K

# Script to run when going multi user.
rc:2345:wait:/etc/rc.d/rc.M

...

# Runlevel 0 halts the system.
l0:0:wait:/etc/rc.d/rc.0

# Runlevel 6 reboots the system.
l6:6:wait:/etc/rc.d/rc.6

...

# Runlevel 4 also starts /etc/rc.d/rc.4 to run a display manager for X.
# Display managers are preferred in this order:  gdm, kdm, xdm
x1:4:respawn:/etc/rc.d/rc.4

# End of /etc/inittab

Na sequência, é executado o scripts rc.S, como definido na linha “si” do inittab. Este script prepara o hardware do sistema: habilita a memória virtual; limpa logs e alguns diretórios; inicializa dispositivos Plug and Play; carrega módulos do kernel; configura PCMCIA; portas usb; seriais e executa os scripts System V que geralmente não existem no Slackware; monta partições do disco; …

Tanto no modo 3 (multiusuário), quanto no 4 (login gráfico), o próximo script a ser executado será o rc.M. Este script é responsável por atualizar os links de bibliotecas e diversos caches de ícones, fontes entre outros, e também configurar o ambiente de rede, iniciar o syslog, udev, levantar todos os serviços de rede, configurar dispositivos conectados às portas usb, scsi e ieee1394, configurar a acpi, e iniciar o d-bus, hal, bluetooth, samba, cups, …

Se estiver utilizando o runlevel 4, o script rc.4 é chamado para levantar o login gráfico, onde são buscados na ordem o gdm, kdm ou o xdm, o que encontrar primeiro.

As alterações discutidas neste texto se concentram nos scripts rc.S e, mais especificamente, no rc.M, onde as otimizações no tempo de boot são mais facilmente alcançadas.

Todos os testes foram feitos em um notebook HP dv6770se, com 4GB de RAM e um HD 7200rpm. A tabela abaixo apresenta os tempos de carga nesta máquina.

[TABLE=39]

Outros ambientes gráficos não apresentados na tabela acima como Fluxbox, BlackBox, Window Maker,… , são muito rápidos na carga, algo entre 2s a 4s. No entanto são muito limitados em recursos e em sua configuração.

O tempo de boot trabalhado neste texto se concentra mais especificamente no item 2 da tabela acima, que consiste no tempo contado desde a inicialização do kernel, execução do init com as chamadas aos scripts rc.S e rc.M, terminando pouco antes da inicialização dos terminais tty1-6, em modo multiusuário, init 3.

Como tive que fazer muitas alterações nos scripts e dar diversos boots no sistema, acabei por dispensar o modo gráfico para agilizar o acesso, ainda por que não há muito o que fazer no carregamento do kde/xfce…, para agilizar a sua inicialização.

2.1. Medindo o tempo de Boot

Na primeira vez que tentei documentar estes procedimentos (está já é a terceira tentativa) medi os tempos de boot com um cronômetro digital, o que foi muito entediante e pouco preciso. Uma busca pela internet apresenta algumas opções interessantes e bem mais eficientes, como pode ser visto no texto Measuring Boot-up Time.

Dentre as opções encontradas, optei por empregar uma solução simples, que em princípio já estivesse incorporado ao sistema, sem ter que instalar novos aplicativos e principalmente fazer adições à arvore do kernel, com a aplicação de patchs. Por isto escolhi o Printk Times.

O Printk Times adiciona à rotina printk, rotina de impressão padrão do kernel, a impressão do tempo de operação do sistema à cada mensagem impressa no log padrão. O Printk Times está presente no kernel desde a versão 2.6.11, de forma que não será necessário aplicação de patchs para utilizá-lo.

Para habilitá-lo basta enviar um “1” para o parâmetro time do módulo printk, como nas linhas abaixo, que todas as mensagens emitidas pelo kernel serão precedidas pela impressão do tempo decorrido desde a carga deste, em segundos.

echo 1 > /sys/module/printk/parameters/time
[prompt]echo "Boot time log message" > /dev/kmsg
[prompt]dmesg | tail -3
ata1.00: configured for UDMA/133
ata1: EH complete
[ 241.036361] Boot time log message

Como mostra acima, a última linha indica que a mensagem “Boot time log message” foi enviada para a saída de log do kernel 241,036361s após sua inicialização.

2.1.1. Script para registrar o tempo de boot

Para o registro do tempo de boot criei o script abaixo em /usr/local/sbin/boottime:

#!/bin/bash
#
STIME="/sys/module/printk/parameters/time"
BOOT_LOG="/root/BOOT_TIMES"

[ ! -e $BOOT_LOG ] && touch $BOOT_LOG

echo 1 > $STIME

echo "Boot time log message" > /dev/kmsg
tt=`dmesg | tail -1 | awk '{print $2}'`
echo 0 > $STIME
d=`date`
echo "Boot time: ${tt/]/}s (${d})" | tee -a $BOOT_LOG

O Arquivo em BOOT_LOG irá armazenar os registros dos tempos de boot a cada inicialização do sistema. Para isto acontecer, ainda será necessário adicionar uma chamada para este script em /etc/rc.d/rc.M.

Poderia colocar esta chamada no script rc.local, mas não se iluda, as mudanças que serão feitas a estes scripts são muitas, de forma que e uma a mais não fará muita diferença. Adicione a chamada ao boottime no final do script rc.M, com nas linhas abaixo:

#!/bin/sh
#
# rc.M          This file is executed by init(8) when the system is being
#               initialized for one of the "multi user" run levels (i.e.
.
.
.
# Start the local setup procedure.
if [ -x /etc/rc.d/rc.local ]; then
  . /etc/rc.d/rc.local
fi

# Register boot time
/usr/local/sbin/boottime

# All done.

Isto garante que qualquer chamada adicionada ao rc.local será executada antes do registro do tempo de boot.

Embora o foco deste texto seja o boot em modo texto, caso for usar o modo gráfico, com login automático em um usuário no XFce, pode colocar a chamada ao script boottime em ”Configurações -> Sessão e Inicialização -> Início automático de aplicativo”, usando o comando sudo, como na figura abaixo:

O mesmo pode ser feito no KDE em ”System Settings -> Startup and Shutdown -> Autostart”. Em seguida, adicione a permissão para a execução do script sem passoword, adicionando a linha abaixo ao /etc/sudoers:

seu_usuário ALL=NOPASSWD: /usr/local/sbin/boottime

Para terminar, se estiver usando o kdm como gerenciador de login, acesse o ”System Settings -> Login Screen -> Convennience” e habilite o auto login com o seu usuário.

Com isto a todo boot em modo gráfico (modo 4), será aberto um terminal xterm com o tempo de boot e ao mesmo tempo registrá-lo em BOOT_LOG.

2.1.2. Registrando o tempo de execução de um comando/Script

Se tiver interesse em conhecer o tempo de execução de algum aplicativo em especial, como por exemplo o script rc.hald, o comando time dá conta do recado, sem a necessidade de mais invenções. Como exemplo, o script rc.M foi alterado pata acompanhar o tempo de execução do rc.hald abaixo:

...
# Start HAL:
if [ -x /etc/rc.d/rc.hald ]; then
  time sh /etc/rc.d/rc.hald start
fi
...

Isto irá imprimir uma mensagem inconfundível durante o seu boot, que lhe permitirá acompanhar o tempo de execução do script em questão. Isto pode ser útil para verificar como algumas mudanças podem interferir pontualmente em outros processos.

Especificamente no caso do rc.hald, processos executados em background, como o ldconfig e o fc-cache iniciados pelo script rc.M, faziam com que o rc.hald levasse 4s para iniciar. Quando removido tais processos, o tempo de carga do rc.hald caiu para 2s, como mostra a mensagem durante o boot.

...
Starting HAL daemon:  /usr/sbin/hald --daemon=yes

real    0m1.988s
user    0m0.041s
sys     0m0.036s
...

2.2. Mais Algumas Palavras Sobre o Tempo de boot

Uma observação imediata ao se tentar medir o tempo de inicialização de um sistema é que ele oscila muito. Mesmo se tratando de uma máquina que, em princípio, realiza as mesmas operações a cada inicialização, a sincronização dos diversos processos, barramentos e respostas a diversos sistemas, nem sempre culminam na otimização do tempo de inicialização. Isto faz com que o tempo oscile muito, em até 10% entre medidas.

Abaixo apresento uma lista com os registros de boot em minha máquina, já com algumas mudanças apresentadas neste texto, especificamente as seções 3.1, 3.2 e 3.3:

* httpd+sshd+svn+trac+VirtualBox:
Boot time: 43.196628s (Wed Sep 28 15:55:38 BRT 2011)
Boot time: 43.669516s (Wed Sep 28 16:03:47 BRT 2011)
Boot time: 42.770043s (Wed Sep 28 16:05:32 BRT 2011)
Boot time: 41.520989s (Wed Sep 28 16:20:05 BRT 2011)
Boot time: 40.486461s (Wed Sep 28 16:35:47 BRT 2011)
Boot time: 43.479524s (Wed Sep 28 16:37:39 BRT 2011)
Boot time: 40.220618s (Wed Sep 28 16:43:53 BRT 2011)
Boot time: 40.829324s (Wed Sep 28 16:45:59 BRT 2011)
Boot time: 40.649360s (Wed Sep 28 19:05:34 BRT 2011)
Boot time: 40.620112s (Wed Sep 28 21:13:49 BRT 2011)
Boot time: 41.374149s (Thu Sep 29 08:18:18 BRT 2011)
Boot time: 44.672557s (Thu Sep 29 10:53:33 BRT 2011)
Boot time: 39.886331s (Thu Sep 29 14:49:19 BRT 2011)

Observe que os tempos de boot variaram de 39,89s até 44,67s, uma variação de 4,78s. Por conta disto é necessário diversos boots antes de se tirar alguma conclusão sobre os benefícios de uma alteração. Uma análise mais adequada seria trabalhar com médias e desvio médio, em ao menos uma dezena ou mais de amostras. Neste caso posso dizer que o tempo de boot neste ponto foi de (42 ± 1)s, usando a média e o desvio da média para calcular os tempos, definidos por:  \bar{t} = \frac{1}{n} \sum_{1}^{n}{t_i} e  \Delta t = \frac{1}{n} \sum_{1}^{n}{ | \bar{t} - t_i | }

3. Otimizando o Tempo de boot

Nesta seção é apresentado as modificações feitas ao sistema, em especial o rc.M. Boa parte das alterações são simples de realizar e não trazem impacto significativo às funcionalidades do sistema, mas outras exigem conhecimento especifico sobre como estas estas podem afetar a inicialização dos serviços utilizados. Por isto aconselho cautela nas mudanças.

3.1. O gerenciador de boot

Embora a carga do kernel não entre na contagem de tempo neste texto, o Lilo não é muito ágil neste processo e por isto aconselho substitui-lo pelo Grub. Além disto, o Lilo apresenta o inconveniente de necessitar ser reescrito na MBR a cada novo kernel instalado, o que pode ser muito necessário se o seu objetivo é melhorar o tempo de boot.

Para a instalação do Grub2 no Slackware64 aconselho a lida do texto “Grub2 no Slackware64”. O grub leva mais tempo para apresentar o menu de seleção de sistema, mas após isto a carga do kernel é bem mais rápida que no Lilo. Em um teste numa máquina virtual a diferença na carga do kernel foi de 5s a menos no boot com o kernel padrão. Esta diferença depende muito do suporte à controladora de disco no boot loader, sendo que o do Grub geralmente é muito melhor.

3.2. O Kernel

Otimizar o kernel não apenas otimiza o seu tempo de carga, mas também o tempo de busca por hardware, uma vez que o conjunto de módulos compilados fica restrito ao hardware disponível de sua máquina.

Não vou descrever aqui a compilação do kernel, pois este é um processo muito específico a cada hardware, o que por si só já daria um longo texto. Existem diversos textos disponíveis da internet que podem lhe auxiliar, mas caso não tenha prática com este procedimento, aconselho prosseguir com o kernel padrão.

Com um kernel otimizado é possível reduzir de 3 a 4s o tempo de boot.

3.3. Reclamando a Área Nobre

Esta alteração foi a última que fiz ao meu sistema, no entanto, como optei por fazer as medições dos tempos de boot com mais critério, achei por bem apresentá-la logo no início do texto. Esta mudança no sistema não é necessária, mas é uma dica fundamental para a utilização eficiente do disco rígido, um dispositivo decisivo no boot de qualquer sistema. Entretanto toda esta discussão é desnecessária se estiver usando um SSD como mídia de armazenamento do sistema.

A utilização adequada do disco rígido não apenas melhorar o desempenho do boot, mas como do sistema como um todo. A ideia é simples mas a sua execução pode ser tediosa. O objetivo e mover a partição com o seu sistema para a área nobre do disco, ou seja, a primeira partição do disco. Não é necessário reformatar e reinstalar o seu GNU/Linux (o mesmo não posso dizer do Windows), basta mover os conteúdos entre as partições no disco. Eventualmente você vai necessitar de um disco externo, caso não possua espaço em disco suficiente para a manobra dos conteúdos.

3.3.1. Usando Várias Partições

O uso de várias partições no disco, permite não apenas usar o disco com mais eficiência, mas também é uma questão de segurança para os seus dados. O uso de pastas como a /home em uma partição separada do sistema, lhe permite executar repetidas instalações do sistema sem afetar em nada os dados dos usuários. Isto também é bem útil quando se deseja experimentar outras distribuições, onde cada distribuição, em uma partição raiz diferente, pode compartilhar os mesmos dados no /home.

Como o foco aqui é desempenho e vou me ater a este aspecto do particionamento. A questão do desempenho é basicamente física. Quando girando a uma velocidade constante \omega, as trilhas mais internas do disco de moverão a uma velocidade linear menor que as trilhas mais externas, uma vez que a velocidade linear depende do raio da trilha em questão (v = r \omega). Isto faz com que os dados nas trilhas mais externas possam ser lidos a uma velocidade mais alta.

Além disto, as trilhas mais externas possuem um comprimento maior (C = 2 \pi r), e por isto comportam mais informações gravadas que as trilhas mais internas, que são mais curtas, pois possuem menor raio. Isto também faz com que no acesso às tilhas mais externas, a cabeça de leitura do disco necessite se move menos entre trilhas, uma vez que estas armazenam mais informação que as internas. Por consequência, nas trilhas mais internar este movimento da cabeça de leitura é mais frequente.

Uma vez que as partições se restringem a uma faixa do disco, com apenas um conjunto de trilhas, isto impede a fragmentação de arquivos por todo o disco, o que também restringe a movimentação da cabeça de leitura, entre trilhas adjacentes ou mesmo próximas.

Este conjunto de fatores esclarece o por que das partições mais externas serem mais rápidas ao acesso que as partições mais internas. Como exemplo apresento abaixo uma tabela com as taxas de leitura/escrita no disco de minha máquina, em diferentes partições, testados com o comando “hdparm -t /dev/sdaN”.

[TABLE=40]

Observe que a taxa de acesso cai de 102MB/s, na primeira partição (/dev/sda1), para 63MB/s, na última partição (/dev/sda11). Isto resulta em uma redução de quase 40% na taxa de transmissão dos dados, o que ilustra bem meu ponto de vista acima.

3.3.2. Migrando o root (/)

O ideal é reorganizar seu disco com foco no uso que deseja dar a ele, deixando as primeiras partições para instalar o seus sistema mais importantes, um bom espaço para a área dos usuários (/home) e as últimas para filmes, músicas, livros e arquivos de backup em geral, onde taxas de 60MB/s ou 40MB/s são suficiente para a sua exibição.

Para prossegui com as alterações no disco, com acesso irrestrito a suas partições, utilize o disco de instalação do Slackware e reinicie o sistema. Aqui suponho que se saiba usar habilmente o comando fsck ou outra ferramenta similar.

Neste texto a raiz do Slackware esta instalado na quarta partição do disco, neste caso a partição /dev/sda6, de 15GB. Reinicie o sistema com o disco de boot e altere as primeiras partições para poder mover seu sistema.

Neste caso foi criado uma partição de 15G no início do disco, onde estava uma partição do Windows:

/dev/sda1              63    31246424    15623181   83  Linux
/dev/sda2   *    31246425   125833213    47293394+   7  HPFS/NTFS/exFAT
/dev/sda3       125833214   976773167   425469977    5  Extended
/dev/sda5       125833216   134221823     4194304   82  Linux swap
/dev/sda6       134221887   167428178    16603146   83  Linux
/dev/sda7       167428242   197133614    14852686+  83  Linux
...

Em seguida crie alguns diretórios para motar as partições destino (sda1) e fonte (sda6), monte as partições e faça uma cópia dos conteúdos de uma partição para a outra. Algo como as linhas abaixo:

mkdir /sda1 /sda6
[prompt]mount /dev/sda6 /sda6
[prompt]mount /dev/sda1 /sda1
[prompt]cp -a /sda6/* /sda1/

Isto lhe garante uma cópia fiel dos conteúdos da partição /dev/sda6 para a /dev/sda1, não é necessário usar o dd ou qualquer outra ferramenta para isto. Em seguida edite o fstab da cópia, modificando o dispositivo para a nova partição /:

vim /sda1/etc/fstab
/dev/sda5        swap           swap        defaults             0   0
/dev/sda1        /              jfs         defaults             1   1
/dev/sda8        ...

O último passo é criar uma entrada no grub.cfg vigente, no meu caso o /sda6/boot/grub/grub.cfg, para o novo Slackware, em meu caso ficou assim:

menuentry "Slackware64 Novo" --class gnu-linux --class gnu --class os {
        insmod jfs
        set root='(hd0,1)'
        echo    Loading New Slackware ...
        linux   /boot/vmlinuz root=/dev/sda1 ro
}

Como estava com o Slackware nas primeiras partições, ainda bem próximo do início do disco, o ganho não foi muito grande, algo em torno de 3s. Neste ponto, o tempo de boot baixou para os (42 ± 1)s, apresentado na seção 2.2 acima.

3.4. rc.local para background

O rc.local é um script utilizado para o administrador e também por alguns aplicativos, como o VirtualBox o faz, para carregar serviços, módulos e mesmo deamons, sem que para isto tenha que alterar os outros scripts em /etc/rc.d/.

Em meu caso o utilizo para carregar o trac, subversion, rc.update (script apresentado adiante), além de carregar os módulos do VirtualBox. Todos estes processos consomem uns 5s na inicialização. Obviamente, se seu rc.local estiver vazio, esta alteração não trará nenhum ganho.

Para colocar o rc.local em background edite o /etc/rc.d/rc.M e altere a linha de carga do rc.local, para algo como:

...
# Start the local setup procedure.
if [ -x /etc/rc.d/rc.local ]; then
  . /etc/rc.d/rc.local 2>&1 > /var/log/rc_local.log &
fi
..

Para não tumultuar as mensagens de boot enviadas ao terminal, é conveniente redirecionar as mensagens para um arquivo de log como /var/log/rc_local.log. Com esta mudança o tempo de boot caiu para (36,9 ± 0,8)s, uma redução de 5s no tempo de boot.

3.5. Concentrando Caches em rc.update

O script rc.M executa alguns grupos de comandos que não são essenciais a todo boot, sendo necessários apenas quando novas bibliotecas, fontes, ícones, … são instalados no sistema. Por isto estes comadas podem ser removidos para na maioria das inicializações de sistema, sem qualquer perda.

Reuni estes chamadas no script rc.update, apresentado a seguir:

#!/bin/bash
#
# This script executes boot commands if new packages are installed on the
# system.
#
# The checking is done by reading the modification date in the directory 
# /var/log/packages
#
# by Rudson R. Alves
# version 2.0
#

UPDATE_DIR="/etc/update_cache"
PKGS_DIR="/var/log/packages"
UPDATE="off"

function get_date() {
  ls -la /var/log/ | awk '/ packages/ {print $5 $6 $7 $8}'
}

function update_cache() {
  echo -e "\e[33;1m"
  # Update all the shared library links:
  if [ -x /sbin/ldconfig ]; then
    echo "Updating shared library links:  /sbin/ldconfig"
    /sbin/ldconfig &
  fi
  
  # Update the X font indexes:
  if [ -x /usr/bin/fc-cache ]; then
    echo "Updating X font indexes:  /usr/bin/fc-cache -f"
    /usr/bin/fc-cache -f &
  fi

  # Update any existing icon cache files:
  if find /usr/share/icons 2> /dev/null | grep -q icon-theme.cache ; then
    for theme_dir in /usr/share/icons/* ; do
      if [ -r ${theme_dir}/icon-theme.cache ]; then
        echo "Updating icon-theme.cache in ${theme_dir}..."
        /usr/bin/gtk-update-icon-cache -t -f ${theme_dir} 1> /dev/null 2> /dev/null
      fi
    done
    # This would be a large file and probably shouldn't be there.
    if [ -r /usr/share/icons/icon-theme.cache ]; then
      echo "Deleting icon-theme.cache in /usr/share/icons..."
      #/usr/bin/gtk-update-icon-cache -t -f /usr/share/icons 1> /dev/null 2> /dev/null
      rm -f /usr/share/icons/icon-theme.cache
    fi
  fi

  # Update mime database:
  if [ -x /usr/bin/update-mime-database -a -d /usr/share/mime ]; then
    echo "Updating MIME database:  /usr/bin/update-mime-database /usr/share/mime"
    /usr/bin/update-mime-database /usr/share/mime 1> /dev/null 2> /dev/null
  fi

  # These GTK+/pango files need to be kept up to date for
  # proper input method, pixbuf loaders, and font support.
  if [ -x /usr/bin/update-gtk-immodules ]; then
    /usr/bin/update-gtk-immodules --verbose
  fi
  if [ -x /usr/bin/update-gdk-pixbuf-loaders ]; then
    /usr/bin/update-gdk-pixbuf-loaders --verbose
  fi
  if [ -x /usr/bin/update-pango-querymodules ]; then
    /usr/bin/update-pango-querymodules --verbose
  fi
  echo -e "\e[m"

}


# -------------------------------------------
#                  Script
# -------------------------------------------
#
echo -en "Check $PKGS_DIR for new packages... "

# check if exist date file UPDATE_DIR
if [ ! -e $UPDATE_DIR/date ]; then
  mkdir $UPDATE_DIR 2>/dev/null
  NEW_DATE=`get_date`
  echo $NEW_DATE > $UPDATE_DIR/date
  UPDATE="on"
fi

OLD_DATE=`cat $UPDATE_DIR/date`

# if UPDATE off, create get new date to check
if [ "$UPDATE" == "off" ]; then
  NEW_DATE=`get_date`
  # check modification date
  if [ "$OLD_DATE" != "$NEW_DATE" ]; then
    UPDATE="on"
  fi
fi

if [ "$UPDATE" == "on" ]; then
  echo -e "\e[34;1m        [ Update caches... ]\e[m"
  update_cache
  echo $NEW_DATE > $UPDATE_DIR/date
else
  echo -e "\e[32;1m        [ Skip ]\e[m"
fi

Este script chama a função update_cache somente quando alguma alteração é feita ao conteúdo do diretório /var/log/packages/, ou seja, quando um novo pacote for instalado ou removido do sistema. Embora nem todo pacote instalado ou removido do sistema deva, necessariamente, levar a atualização destes caches, esta solução tem sido muito bem vinda, reduzindo significativamente o tempo na maioria das inicializações.

Este script pode ser colocado no rc.local para ser executado ao final da carga do sistema, em background, sem nenhuma perda.

#!/bin/sh
#
# /etc/rc.d/rc.local:  Local system initialization script.
...
if [ -x /etc/rc.d/rc.update ]; then
  . /etc/rc.d/rc.update
fi
...

Com esta mudança, o tempo de carga em meu sistema passou para (21,4 ± 0,5)s, uma redução de 15s. Esta será a maior redução ao tempo de boot alcançado com as mudanças apresentadas aqui. As demais alterações trarão reduções bem menores, como variações de 1 a 3 segundos, mas nem por isto são menos significativas.

3.6. Checar Disco apenas quando necessário

Durante a inicialização do sistema, o script rc.S verifica os discos com o comando fsck, para corrigir pequenos problemas que podem ocorrer no sistema de arquivos, geralmente quando o sistema é desligado inadequadamente (falta de energia, travamentos, …). Fora estas ocasiões, o fsck não é necessário, pois os discos foram desmontados adequadamente.

Neste ponto sugiro que adicione o script rc.fsck_check, abaixo, ao /etc/rc.d/rc.local_shutdown:

#!/bin/bash
#
# script rc.fsck_check
# by Rudson Alves
#
MAX_BOOT=20
rm /etc/fastboot 2>/dev/null

if [ -e /etc/fsck_check/count ]; then
  COUNT=`cat /etc/fsck_check/count`
else
  mkdir /etc/fsck_check 2>/dev/null
  echo $MAX_BOOT > /etc/fsck_check/count
  let COUNT=$MAX_BOOT+1
fi

let COUNT--

if [ $COUNT -lt 0 ]; then
  echo -e "\e[31;1mFsck count -1: FSCK ON\e[m"
  echo $MAX_BOOT > /etc/fsck_check/count
else
  echo -e "\e[34;1mFsck count $COUNT: FAST BOOT\e[m"
  echo $COUNT > /etc/fsck_check/count
  touch /etc/fastboot
fi

O script rc.fsck_check apenas cria o arquivo /etc/fastboot sempre que o contador COUNT, iniciado com MAX_BOOT, não atingir zero. O resultado do contador fica armazenado em /etc/fsck_check/count. O rc.S verifica e existência deste arquivo para executar o fsck, após isto o remove.

O script rc.local_shutdown deve ser criado, pois não existe normalmente no sistema. O rc.local_shutdown é executado quase ao final do rc.0 (ou rc.6), no momento de desligar o sistema.

#!/bin/bash
#
# script rc.local_shutdown
#
# Check fsck boot time
if [ -x /etc/rc.d/rc.fsck_check ]; then
  /etc/rc.d/rc.fsck_check
fi

Caso tenha algum problema, sugiro colocar a chamada ao script rc.fsck_check pouco antes de desmontar o root, como na linha 240 do script rc.0, antes do /bin/sync.

Com estas mudanças, meu sistema passou a iniciar em (19,6 ± 0,4)s, uma redução de quase 2s.

3.7. O script rc.netservices

Como se trata de uma máquina com foco no uso como desktop, serviços de rede como http, trac, svn, ssh, ftp, bem como outros, podem ser iniciados em segundo plano, ou mesmo após a inicialização do X11.

Neste ponto proponho a maior das alterações ao script rc.M. A ideia é remover todas as chamadas à configurações e serviços de rede para um script a parte, chamado rc.netservices, apresentado a seguir:

#!/bin/sh
#
# rc.netservices
#
echo "Network services..."

# Set the hostname.
#if [ -r /etc/HOSTNAME ]; then
#  /bin/hostname $(cat /etc/HOSTNAME | cut -f1 -d .)
#else
#  # fall back on this old default:
#  echo "darkstar.example.net" > /etc/HOSTNAME
#  /bin/hostname darkstar
#fi

# Initialize the networking hardware.
if [ -x /etc/rc.d/rc.inet1 ]; then
  . /etc/rc.d/rc.inet1
fi

# Start networking daemons:
if [ -x /etc/rc.d/rc.inet2 ]; then
  . /etc/rc.d/rc.inet2
fi

# Start the Network Time Protocol daemon:
if [ -x /etc/rc.d/rc.ntpd ]; then
  sh /etc/rc.d/rc.ntpd start
fi

# Start wicd:
if [ -x /etc/rc.d/rc.wicd ]; then
  sh /etc/rc.d/rc.wicd start
fi

# Start dnsmasq, a simple DHCP/DNS server:
if [ -x /etc/rc.d/rc.dnsmasq ]; then
  /etc/rc.d/rc.dnsmasq start
fi

# Start snmpd:
if [ -x /etc/rc.d/rc.snmpd ]; then
  /etc/rc.d/rc.snmpd start
fi

# Start the print spooling system.  This will usually be LPRng (lpd) or CUPS.
if [ -x /etc/rc.d/rc.cups ]; then
  # Start CUPS:
  /etc/rc.d/rc.cups start
elif [ -x /etc/rc.d/rc.lprng ]; then
  # Start LPRng (lpd):
  . /etc/rc.d/rc.lprng start
fi

# Start netatalk. (a file/print server for Macs using Appletalk)
if [ -x /etc/rc.d/rc.atalk ]; then
  /etc/rc.d/rc.atalk
fi

# Start the SASL authentication server.  This provides SASL
# authentication services for sendmail:
if [ -x /etc/rc.d/rc.saslauthd ]; then
  . /etc/rc.d/rc.saslauthd start
fi

# Start the sendmail daemon:
if [ -x /etc/rc.d/rc.sendmail ]; then
  . /etc/rc.d/rc.sendmail start
fi

# Start the MySQL database:
if [ -x /etc/rc.d/rc.mysqld ]; then
  . /etc/rc.d/rc.mysqld start
fi

# Start Apache web server:
if [ -x /etc/rc.d/rc.httpd ]; then
  . /etc/rc.d/rc.httpd start
fi

# Start OpenLDAP:
if [ -x /etc/rc.d/rc.openldap ]; then
  . /etc/rc.d/rc.openldap start
fi

# Start Samba (a file/print server for Win95/NT machines).
# Samba can be started in /etc/inetd.conf instead.
if [ -x /etc/rc.d/rc.samba ]; then
  . /etc/rc.d/rc.samba start
fi

# All done.

Observe que o script rc.netservices inicia com a chamada ao script rc.inet1, quem de fato carrega as configurações de rede e levanta as suas interfaces. O rc.inet2 inicia os deamons de rede como montar as pastas nfs, o portmap, smb entre outros deamons.

Após o rc.inet2, é carregado o daemon Network Time Protocol, wicd, LPRng/CUPS, …, mantendo a mesma ordem original do script rc.M. Dependendo da aplicação do seu sistema a ordem destes processos pode ser alterada, mas é bom fazer isto com cautela para não ter surpresas indesejadas.

A seção seguinte apresenta o rc.M resultante, após a retirada destas linhas e as linhas do rc.update, além de alguns comentários sobre a melhor posição para fazer a chamada ao rc.netservices e conseguir um ganho significativo com estas mudanças.

3.8. Um rc.M quase final

O rc.M resultante é apresentado a seguir. As linhas que foram adicionadas aos scripts rc.netservices e rc.update foram removidas, para encurtar o texto, no entanto é aconselhado apenas comentá-las, até que estja certo das alterações. Embora não seja necessário, aproveitei e comentei também a seção quota, uma vez que não utilizo o serviço.

#!/bin/sh
#
# rc.M		This file is executed by init(8) when the system is being
#		initialized for one of the "multi user" run levels (i.e.
#		levels 1 through 6).  It usually does mounting of file
#		systems et al.
#
# Version:	@(#)/etc/rc.d/rc.M	2.23	Wed Feb 26 19:20:58 PST 2003
#
# Author:	Fred N. van Kempen, 
#		Heavily modified by Patrick Volkerding 
#

# Tell the viewers what's going to happen.
echo "Going multiuser..."

# Screen blanks after 15 minutes idle time, and powers down in one hour
# if the kernel supports APM or ACPI power management:
/bin/setterm -blank 15 -powersave powerdown -powerdown 60

# Set the hostname.
if [ -r /etc/HOSTNAME ]; then
  /bin/hostname $(cat /etc/HOSTNAME | cut -f1 -d .)
else
  # fall back on this old default:
  echo "darkstar.example.net" > /etc/HOSTNAME
  /bin/hostname darkstar
fi

# Set the permissions on /var/log/dmesg according to whether the kernel
# permits non-root users to access kernel dmesg information:
if [ -r /proc/sys/kernel/dmesg_restrict ]; then
  if [ $(cat /proc/sys/kernel/dmesg_restrict) = 1 ]; then
    touch /var/log/dmesg
    chmod 640 /var/log/dmesg
  fi
else
  touch /var/log/dmesg
  chmod 644 /var/log/dmesg
fi
# Save the contents of 'dmesg':
/bin/dmesg -s 65536 > /var/log/dmesg

# Initialize PCMCIA devices:
#
# NOTE: This used to be started near the top of rc.S so that PCMCIA devices
# could be fsck'ed along with the other drives.  This had some unfortunate
# side effects, however, since root isn't yet read-write, and /var might not
# even be mounted the .pid files can't be correctly written in /var/run and
# the pcmcia system can't be correctly shut down.  If you want some PCMCIA
# partition to be mounted at boot (or when the card is inserted) then add
# the appropriate lines to /etc/pcmcia/scsi.opts.
#
# Note that the stuff in /etc/pcmcia/ is only for 2.4.x kernels using
# 16-bit PCMCIA cards (not 32-bit Cardbus cards!).  For example, with a
# wireless card you might need to set options in /etc/pcmcia OR in
# /etc/rc.d/rc.wireless.conf, or even in /etc/rc.d/rc.inet1.conf (with
# extra options if needed for the encryption key, ESSID, etc.)
#
# Hopefully this situation will be unified in the future, but for now
# that's how it is...
#
if [ -x /etc/rc.d/rc.pcmcia ]; then
  . /etc/rc.d/rc.pcmcia start
  # The cards might need a little extra time here to initialize.
  sleep 5
fi

# Start the system logger.
if [ -x /etc/rc.d/rc.syslog -a -x /usr/sbin/syslogd -a -d /var/log ]; then
  . /etc/rc.d/rc.syslog start
fi

# If we are returning from single-user mode we will need to restart
# udevd on systems that use udev:
if grep -wq sysfs /proc/mounts && grep -q tmpfs /proc/filesystems ; then
  if ! grep -wq nohotplug /proc/cmdline ; then
    if [ -x /etc/rc.d/rc.udev ]; then
      /bin/sh /etc/rc.d/rc.udev start
    fi
  fi
fi

# Initialize the networking hardware.
#if [ -x /etc/rc.d/rc.netservices ]; then
#  . /etc/rc.d/rc.netservices 2>&1 > /var/log/rc.netservices &
#fi

# Look for additional USB/SCSI/IEEE1394/etc devices on multiple LUNs:
if [ -x /etc/rc.d/rc.scanluns ]; then
  . /etc/rc.d/rc.scanluns
fi

# Mount any additional filesystem types that haven't already been mounted:
mount -a -v 2> /dev/null | grep -v "already mounted"

# Start the Control Script for automounter:
if [ -x /etc/rc.d/rc.autofs ]; then
  sh /etc/rc.d/rc.autofs start
fi

# Remove stale locks and junk files (must be done after mount -a!)
/bin/rm -f /var/lock/* /var/spool/uucp/LCK..* /tmp/.X*lock /tmp/core /core 2> /dev/null

# Remove stale hunt sockets so the game can start.
if [ -r /tmp/hunt -o -r /tmp/hunt.stats ]; then
  echo "Removing your stale hunt sockets from /tmp."
  /bin/rm -f /tmp/hunt*
fi

# Ensure basic filesystem permissions sanity.
chmod 755 / 2> /dev/null
chmod 1777 /tmp /var/tmp

# Start APM or ACPI daemon.
# If APM is enabled in the kernel, start apmd:
if [ -e /proc/apm ]; then
  if [ -x /usr/sbin/apmd ]; then
    echo "Starting APM daemon:  /usr/sbin/apmd"
    /usr/sbin/apmd
  fi
elif [ -x /etc/rc.d/rc.acpid ]; then # otherwise, start acpid:
  . /etc/rc.d/rc.acpid start
fi

# Start D-Bus:
if [ -x /etc/rc.d/rc.messagebus ]; then
  sh /etc/rc.d/rc.messagebus start
fi

# Start console-kit-daemon:
if [ -x /etc/rc.d/rc.consolekit ]; then
  sh /etc/rc.d/rc.consolekit start
fi

# Start HAL:
if [ -x /etc/rc.d/rc.hald ]; then
  sh /etc/rc.d/rc.hald start
fi

# Initialize the networking hardware.
if [ -x /etc/rc.d/rc.netservices ]; then
  . /etc/rc.d/rc.netservices 2>&1 > /var/log/rc.netservices &
fi

# Start Bluetooth:
if [ -x /etc/rc.d/rc.bluetooth ]; then
  sh /etc/rc.d/rc.bluetooth start
fi

# Start smartd, which monitors the status of S.M.A.R.T. compatible
# hard drives and reports any problems.  Note some devices (which aren't
# smart, I guess ;) will hang if probed by smartd, so it's commented out
# by default.
#if [ -x /usr/sbin/smartd ]; then
#  /usr/sbin/smartd
#fi

# If we're using udev, make /dev/cdrom and any other optical drive symlinks
# if some udev rule hasn't made them already:
if grep -wq sysfs /proc/mounts && grep -q tmpfs /proc/filesystems; then
  if ! grep -wq nohotplug /proc/cmdline ; then
    if [ -x /lib/udev/rc.optical-symlinks -a -x /etc/rc.d/rc.udev ]; then
      /bin/sh /lib/udev/rc.optical-symlinks
    fi
  fi
fi

# Monitor the UPS with genpowerd.
# To use this, uncomment this section and edit your settings in
# /etc/genpowerd.conf (serial device, UPS type, etc).  For more information,
# see "man genpowerd" or the extensive documentation in the
# /usr/doc/genpower-*/ directory.
# You'll also need to configure a similar block in /etc/rc.d/rc.6 if you want
# support for stopping the UPS's inverter after the machine halts.
#if [ -x /sbin/genpowerd ]; then
#  echo "Starting genpowerd daemon..."
#  /sbin/genpowerd
#fi

# Turn on process accounting.  To enable process accounting, make sure the
# option for BSD process accounting is enabled in your kernel, and then
# create the file /var/log/pacct (touch /var/log/pacct).  By default, process
# accounting is not enabled (since /var/log/pacct does not exist).  This is
# because the log file can get VERY large.
if [ -x /sbin/accton -a -r /var/log/pacct ]; then
  chmod 640 /var/log/pacct
  /sbin/accton /var/log/pacct
fi

# Start crond (Dillon's crond):
# If you want cron to actually log activity to /var/log/cron, then change
# -l notice to -l info to increase the logging level.
if [ -x /usr/sbin/crond ]; then
  /usr/sbin/crond -l notice
fi

# Start atd (manages jobs scheduled with 'at'):
if [ -x /usr/sbin/atd ]; then
  /usr/sbin/atd -b 15 -l 1
fi

# Slackware-Mini-Quota-HOWTO:
# To really activate quotas, you'll need to add 'usrquota' and/or 'grpquota' to
# the appropriate partitions as listed in /etc/fstab.  Here's an example:
#
# /dev/hda2      /home      ext3     defaults,usrquota      1   1
#
# You'll then need to setup initial quota files at the top of the partitions
# to support quota, like this:
# touch /home/aquota.user /home/aquota.group
# chmod 600 /home/aquota.user /home/aquota.group
#
# Then, reboot to activate the system.
# To edit user quotas, use 'edquota'.  See 'man edquota'.  Also, the
# official Quota Mini-HOWTO has lots of useful information.  That can be found
# here:  /usr/doc/Linux-HOWTOs/Quota

# Check quotas and then turn quota system on:
#if grep -q quota /etc/fstab ; then
#  for quotafs in $(awk '/quota/ {print $2}' /etc/fstab) ; do
#    /bin/rm -f $quotafs/{a,}quota.{group,user}.new
#  done
#  if [ -x /sbin/quotacheck ]; then
#    echo "Checking filesystem quotas:  /sbin/quotacheck -avugm"
#    /sbin/quotacheck -avugm
#  fi
#  if [ -x /sbin/quotaon ]; then
#    echo "Activating filesystem quotas:  /sbin/quotaon -avug"
#    /sbin/quotaon -avug
#  fi
#fi

# Load ALSA (sound) defaults:
if [ -x /etc/rc.d/rc.alsa ]; then
  . /etc/rc.d/rc.alsa
fi

# Load a custom screen font if the user has an rc.font script.
if [ -x /etc/rc.d/rc.font ]; then
  . /etc/rc.d/rc.font
fi

# Load a custom keymap if the user has an rc.keymap script.
if [ -x /etc/rc.d/rc.keymap ]; then
  . /etc/rc.d/rc.keymap
fi

# Start the GPM mouse server:
if [ -x /etc/rc.d/rc.gpm ]; then
  . /etc/rc.d/rc.gpm start
fi

# If there are SystemV init scripts for this runlevel, run them.
if [ -x /etc/rc.d/rc.sysvinit ]; then
  . /etc/rc.d/rc.sysvinit
fi

# Start the local setup procedure.
if [ -x /etc/rc.d/rc.local ]; then
  . /etc/rc.d/rc.local 2>&1 > /var/log/rc_local.log &
fi

/usr/local/sbin/boottime
# All done.

Inicialmente havia colocado a chamada ao script rc.netservices no mesmo lugar em que se encontrava a chamada ao rc.inet1, executando-o em background. No entanto isto fez com que o rc.hald aumentasse de 2s para 5s o seu tempo de execução, suprimindo grande parte do ganho no tempo de boot com a criação do rc.netservices. O sistema passou a iniciar com uma redução de apenas 1s.

Aparentemente o rc.hald exige muito processamento ou/e acesso a dispositivos do hardware, ficando muito sensível ao compartilhamento com com outros processos rodando em background.

Uma solução foi mover o rc.netservices para depois do rc.hald, o que gerou um resultado bem satisfatório, o sistema passou a iniciar em (15,9 ± 0,3 )s, uma redução de quase 4s.

Outra opção seria mover o rc.hald para o início do rc.M, pouco antes do rc.netservices. Acabei utilizando a primeira opção, pois esta estava mais pensada e testada em experimentos anteriores.

3.9. Autofs, montando partições por demanda

O uso do autofs não é fundamental, o objetivo aqui foi mais documentar e testar uma sugestão que li em uma lista de discussão na rede. A maior parte do tempo desprendido com as partições durante o boot é mais na checagem da integridade do sistema de arquivo (com o fsck), do que na montagem em si, ao menos foi o que percebi com o sistema de arquivos jfs. O jfs já é muito rápido na montagem e mesmo na checagem, talvez por isto o tempo ganho aqui não tenha sido significativo, bem ao contrário, acabou sendo custoso.

Para fazer valer a montagem por demanda, foi necessário colocar o autofs em background, o que garantiu um ganho pequeno no tempo de inicialização. No entanto alguns cuidados devem ser tomados aqui, para que as partições com conteúdos necessários para outros serviços sejam disponibilizados em tempo, uma vez que o autofs pode não estar adequadamente levantado.

A montagem por demanda pode ser útil para algumas partições de armazenamento de arquivos que geralmente não são muito requisitadas como:

  • linux – partição com distribuições Linux (imagens de dvd/cd e pacotes);
  • pessoal – partição com arquivos pessoais como documentos, fotos e outros;
  • movies – partição com arquivos de vídeo em geral;
  • windows – partição com o windows instalado;
  • others – partição para outras distribuições Linux/BSD, essencialmente para testes

A montagem e, principalmente, a checagem de todos estas partições geralmente consome um tempo significativo, o qual depende do tamanho das partições e do volume nelas ocupado. É importante identificar com precisão quais partições podem ser montadas por demanda.

3.9.1. Configurando o autofs

Para colocar em montagem automática as partições listadas acima, comesse por adicionar um noauto no /etc/fstab, para que estas partições não sejam montadas no momento do boot.

/dev/sda5         swap                     swap    defaults               0   0
/dev/sda6         /                        jfs     defaults               1   1
/dev/sda8         /home                    jfs     defaults               1   2
/dev/sda9         /mnt/sda/linux           jfs     noauto,defaults        1   2
/dev/sda10        /mnt/sda/pessoal         jfs     noauto,defaults        1   2
/dev/sda11        /mnt/sda/movies          jfs     noauto,defaults        1   2
/dev/sda7         /mnt/sda/other           jfs     noauto,defaults        1   0
/dev/sda1         /mnt/sda/win             vfat    noauto                 1   0
devpts            /dev/pts                 devpts  gid=5,mode=620         0   0
proc              /proc                    proc    defaults               0   0
tmpfs             /dev/shm                 tmpfs   defaults               0   0
none              /proc/bus/usb            usbfs   devmode=664,devgid=83  0   0
/dev/mapper/alves /home/alves              ext2    user,noauto,exec       0   0

Agora edite o /etc/auto.master e adicione a linha

/mnt/sda  /etc/auto.sda  --timeout=30

Está linha dirá ao autofs para montar a pasta /mnt/sda com as premissas do /etc/auto.sda e com a opção timeout de 30s, o que desmontará o sistema automaticamente após 30s sem acesso. As demais linhas deste arquivo podem ser comentadas, para não interferir nos processos de montagem do KDE, XFce, ou outro ambiente que estiver usando.

Em seguida crie os diretórios /mnt/sda com o comando abaixo:

mkdir -p /mnt/sda/{linux,pessoal,movies,others,win}

Criar estes subdiretórios não é necessário, mas eles irão facilitar a montagem manual se por algum motivo o autofs tiver que ser desabilitado. Em /etc/auto.sda coloque as informações para o sistema montar as pastas:

linux    -fstype=jfs,rw  :/dev/sda9
pessoal  -fstype=jfs,rw  :/dev/sda10
movies   -fstype=jfs,rw  :/dev/sda11
other    -fstype=jfs,rw  :/dev/sda7
win      -fstype=vfat,rw :/dev/sda1

Após isto basta iniciar o autofs que as partições serão montadas automaticamente:

/etc/rc.d/rc.autofs start

Um ls em /mnt/sda não retornará nada, mas um ls em /mnt/sda/linux/ fará com que a partição /dev/sda9 seja montada. A barra (/) ao final do diretório, no comando ls, é necessária para que o autofs monte o diretório. Para terminar, faça links simbólicos dos pontos de montagem para os pontos de acessos mais convenientes no seu sistema, como por exemplo:

ln -s /mnt/sda/linux   /home/ftp/linux
[prompt]ln -s /mnt/sda/pessoal /home/ftp/pessoal
[prompt]ln -s /mnt/sda/movies  /home/ftp/movies
[prompt]ln -s /mnt/sda/other   /media/other
[prompt]ln -s /mnt/sda/win     /media/windows

Depois disto um ls nos links fará com que as pastas sejam montadas.

A autofs funciona muito bem, mas como disse acima, o ganho não é muito expressivo, além dos inconvenientes possíveis. Após as alterações o tempo de boot caiu para (15,3 ± 0,3)s, algo em torno de meio segundo.

3.10. Baixando a bola do HAL (Hardware Abstraction Layer)

Como o próprio nome diz, o HAL cria uma camada de abstração do hardware, padronizando o acesso aos mais diversos dispositivos, o que deve simplifica em muito a vida dos programadores. Uma pesquisa rápida na rede permite verificar que a atual situação do HAL no Linux não promete uma vida muito longa.

Desde 2010 se ouve rumores sobre a remoção do HAL, dado a complexidade do seu código monolítico e poucos programadores capacitados em mantê-lo. Muito de suas funcionalidades já estão presentes no kernel e outras muitas foram transferidas para o udev. O processo de exclusão do HAL é muito complexo e embora muito já tenha sido feito, alguma dependência ainda permanece, principalmente em desktops como GNOME, Kde e XFCe. Algumas distribuições que já iniciaram este movimento como o Ubuntu, Fedora e o Debian.

O Slackware foi uma das últimas distribuições a adicionarem o HAL à sua árvore. Atualmente a remoção do HAL do Slackware somente será possível quando projetos de desktop como o KDE, XFCe e mesmo o X.org, conseguirem terminar a remoção de suas dependências com o HAL.

Infelizmente, no momento o HAL não pode ser desabilitado, a menos que não se incomode em fazer praticamente toda as montagens manualmente, além de perder o acesso a alguns dispositivos, como som, wireless, … Neste caso não há muito o que fazer com respeito ao HAL, além de mandá-lo para background. Não dá para dar garantias de que tudo funcionará perfeitamente e por isto fica a expectativa de que o ambiente gráfico como outros aplicativos dependentes do HAL sejam iniciados somente após o término da inicialização do HAL.

Este procedimento foi testado em três notebooks da HP, os quais não apresentaram nenhum problema, perceptível.

Para fazer esta última modificação, edite o /etc/rc.d/rc.M e adicione um & ao final da chamada ao script rc.hald:

#!/bin/sh
#
# rc.M          This file is ex...
...

# Start HAL:
if [ -x /etc/rc.d/rc.hald ]; then
  sh /etc/rc.d/rc.hald start &
fi

...

Se tudo correr bem, o ambiente gráfico deve iniciar sem problemas com todos o seu hardware funcional. Embora o comando time acuse que o rc.hald demorava 2s para executar, o ganho neste ponto foi de apenas 1s, caindo o tempo de boot para (14,3 ± 0,3)s em minha máquina. Isto se deve aos diversos outros processos executando em background neste momento.

3.11. Ajustes finais

Existe ainda algumas ações básicas, como desabilitar serviços/funcionalidades em /etc/rc.d/, que geralmente surtem um bom efeito. Uma boa inspeção em /etc/rc.d/ pode revelar alguns recursos desnecessários que podem ser desabilitados, como eventualmente sshd, httpd, cups, alsa, wireless, mysql, …

Para desabilitar um serviço basta mudar a permissão de execução do script com o comando chmod:

chmod -x /etc/rc.d/rc.alsa

Em minha máquina já havia desabilitado os serviços indesejados, faltando apenas desabilitar o rc.alsa, uma vez que o som já é devidamente configurado pelo HAL. Esta última intervenção resultou em uma redução de 0,8s, deixando o boot da máquina em (13,5 ± 0,1)s.

Outra mudança que ainda pode lhe tirar 1 segundo do tempo de boot é colocar para background diversos comandos e chamadas nos scripts rc.S e rc.M. As linhas abaixo mostram linhas do rc.S que estão sendo executadas em background:

grep '&$' /etc/rc.d/rc.S
  . /etc/rc.d/rc.loop start &
/sbin/swapon -a 2> /dev/null &
  sh /etc/rc.d/rc.fuse start &
    /sbin/hwclock $CLOCK_OPT --utc --hctosys &
    /sbin/hwclock $CLOCK_OPT --localtime --hctosys &
    /sbin/isapnp /etc/isapnp.conf &
  /bin/sh /etc/rc.d/rc.modules.local &
/sbin/swapon -a 2> /dev/null &
  . /etc/rc.d/rc.sysvinit &
  sh /etc/rc.d/rc.serial start &

e a seguir as linhas do rc.M:

# grep '&$' /etc/rc.d/rc.M
/bin/setterm -blank 15 -powersave powerdown -powerdown 60 &
#  . /etc/rc.d/rc.netservices 2>&1 > /var/log/rc.netservices &
  sh /etc/rc.d/rc.autofs start &
  sh /etc/rc.d/rc.hald start &
  . /etc/rc.d/rc.netservices 2>&1 > /var/log/rc.netservices &
  /usr/sbin/crond -l notice &
  . /etc/rc.d/rc.alsa &
  . /etc/rc.d/rc.font &
  . /etc/rc.d/rc.keymap &
  . /etc/rc.d/rc.gpm start &
  . /etc/rc.d/rc.sysvinit &
  . /etc/rc.d/rc.local 2>&1 > /var/log/rc_local.log &

Isto baixou o tempo de inicialização para (12,5 ± 0,1)s.

4. Comentários Finais

Com estas mudanças consegui baixar o tempo de boot de minha máquina de 45s para 12,5s, desde a seleção do sistema no grub até o login em modo texto. No modo gráfico, com login automático na conta de um usuário, o XFCe abriu em 38s enquanto que o KDE em 75s.

A tabela a seguir apresenta um resumo das medições do tempo de boot em função das alterações realizadas neste texto.

[TABLE=41]

Estes valores não podem ser considerados padrões, visto que as máquinas são muito diferentes, assim como os sistemas e serviços utilizados em cada instalação. Se você não tiver nada em seu rc.local, de certo não ajudará muito colocá-lo em background.

Fiz as mesmas alterações num notebook HP dv5-1140br, com um HD de 250GB/5400rpm, com taxa de 50MB/s, na partição root. Nesta máquina apenas o sshd está habilitado. Neste caso o tempo de boot ficou em (15,1 ± 0,3)s.

Existe outras alterações que podem gerar reduções significativas no tempo de boot, principalmente enviando processos para background, um recursos pouco utilizado na inicialização do Slackware. Enviar processos para background geralmente faz com que o sistema utilize melhor os recursos de processamento da CPU, no entanto abusos podem deixar a máquina lenta para responder a novos processos o que eventualmente pode atrapalhar.

Recentemente tive que adquirir outro HD para backup e aproveitei a oportunidade para adquirir o novo HD híbrido da Seagate, Momentus XT 500GB ST95005620AS. Este disco possui 4GB de SSD, que, imagino seja usado com uma espécie de cache para o disco. Neste disco o tempo de boot caiu para (8,1 ± 0,3)s. Neste caso tive de adicionar um “sleep 1” nas primeiras linhas do rc.netservices, para que os dispositivos de rede estivessem prontos para poderem ser adequadamente configurados.

4.1 Preciso do hald?

Atualmente a necessidade do deamon hald está relacionado ao gerenciador de desktop que esteja usando, uma vez que o X.Org baseia puramente no udev. Caso use o KDE 4 não faz muita diferença desabilitar o hald. O XFCE mantêm alguma dependência com o hal na montagem automática dos dispositivos. Como uso o KDE 4, tenho desabilitado o script de inicialização do hald, /etc/rc.d/rc.hald, em minha máquina. Isto deve ter garantido mais alguma fração de segundo, uma vez que o /etc/rc.d/rc.hald está sendo executado em background, no entanto não fiz esta medida.

4.2. Finalizando

Todos os scripts alterados estão em fastboot.tar.xz.

Espero ter acrescido algo significativo a este contexto. Se tiver algo a contribuir não deixe de adicionar seu comentário.

Até…

Este post tem 12 comentários

  1. oda

    bom artigo! assim que arrumar um tempo vou brincar com isso.

  2. Leandro Leal Parente

    Parabéns amigão !!! Esse tutorial ficou muito bom e altamente profissional.

    Segui grande parte das suas dicas, e o meu slack está com o boot de 17 seg, e olha que eu não instalei o grub2, não compilei o kernel, não utilizei o autofs e não estou executando o HAL em segundo plano.

    Obrigado !

  3. Gustavo T. Ludwig

    Amigo, excelente material! Parabéns!
    MInha sugestão é que você atualize esse artigo e o traduza para inglês para publicar na seção de howtos do http://docs.slackware.com/. Se precisar de ajuda na tradução, avisa aí!

  4. hong kong

    What a information of un-ambiguity and preserveness of valuablke know-how regarding unexpected feelings.

  5. edps

    Simplesmente fantástico esse artigo, o qual tomei como referência em meu blog.

    Obrigado por compartilhar seu conhecimento,

    @edps

  6. Thank you for every other informative web site. Where else could I get that kind of information written in such a
    perfect method? I have a venture that I’m simply now running on, and I have
    been at the look out for such info.

  7. Rogerio Carlos

    Bom dia pessoal!
    Parabéns pelo trabalho.
    Com um sistema que dispensa apresentações, mantenho aquela antiga filosofia: Se está funcionando…..
    Tenham todos um ótimo dia.

Deixe um comentário

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.