bash debugging cygwin bash-completion

Tiempo de carga lenta de bash en cygwin



debugging bash-completion (10)

Como alguien mencionado anteriormente, un posible problema es que la variable de entorno PATH contiene demasiada ruta, cygwin los buscará a todos. Prefiero editar directamente el / etc / profile, solo sobrescribo la variable PATH a la ruta relacionada con cygwin, por ejemplo, PATH="/usr/local/bin:/usr/bin" . Añade ruta adicional si quieres.

Por el momento bash tarda unos 2 segundos en cargar. He ejecutado bash con el indicador -x y estoy viendo la salida y parece que PATH se está cargando muchas veces en cygwin. Lo gracioso es que uso el mismo archivo en un entorno de Linux, pero funciona bien, sin el problema de recarga. ¿Podría lo siguiente causar el problema?

if [ `uname -o` = "Cygwin" ]; then .... fi


Como ha señalado en su respuesta, el problema es el paquete de finalización de bash de Cygwin. La solución rápida y fácil es deshabilitar la finalización de bash, y la forma correcta de hacerlo es ejecutar el archivo setup.exe de Cygwin ( descárguelo nuevamente si es necesario) y seleccione desinstalar ese paquete.

La solución más larga es trabajar con los archivos en /etc/bash_completion.d y deshabilitar los que no necesita. En mi sistema, los mayores culpables de ralentizar el tiempo de carga de Bash (mailman, shadow, dsniff y e2fsprogs) no hicieron nada, ya que no se instalaron las herramientas para las que fueron creados.

Si cambia el nombre de un archivo en /etc/bash_completion.d para tener una extensión .bak , se detendrá la carga de ese script. Habiendo deshabilitado todos menos uno selecto de 37 scripts en uno de mis sistemas de esa manera, he reducido el tiempo promedio para que bash_completion se cargue en un 95% (6.5 segundos a 0.3 segundos).


En mi caso fue el controlador de dominio de Windows. Hice esto para encontrar el problema:

Comencé con un simple cmd.exe windows y, escribí esto:
c:/cygwin/bin/strace.exe c:/cygwin/bin/bash

En mi caso, noté una secuencia siguiente:

218 12134 [main] bash 11304 transport_layer_pipes::connect: Try to connect to named pipe: //./pipe/cygwin-c5e39b7a9d22bafb-lpc 45 12179 [main] bash 11304 transport_layer_pipes::connect: Error opening the pipe (2) 39 12218 [main] bash 11304 client_request::make_request: cygserver un-available 1404719 1416937 [main] bash 11304 pwdgrp::fetch_account_from_windows: line: <CENSORED_GROUP_ID_#1> 495 1417432 [main] bash 11304 pwdgrp::fetch_account_from_windows: line: <CENSORED_GROUP_ID_#2> 380 1417812 [main] bash 11304 pwdgrp::fetch_account_from_windows: line: <CENSORED_GROUP_ID_#3> etc...

La clave fue identificar la client_request::make_request: cygserver un-available de client_request::make_request: cygserver un-available . Puedes ver cómo, después de eso, cygwin intenta obtener todos los grupos de Windows y los tiempos de ejecución se vuelven locos.

Un Google rápido reveló lo que es un cygserver : https://cygwin.com/cygwin-ug-net/using-cygserver.html

Cygserver es un programa diseñado para ejecutarse como un servicio en segundo plano. Proporciona a las aplicaciones Cygwin servicios que requieren arbitraje de seguridad o que deben persistir mientras no se está ejecutando ninguna otra aplicación cygwin.

La solución era ejecutar cygserver-config y luego net start cygserver para iniciar el servicio de Windows. Los tiempos de inicio de Cygwin cayeron significativamente después de eso.


Escribí una función Bash llamada ''minimizecompletion'' para desactivar scripts de finalización no necesarios.

Los scripts de finalización pueden agregar más de una especificación de finalización o tener especificaciones de finalización para las versiones de shell, por lo que no es suficiente comparar los nombres de los scripts con los archivos ejecutables que se encuentran en $ PATH.

Mi solución es eliminar todas las especificaciones de finalización cargadas, cargar un script de finalización y comprobar si ha agregado nuevas especificaciones de finalización. Dependiendo de esto, se desactiva agregando .bak al nombre del archivo de script o se activa eliminando .bak. Hacer esto para los 182 scripts en /etc/bash_completion.d da como resultado 36 scripts de finalización activos y 146 inactivos, lo que reduce el tiempo de inicio de Bash en un 50% (pero debe estar claro que esto depende de los paquetes instalados).

La función también verifica los scripts de finalización inactivados para que pueda activarlos cuando sean necesarios para los nuevos paquetes de Cygwin instalados. Todos los cambios se pueden deshacer con el argumento -a que activa todos los scripts.

# Enable or disable global completion scripts for speeding up Bash start. # # Script files in directory ''/etc/bash_completion.d'' are inactived # by adding the suffix ''.bak'' to the file name; they are activated by # removing the suffix ''.bak''. After processing all completion scripts # are reloaded by calling ''/etc/bash_completion'' # # usage: [-a] # -a activate all completion scripts # output: statistic about total number of completion scripts, number of # activated, and number of inactivated completion scripts; the # statistic for active and inactive completion scripts can be # wrong when ''mv'' errors occure # return: 0 all scripts are checked and completion loading was # successful; this does not mean that every call of ''mv'' # for adding or removing the suffix was successful # 66 the completion directory or loading script is missing # minimizecompletion() { local arg_activate_all=${1-} local completion_load=/etc/bash_completion local completion_dir=/etc/bash_completion.d ( # Needed for executing completion scripts. # local UNAME=''Cygwin'' local USERLAND=''Cygwin'' shopt -s extglob progcomp have() { unset -v have local PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" type -- "$1" &>/dev/null && have=''yes'' } # Print initial statistic. # printf ''Completion scripts status:/n'' printf '' total: 0/n'' printf '' active: 0/n'' printf '' inactive: 0/n'' printf ''Completion scripts changed:/n'' printf '' activated: 0/n'' printf '' inactivated: 0/n'' # Test the effect of execution for every completion script by # checking the number of completion specifications after execution. # The completion scripts are renamed depending on the result to # activate or inactivate them. # local completions total=0 active=0 inactive=0 activated=0 inactivated=0 while IFS= read -r -d '''' f; do ((++total)) if [[ $arg_activate_all == -a ]]; then [[ $f == *.bak ]] && mv -- "$f" "${f%.bak}" && ((++activated)) ((++active)) else complete -r source -- "$f" completions=$(complete | wc -l) if (( $completions > 0 )); then [[ $f == *.bak ]] && mv -- "$f" "${f%.bak}" && ((++activated)) ((++active)) else [[ $f != *.bak ]] && mv -- "$f" "$f.bak" && ((++inactivated)) ((++inactive)) fi fi # Update statistic. # printf ''/r/e[6A/e[15C%s'' "$total" printf ''/r/e[1B/e[15C%s'' "$active" printf ''/r/e[1B/e[15C%s'' "$inactive" printf ''/r/e[2B/e[15C%s'' "$activated" printf ''/r/e[1B/e[15C%s'' "$inactivated" printf ''/r/e[1B'' done < <(find "$completion_dir" -maxdepth 1 -type f -print0) if [[ $arg_activate_all != -a ]]; then printf ''/nYou can activate all scripts with %s./n'' "''$FUNCNAME -a''" fi if ! [[ -f $completion_load && -r $completion_load ]]; then printf ''Cannot reload completions, missing %s./n'' / "''$completion_load''" >&2 return 66 fi ) complete -r source -- "$completion_load" }

Este es un ejemplo de salida y los tiempos resultantes:

$ minimizecompletion -a Completion scripts status: total: 182 active: 182 inactive: 0 Completion scripts changed: activated: 146 inactivated: 0 $ time bash -lic exit logout real 0m0.798s user 0m0.263s sys 0m0.341s $ time minimizecompletion Completion scripts status: total: 182 active: 36 inactive: 146 Completion scripts changed: activated: 0 inactivated: 146 You can activate all scripts with ''minimizecompletion -a''. real 0m17.101s user 0m1.841s sys 0m6.260s $ time bash -lic exit logout real 0m0.422s user 0m0.092s sys 0m0.154s


Esto realmente no es un problema, porque 2 segundos de tiempo de carga en el procesador i7 de segunda generación y SSD es realmente normal. El culpable de un tiempo de carga más largo que el shell bash nativo de Linux es /etc/bash_completion que forma parte del paquete cygwin. Así que este es un problema específico de cygwin. Podría estar completamente equivocado aquí, pero por lo que puedo ver, cada programa instalado instalado a través de la configuración se está perfilando. Más discusión está ocurriendo here .


Estoy en una red corporativa con una configuración bastante complicada, y parece que realmente mata los tiempos de inicio de cygwin. En relación con la respuesta de npe, también tuve que seguir algunos de los pasos descritos aquí: cygwin.com/faq/faq.html#faq.using.startup-slow

Otra causa para el sistema cliente AD es la lentitud de las respuestas de DC, observadas comúnmente en las configuraciones con acceso remoto a DC. La DLL de Cygwin consulta información sobre cada grupo en el que se encuentra para llenar el caché local en el inicio. Puede acelerar un poco este proceso almacenando su propia información en archivos locales. Ejecute estos comandos en un terminal de Cygwin con acceso de escritura a / etc:

getent passwd $ (id -u)> / etc / passwd getent group $ (id -G)> / etc / group

Además, configure /etc/nsswitch.conf de la siguiente manera:

passwd: archivos db grupo: archivos db

Esto limitará la necesidad de que Cygwin se ponga en contacto con el controlador de dominio de AD (DC) al tiempo que permite que se recupere información adicional de DC, como cuando se listan directorios remotos.

Después de hacer eso, además de iniciar cygserver, el tiempo de inicio de cygwin se redujo significativamente.


Mi respuesta es la misma que la de npe arriba. Pero, como me acabo de unir, no puedo comentarlo ni siquiera votar. Espero que esta publicación no se elimine porque ofrece tranquilidad a cualquiera que busque una respuesta al mismo problema.

La solución de npe funcionó para mí. Solo hay una advertencia: tuve que cerrar todos los procesos de cygwin antes de sacar lo mejor de él. Eso incluye ejecutar los servicios de cygwin, como sshd, y el agente ssh que comienzo desde mis scripts de inicio de sesión. Antes de eso, la ventana del terminal cygwin aparecería instantáneamente pero se colgaría durante varios segundos antes de que presentara el aviso. Y se colgó durante varios segundos al cerrar la ventana. Después de que eliminé todos los procesos y comencé el servicio cygserver (por cierto, prefiero usar la forma Cygwin - ''cygrunsrv -S cygserver'', en lugar de ''net start cygserver''; no sé si hace alguna diferencia práctica) comienza de inmediato. Así que gracias a npe de nuevo!


Nueva respuesta para un hilo antiguo, relacionado con el PATH de la pregunta original.

La mayoría de las otras respuestas tratan con el inicio de bash. Si ve un tiempo de carga lento cuando ejecuta bash -i dentro del shell, es posible que se apliquen.

En mi caso, bash -i corrió rápido, pero cada vez que abría una nueva shell (ya fuera en una terminal o en xterm), tomaba mucho tiempo. Si bash -l está tardando mucho tiempo, significa que es el tiempo de inicio de sesión.

Hay algunos enfoques en las Preguntas frecuentes de Cygwin en cygwin.com/faq/faq.html#faq.using.startup-slow pero no funcionaron para mí.

El póster original preguntó sobre el PATH , que diagnosticó usando bash -x . También encontré que aunque bash -i era rápido, bash -xl era lento y mostraba mucha información sobre el PATH .

Hubo un camino de Windows tan ridículamente largo que el proceso de inicio de sesión continuó ejecutando programas y buscando el programa correcto en todo el PATH .

Mi solución: Edite el PATH Windows para eliminar cualquier cosa superflua. No estoy seguro de qué pieza eliminé que hizo el truco, pero el inicio de shell de inicio de sesión pasó de 6 segundos a menos de 1 segundo.

YMMV.


Sé que este es un tema antiguo, pero después de una nueva instalación de Cygwin esta semana todavía tengo este problema.

En lugar de seleccionar todos los archivos bash_completion, utilicé esta línea para implementar el enfoque de @ me_and para cualquier cosa que no esté instalada en mi máquina. Esto redujo significativamente el tiempo de inicio de bash para mí.

En /etc/bash_completion.d , ejecute lo siguiente:

for i in $(ls|grep -v /); do type $i >/dev/null 2>&1 || mv $i $i.bak; done


Todas las respuestas se refieren a versiones anteriores de bash_completion, y son irrelevantes para bash_completion reciente.

El bash_completion moderno movió la mayoría de los archivos de finalización a /usr/share/bash-completion/completions de forma predeterminada, verifique la ruta de su sistema ejecutando

# pkg-config --variable=completionsdir bash-completion /usr/share/bash-completion/completions

Hay muchos archivos allí, uno para cada comando, pero eso no es un problema, ya que se cargan a pedido la primera vez que se usa para completar con cada comando. El antiguo /etc/bash_completion.d todavía es compatible con la compatibilidad, y todos los archivos desde allí se cargan cuando se inicia bash_completion .

# pkg-config --variable=compatdir bash-completion /etc/bash_completion.d

Use esta secuencia de comandos para verificar si hay archivos obsoletos en el directorio anterior.

#!/bin/sh COMPLETIONS_DIR="$(pkg-config --variable=completionsdir bash-completion)" COMPAT_DIR="$(pkg-config --variable=compatdir bash-completion)" for file in "${COMPLETIONS_DIR}"/*; do file="${COMPAT_DIR}/${file#${COMPLETIONS_DIR}/}" [ -f "$file" ] && printf ''%s/n'' $file done

Imprime la lista de archivos en el directorio de compatibilidad que también están presentes en el directorio de finalización más reciente (a pedido). A menos que tenga razones específicas para conservar algunos de ellos, revise, haga copias de seguridad y elimine todos esos archivos.

Como resultado, el directorio de compatibilidad debe estar casi vacío.

Ahora, para la parte más interesante: comprobar por qué bash startup es lento. Si acaba de ejecutar bash , se iniciará un shell interactivo sin inicio de sesión, este en la fuente de Cygwin /etc/bash.bashrc y luego ~/.bashrc . Lo más probable es que esto no incluya la finalización de bash, a menos que lo obtenga de uno de los archivos rc. Si ejecuta bash -l ( bash --login ), inicia Cygwin Terminal (depende de su cygwin.bat ), o inicie sesión a través de SSH, iniciará un inicio de sesión, shell interactivo , que será fuente /etc/profile , ~/.bash_profile , y los archivos rc antes mencionados. El script /etc/profile sí mismo /etc/profile.d todos los archivos ejecutables .sh en /etc/profile.d .

Puede verificar cuánto tiempo lleva cada archivo a la fuente. Encuentra este código en /etc/profile :

for file in /etc/profile.d/*.$1; do [ -e "${file}" ] && . "${file}" done

Haz una copia de seguridad, luego reemplázalo con esto:

for file in /etc/profile.d/*.$1; do TIMEFORMAT="%3lR ${file}" [ -e "${file}" ] && time . "${file}" done

Comience bash y verá cuánto tiempo tomó cada archivo. Investigue archivos que tomen una cantidad significativa de tiempo. En mi caso, fue bash_completion.sh y fzf.sh (fzf es un buscador difuso, un complemento muy bueno para bash_completion). Ahora la opción es deshabilitarlo o investigar más. Como quería seguir utilizando los fzf directos de fzf en bash, investigué, encontré el origen de la desaceleración, lo optimicé y envié mi parche al repositorio de fzf (espero que sea aceptado).

Ahora, para el mayor bash_completion.sh tiempo: bash_completion.sh . Básicamente, ese script fuente /usr/share/bash-completion/bash_completion . Hice una copia de seguridad de ese archivo, luego lo edité. En la última página hay for bucle que /etc/bash_completion.d todos los archivos en compat dir - /etc/bash_completion.d . Una vez más, agregué TIMEFORMAT y time , y vi qué script estaba causando el inicio lento. Era zzz-fzf (paquete fzf ). Investigué y encontré una subshell ( $() ) que se ejecutaba varias veces en un bucle for , reescribí esa parte sin usar una subshell, haciendo que el script funcionara rápidamente. Ya envié mi parche al repositorio de fzf.

La razón principal de todas estas ralentizaciones es que: el modelo de proceso de Windows no admite el fork , Cygwin hizo un gran trabajo emulándolo, pero es extremadamente lento en comparación con un UNIX real. Un subshell o un oleoducto que realiza muy poco trabajo por sí solo gasta la mayor parte de su tiempo de ejecución para la fork . Por ejemplo, compare los tiempos de ejecución del time echo msg de time echo msg (0,000s en mi Cygwin) frente al time echo $(echo msg) (0,042 s en mi Cygwin) - día y noche. El comando echo sí mismo no toma un tiempo apreciable para ejecutarse, pero crear una subshell es muy costoso. En mi sistema Linux, estos comandos toman 0.000s y 0.001s respectivamente. Muchos paquetes que tiene Cygwin están desarrollados por personas que usan Linux u otro UNIX, y pueden ejecutarse en Cygwin sin modificar. Así que, naturalmente, estos desarrolladores pueden utilizar subshells, tuberías y otras características siempre que sea conveniente, ya que no sienten ningún impacto significativo en su sistema, pero en Cygwin esos shell scripts pueden ejecutarse decenas y cientos de veces más lento.

En pocas palabras, si un script de shell funciona lentamente en Cygwin, intente localizar el origen de las llamadas de fork y reescriba el script para eliminarlas lo más posible. Por ejemplo, cmd="$(printf "$1" "$2")" (usa una bifurcación para subshell) puede reemplazarse con printf -v cmd "$1" "$2" .

Chico, salió muy largo. Cualquier persona que siga leyendo hasta aquí es un verdadero héroe. Gracias :)