Arch Linux: Un romance de Performance y Rendimiento.

1. Breve introducción

Antes de entrar en detalles, quiero aclarar que esta guía refleja mi experiencia personal optimizando y utilizando Arch Linux durante más de 3 años sin necesidad de formatearlo. Si bien uso Linux desde hace más de 15 años, fue recién hace poco que me obsesioné más con la optimización del sistema.

Aunque siempre se pueden encontrar enfoques más avanzados o diferentes (quizás incluso mejores) en la wiki oficial de Arch o en la comunidad en general, estas configuraciones las trato de mejorar día a día, obteniendo resultados que para mí son bastante satisfactorios.

También tengo que aclarar algo muy importante: tengo una PC Desktop de gama media-alta con un procesador Intel i7, una placa de video NVIDIA RTX 3070 y 32 GB de RAM. A pesar de esto, no me gusta derrochar recursos ni dejar que el sistema consuma más de lo necesario. Por eso, trato de optimizar todo para usar al máximo mi hardware de manera eficiente y sacar el mejor rendimiento sin comprometer la estabilidad.

Aun así, logré mejorar mucho los tiempos de respuesta y optimización general. Estoy seguro de que, si replicás esto en tu entorno, sin dudas que algún beneficio positivo vas a notar (siempre acordarse de hacer backup de todo antes!).


Dotfiles: Uso BSPWM como gestor de ventanas, Polybar para la barra de estado, y un .zshrc bastante customizado con Zinit. Debido a que me dedico al Pentesting / Cyberescurity / CTFs, tengo muchas lineas entre configuraciones, alias y funciones. Luego utilizo distintas tools y scripts para mantener todo el sistema lo mas clean posible.


2. Mantenimiento periodico de un Arch Linux.

Como sabemos Arch sigue el modelo rolling release, lo que significa que constantemente recibe las últimas actualizaciones y mejoras. Esto permite que tengamos un sistema siempre al día pero también implica que necesite de un mantenimiento “sin mucho esfuerzo” pero necesario para evitar problemas y asegurar un buen performance.

Seguir una rutina de mantenimiento del sistema se tiene que volver casi una disciplina.

Mantener siempre el sistema actualizado:

Esto es clave para estar al día con los ultimos updates de software y parches de seguridad. Entre ellos, el Kernel, que es crítico para el buen funcionamiento del sistema.

1
sudo pacman -Syu

Limpieza de paquetes Orphans/Huerfanos

Los paquetes huérfanos son aquellos que quedaron instalados manualmente o sobraron al desinstalar otros paquetes que los necesitaban. Es importante eliminarlos regularmente porque ocupan espacio innecesario y pueden generar conflictos si se vuelven obsoletos. Un alias que suelto utilizar para gestionarlos rápidamente:

1
alias orphans='[[ -n $(pacman -Qdt) ]] && sudo pacman -Rs $(pacman -Qdtq) && yay -Yc || echo "no orphans to remove"'

Gestion de espacio en disco: NCDU

Con ncdu puedo ver rápidamente qué carpetas están ocupando más espacio y decidir qué borrar o mover. Es una tool que empecé a usar hace poco, y me facilito mucho al tener un panorama mas claro de cuanto ocupa cada carpeta, tiene un aspecto simple en la terminal, y podés desplazarte con las flechas del teclado hacia delante o atras.


Gestion y limpieza de la cache de paquetes

También gestiono la caché de paquetes con el siguiente alias. (En mi caso, lo hago de manera más agresiva para liberar todo el espacio, incluyendo los paquetes instalados. No me molesta tener que descargarlos nuevamente si los necesito):

1
yay -Sc && sudo pacman -Scc

Optimizacion de mirrors para instalar paquetes

Si entramos a https://archlinux.org/mirrorlist/, podemos obtener un listado de todos los mirrors o repositorios que tiene arch según su respectiva ubicación. Siempre es mejor setear los mas cercanos posibles por una cuestion de delay y tiempo al momento de descargarlos, aunque a veces comprobé que algunos mas lejos, tenian una mejor respuesta o menor carga que los que limitaban con mi pais.

Se edita el siguiente archivo para poner el listado:

1
sudo nano /etc/pacman.d/mirrorlist

Personalmente, suelo tener no mas de 3 mirrors descomentados (los comentados con # son ignorados por el sistema) a veces menos si la conectividad es muy buena. Esto es porque:

  • Si el mirror principal falla, tu sistema puede usar el siguiente de la lista automáticamente. Esto evita interrupciones al actualizar o instalar paquetes.
  • No todos los mirrors están sincronizados al mismo tiempo. Si uno no tiene los últimos paquetes, el sistema usa otro más actualizado.

No es mi caso, porque suelo utilizar algunos de confianza y conectividad que tienen un uptime muy bueno, pero se puede utilizar la tool reflector como alternativa para hacer un testing de conectividad y ordenarlos por velocidad o tasa de transferencia.

Una vez seteados los nuevos servers en mirrorlist, updateo y sincronizo completamente la base de datos con los nuevo mirrors:

1
sudo pacman -Syyu

-yy: Fuerza a pacman a actualizar la base de datos de los repositorios desde los mirrors configurados en el mirrorlist


Stacer: Es una buena alternativa grafica para optimizar y monitorear el sistema.


Estas son algunas de las cosas que podés hacer con esta herramienta:

  1. Monitorear el rendimiento del sistema: Te muestra en tiempo real qué tan cargados están el CPU, la RAM y el disco. Ideal para identificar si algo está consumiendo más recursos de lo que debería.
  2. Administrar servicios: Podés activar, desactivar o apagar servicios con un par de clics.
  3. Hacer limpieza rápida de archivos basura: Cachés, logs y temporales… todo eso que ocupa espacio sin que te des cuenta lo podés eliminar en segundos.
  4. Controlar aplicaciones de inicio: Te permite elegir qué programas se inician junto con el sistema, para que no arranque más lento de lo que debería.
  5. Ver información del sistema: Consultar datos sobre tu hardware y distribución Linux.

Para ser honesto lo que mas utilizo de esta tool es la función de limpieza (punto 3).
Se puede instalar rapidamente con paru:



3. Optimizando el .zshrc

Utilizo ZSH y el archivo .zshrc es el pilar fundamental de su funcionamiento. En mi caso, está optimizado para ser rápido, funcional y adaptado a mis necesidades, especialmente en tareas de pentesting y scripting diario.

Comentaré algunas mejoras que le hice (hace muy poco), las cuales me dejaron más que satisfecho. Debido a que soy muy detallista y meticuloso, ya tenía una carga de la terminal buena (cuando abrís la terminal, esta siempre carga el .zshrc).
La demora era de milésimas de segundos. Sin embargo, sabía que podía mejorarlo aún más. (aunque hablemos de milesimas!). Optimicé líneas de código, quité alias y funciones inútiles o redundantes, mejoré el performance de la carga de los plugins de ZSH y ordené el PATH, ya que a veces incluía carpetas repetidas.


Midiendo la carga del .zshrc:

Antes de optimizar, es importante medir cuánto tiempo tarda en cargarse. Esto me permitió identificar qué partes del archivo estaban ralentizando el inicio del shell. Con el siguiente comando, ejecutándolo varias veces, se puede sacar un promedio:

1
time zsh -i -c exit

Mi velocidad de carga del .zshrc hasta el momento quedo asi:


  • Un .zshrc con 953 líneas carga en un promedio de 35.7 milisegundos.

Es prácticamente imperceptible para un humano. Como referencia, un tiempo de carga por debajo de 100ms es considerado ‘ideal’. ¿Qué es lo que mejoré entonces? Let’s go.


ZPROF un profiler integrado en ZSH:

Zsh incluye un profiler integrado llamado zprof, que permite analizar en detalle cómo se utiliza el tiempo durante el inicio del shell. Esto es ideal para identificar qué plugins, funciones o configuraciones están afectando el rendimiento.

Para activarlo, simplemente agregá las siguientes líneas en tu archivo ~/.zshrc:

  • Al inicio del .zshrc:
1
zmodload zsh/zprof
  • Al final del .zshrc:
1
zprof

Cuiando inicies una nueva terminal de Zsh, vas a ver un reporte detallado con los tiempos de ejecución, lo que ayudará a entender mejor y tratar de optimizar la configuración:

El análisis muestra que compinit consume 7.07 ms (51.6%) y zinit junto a sus funciones, 5.46 ms (39.86%), siendo los principales responsables del tiempo de carga.


¿Qué es Zinit?

Zinit es básicamente un gestor de plugins para Zsh. En mi caso, lo utilizo para optimizar la carga de los plugins cada vez que abro una nueva terminal.

Lo interesante de Zinit es que permite configurar diferentes modos de carga, como retrasos o ejecución silenciosa, lo que ayuda a mantener el shell rápido sin perder funcionalidad.

La instalacion es rapida y facil:

1
bash -c "$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/zdharma-continuum/zinit/HEAD/scripts/install.sh)"

En mi caso esta asi en el .zshrc casi al principio de todo.:

1
2
3
4
5
6
# Cargar Zinit
source "$HOME/.local/share/zinit/zinit.git/zinit.zsh"
# Autoload de _zinit para compatibilidad con el autocompletado
autoload -Uz _zinit
autoload -Uz compinit
(( ${+_comps} )) && _comps[zinit]=_zinit

Plugins que uso con Zinit:

En mi configuración actual del .zshrc, tengo tres plugins esenciales que considero suficientes para mis tareas:


Plugin Descripción
zsh-autosuggestions Sugiere comandos basados en lo que estás escribiendo, usando el historial. Ideal para no repetir comandos largos.
zsh-syntax-highlighting Resalta la sintaxis de los comandos en tiempo real. Ayuda a evitar errores al detectar comandos mal escritos antes de ejecutarlos.
zsh-sudo-plugin Agrega sudo automáticamente al principio del comando, en mi caso con la tecla ESCAPE.

¿Cómo optimizo los plugins?

Para ganar milisegundos en la carga del .zshrc (nueva terminal) utilizo zinit con opciones como wait y silent.

Esto hace que los plugins no esenciales se carguen con un ligero retraso y que no muestren mensajes innecesarios al iniciar la terminal. De esta manera, consigo que la terminal abra mas rapido y que los plugins que mencione antes estén listos para usarse cuando los necesito.

El resultado es una configuración balanceada: la terminal abre en milisegundos y, aunque tiene funcionalidades adicionales, sigue siendo ágil y veloz (basandonos en los tiempos previamente mostrados de carga).

Esta es la forma en que los tengo configurados en mi .zshrc:

1
2
3
4
5
6
7
8
9
10
# zsh-autosuggestions
zinit light zsh-users/zsh-autosuggestions

# zsh-syntax-highlighting
zinit ice wait"1" silent
zinit light zsh-users/zsh-syntax-highlighting

# zsh-sudo-plugin
zinit ice wait"2" silent
zinit snippet /usr/share/zsh/plugins/zsh-sudo-plugin/sudo.plugin.zsh

Algunos de los modos rapidamente explicados:

Comando Descripción
zinit light Carga un plugin de forma optimizada, sin características adicionales como instalación o chequeos innecesarios. Ideal para plugins ya configurados.
zinit ice wait La opción wait"N" indica que el plugin se cargará después de N segundos desde que la terminal inicia. Distribuye la carga y mejora el inicio.
zinit snippet Permite cargar un script o plugin desde una ruta local o una URL. Con un retraso (wait"N") para funcionalidades no críticas en el arranque.

Compilación del .zshrc: ¿Vale la pena?

Otra de las cosas que hice fue compilar el archivo .zshrc. Para esto utilicé el comando zcompile de Zsh, que convierte el archivo en un formato binario más eficiente, reduciendo los tiempos de procesamiento cada vez que se abre una nueva shell.

Lo implemente en mi config y aunque la mejora en los tiempos de carga resultó mínima (alrededor de 2.5ms en promedio) lo mantuve ya que si en el futuro agrego más plugins o configuraciones, este ajuste ayuda bastante a mantener la carga rápida y estable.

1
2
3
4
# Compilación del .zshrc
if [[ $HOME/.zshrc -nt $HOME/.zshrc.zwc ]]; then
zcompile $HOME/.zshrc
fi

Tambien es posible compilarlo manualmente:

1
zcompile ~/.zshrc

Organizando el PATH de manera eficiente

Esto no impactan mucho en el performance, pero organizar las rutas en variables separadas como en el ejemplo TOOLS_PATH para tools y SYSTEM_PATHS para rutas del sistema es una forma clara y ordenada de mantener el archivo .zshrc, esta fue una costumbre que fui adoptando y así pude evitar con el tiempo duplicados y verificar que solo se añadan directorios existentes al PATH, lo que garantiza un entorno un poco mas eficiente.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Tools Path
TOOLS_PATH=(
"$HOME/tools/bin"
"$HOME/tools/custom-scripts"
"$HOME/tools/analyzers"
"$HOME/tools/helpers"
)

# System or Framework Paths
SYSTEM_PATHS=(
"$HOME/.local/bin"
"$HOME/.pyenv/bin"
"$HOME/.cargo/bin"
"/usr/local/bin"
"/usr/bin"
"/bin"
)

# Agrego todas las rutas verificando que existan
for dir in "${TOOLS_PATH[@]}" "${SYSTEM_PATHS[@]}"; do
[[ -d "$dir" && ":$PATH:" != *":$dir:"* ]] && export PATH="$dir:$PATH"
done

# Limpo variables temporales
unset TOOLS_PATH SYSTEM_PATHS

  • Evita redundancias: Estro verifica si un directorio ya está en el PATH, se reduce el riesgo de duplicados, lo que hace que las búsquedas de binarios sean más rápidas y eficientes.
  • Organizado y legible : Tener las rutas organizadas en variables separadas (como TOOLS_PATH y SYSTEM_PATHS) permite añadir, modificar o eliminar rutas sin desordenar el resto de tu .zshrc.

4. Mi Configuración de picom.conf en un entorno con BSPWM

BSPWM es un gestor de ventanas en mosaico que organiza las ventanas dividiendo el espacio disponible en regiones rectangulares mediante particiones binarias, adaptando automáticamente las ventanas al espacio asignado.

Se controla completamente mediante combinaciones de teclas y scripts personalizados, sin menús ni barras de herramientas, ofreciendo una experiencia mas “minimalista”, ligera y altamente configurable.

Mientras que BSPWM gestiona las ventanas de manera eficiente con el sistema de particiones binarias, PICOM aporta los efectos visuales necesarios, como transparencias, sombras, bordes redondeados, animaciones y mas..

Sin embargo, su configuración por defecto puede incluir opciones que afectan negativamente al rendimiento en muchos setups. A continuación, comparto cómo configuré mi archivo picom.conf y por qué elegí cada ajuste pensando en el performance sobre belleza.


Siempre recorda que esta configuración es a gusto mio, y no necesariamente tiene que ser la mejor para vos, yo priorizo performance antes que mucha belleza o efectos visuales, y tranquilamente podes ir cambiando cada valor en tu caso, pero entre muchos estos son los que identifique en mi configuracion que tenian mayor impacto tanto visual como de rendimiento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# General Settings

shadow = false;
fading = false;
corner-radius = 0;

inactive-opacity = 1.0;
active-opacity = 1.0;
inactive-opacity-override = false;

focus-exclude = [
"class_g = 'Cairo-clock'",
"class_g = 'slop'"
];

backend = "xrender";
xrender-sync-fence = false;
dithered-present = false;
vsync = false;
mark-wmwin-focused = true;
mark-ovredir-focused = true;

detect-rounded-corners = false;
detect-client-opacity = false;
detect-transient = false;
glx-no-stencil = true;
use-damage = true;
log-level = "none";

wintypes:
{
normal = { fade = false; shadow = false; }
tooltip = { fade = false; shadow = false; focus = false; full-shadow = false; }
dock = { shadow = false; clip-shadow-above = false; }
dnd = { shadow = false; }
};

glx-swap-method = -1;
no-fading-destroyed-argb = true;

- Sombras desactivadas

1
shadow = false;

Las sombras pueden ser visualmente atractivas, pero también son una de las principales causas de consumo de recursos. Al desactivarlas, elimino posibles artefactos y reduzco la carga sobre la GPU. En un entorno minimalista, las sombras no son esenciales al menos para mi ;D

- Sin efectos de desvanecimiento

1
fading = false;

Los efectos de desvanecimiento (“fading”) al abrir o cerrar ventanas son innecesarios si priorizas la velocidad y respuesta inmediata. Desactivarlos ayuda a reducir la latencia perceptible.

- Sin Bordes

1
corner-radius = 0;

Esto puede ser a gusto claramente de cada user, algo como 5-8 no deberia consumir mucho, aun asi es increible como impacta en ciertas placas de video. Los bordes redondeados pueden ser agradables a la vista, pero renderizarlos consume recursos adicionales.

- Transparencia en las ventanas

1
2
3
inactive-opacity = 1.0;
active-opacity = 1.0;
inactive-opacity-override = false;

Tener una opacidad fija tanto para ventanas activas como tambien inactivas elimina la necesidad de transiciones visuales, y esto reduce la carga en el compositor.

- Backend: xrender

1
backend = "xrender";

Bueno este es un gran debate que se da seguido en foros y demas hace mucho tiempo. Tratare de resumirlo..

  • OpenGL: Está diseñado para que los gráficos los maneje la GPU, siendo ideal para crear imágenes 3D (maneja profundidad, matrices 4x4, etc.). Pero también sirve para gráficos 2D. Es más flexible y potente.

  • XRender: Es una extensión de X11 enfocada en gráficos 2D (sin profundidad, matrices 3x3). Es más fácil de configurar y útil en sistemas donde OpenGL no funciona bien o los drivers son inestables.

Generalmente, se suele usar OpenGL (glx) como backend y mas en setups modernos, sin embargo hay algunos sistemas, en los que XRender va mejor. En mi caso, antiguamente usaba GLX, a pesar de ser una pc de gama media-alta, siento que XRender satisface con fluidez todo lo que necesito. Sin glitches, ni tearing. Es por eso que lo setie asi.

- Vsync

1
vsync = false;

Desactivar Vsync reduce la latencia al costo de posibles tearing en pantalla. En mi caso, la prioridad es la velocidad y no los efectos visuales..

- Uso eficiente de recursos

1
use-damage = true;

Con esta opción activada, Picom renderiza solo las partes de la pantalla que cambian, reduciendo el uso de CPU y GPU en aplicaciones estáticas o con poca actividad.

- Reglas para tipos de ventana (wintypes)

1
2
3
4
5
6
7
wintypes:
{
normal = { fade = false; shadow = false; }
tooltip = { fade = false; shadow = false; focus = false; full-shadow = false; }
dock = { shadow = false; clip-shadow-above = false; }
dnd = { shadow = false; }
};

Configurar reglas para diferentes tipos de ventanas evita aplicar efectos innecesarios en elementos como tooltips, docks o ventanas de arrastrar y soltar (drag and drop). Esto optimiza el comportamiento general de Picom.

- Otros ajustes para reducir el uso de GPU

1
2
3
glx-no-stencil = true;
glx-swap-method = -1;
no-fading-destroyed-argb = true;
  • glx-no-stencil reduce el uso de stencil buffers, lo que disminuye el impacto en la memoria gráfica.
  • glx-swap-method = -1 optimiza el intercambio de buffers para mejorar la eficiencia.
  • no-fading-destroyed-argb evita renderizados innecesarios al cerrar ventanas.

Update 17-01-2025 - Fix Tearing Nvidia Cards

Luego de continuar este paper y seguir con unas pruebas encontre una forma muy eficas al menos para mi y mi placa de video NVIDIA RTX 3070 para definitivamente eliminar el poco tearing que quedaba y fue la siguiente:

1
2
# Fix NVIDIA Tearing and set Monitor Config
sudo nvidia-settings --assign CurrentMetaMode="DP-2: 1920x1080_240 +0+0 {ForceCompositionPipeline=On, ForceFullCompositionPipeline=On}, DP-0: 1920x1080_120 +1920+0 {ForceCompositionPipeline=On, ForceFullCompositionPipeline=On}"

Esto activa ForceCompositionPipeline en cada monitor. Adaptá el comando según tus necesidades. 🙌

La única aclaración es que estén atentos a los valores que obtienen y como configuran los monitores, pueden obtener los valores correctos desde acá:

1
xrandr -q

Si quieren hacerlo persistente y rapido pueden simplemente crearse una entrada en el archivo .xprofile para que al iniciar sesion se aplique, sino pueden hacerlo en /etc/X11/xorg.conf.d/20-nvidia.conf por ejemplo agregando una seccion Option para el MetaMode


5. Una visión general de mi sistema

En este ultimo apartado quiero mostrar todo lo que compone mi sistema Arch Linux muy por encima:

  • SXHKD: Para gestionar atajos de teclado.

  • Polybar: Barra de estado personalizable, donde incluyo módulos propios, para setear varios targets, vpn, dominios, etc.


  • Rofi: Lanzador de aplicaciones que simplifica la búsqueda y ejecución.


  • Dunst: Notificaciones minimalistas y personalizables.


  • Feh: Gestión de fondos de pantalla.
  • Alacritty: Muchos prefieren Kitty, pero es mi terminal por excelencia :D

Mis modulos de la polybar para CTF / Pentesting:

Voy a poner un ejemplo de un modulo para obtener la ip de la vpn y mostrarla en la polybar, como tambien poder copiarla:

  • Primero, defino una función que verifica si la interfaz tun0 está activa, obtiene la IP y la guarda en un archivo:
1
2
3
4
5
6
7
8
function von(){
if ip link show tun0 &>/dev/null; then
ip -o -4 addr list tun0 | awk '{print $4}' | cut -d/ -f1 > $HOME/.config/bin/vpn
else
echo "\nNo ifaces available\n"
echo "" >$HOME/.config/bin/vpn
fi
}

  • Luego este script lee la dirección IP del archivo creado y genera el formato adecuado para que Polybar lo muestre:
1
2
3
4
5
6
7
8
9
#!/bin/bash
# Lee la dirección IP de la VPN desde el archivo
vpn_add=$(awk '{print $1}' /home/$USER/.config/bin/vpn)

if [ "$vpn_add" ]; then
echo "%{F#4FC3F7}🖥️ ▶ %{F-}%{F#4FC3F7}$vpn_add%{u-}"
else
echo "%{F#00ffff}%{u-}%{F#ffee00}"
fi

  • Finalmente en el archivo de configuración de Polybar, agrego el módulo con el siguiente formato:
1
2
3
4
5
6
[module/vpn]

type = custom/script
interval = 2
exec = ~/.config/bin/vpn.sh
click-left = ~/.config/bin/copyVPN.sh

Tambien le doy la funcionalidad de copiar al clipboard con click izquierdo del mouse y es por eso que creo otro archivo para tenerlo ordenado en la misma carpeta donde esta el vpn.sh. Lo llame copyVPN.sh (cuanta imaginacion!), necesitaran xclip si lo hacen de este modo, sudo pacman -S xclip:

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

# Obtengo la IP del archivo TARGET
ip_address=$(cat /home/$USER/.config/bin/vpn | awk '{print $1}')

# Copio sin dejar salto de linea
echo -n "$ip_address" | xclip -sel clip

# Notifico IP copiada
notify-send "[VPN Copied]" "VPN ➜ $ip_address"

Finalmente cuando inicien la VPN al tipear el comando von en mi terminal:


Del mismo modo pueden crear mas modulos para la polybar como el del dominio, o setear otro target y copiar la ip, etc.

Para finalizar una vez que quieran limpiar la polybar de un modulo como el de obtener la ip, se me ocurrio esto rapidamente, aunque seguro tengan mas soluciones faciles, es funcional:

1
2
3
function voff(){
echo "" > $HOME/.config/bin/vpn
}

Simplemente deja vacio el archivo que recibe la ip por ende no se muestra nada en la polybar. :D

Espero que algo haya sido de utilidad. Dejo unos links relacionados a Arch que seguro les pueden servir tambien:

Gracias.