Медленное время загрузки bash в cygwin
На данный момент загрузка занимает около 2 секунд. Я побежал с -x
флаг, и я вижу вывод, и кажется, что PATH загружается много раз в Cygwin. Самое смешное, что я использую тот же файл в среде Linux, но он работает нормально, без проблем с перезагрузкой. Может ли следующее вызвать проблему?
if [ `uname -o` = "Cygwin" ]; then
....
fi
10 ответов
Как вы отметили в своем ответе, проблема заключается в пакете завершения bash Cygwin. Быстрое и простое решение состоит в том, чтобы отключить завершение bash, и правильный способ сделать это - запустить setup.exe Cygwin ( загрузите его снова, если вам нужно) и выбрать, чтобы удалить этот пакет.
Более длительное решение - работать с файлами в /etc/bash_completion.d
и отключите те, которые вам не нужны. В моей системе основные виновники замедления времени загрузки Bash (mailman, shadow, dsniff и e2fsprogs) ничего не сделали, поскольку инструменты, которые они создавали для завершения, не были установлены.
Если вы переименуете файл в /etc/bash_completion.d
иметь .bak
расширение остановит загрузку этого скрипта. Таким образом отключив все сценарии, кроме выбранных 37, на одной из моих систем, я сократил среднее время загрузки bash_completion на 95% (с 6,5 до 0,3 секунды).
В моем случае это был контроллер домена Windows. Я сделал это, чтобы найти проблему:
Я начал с простого окна cmd.exe
и набрал это:c:\cygwin\bin\strace.exe c:\cygwin\bin\bash
В моем случае я заметил следующую последовательность:
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...
Ключевым моментом было выявление client_request::make_request: cygserver un-available
линия. Вы можете видеть, как после этого cygwin пытается извлечь каждую группу из окон, и время выполнения сводится с ума.
Быстрый Google показал, что cygserver
это: https://cygwin.com/cygwin-ug-net/using-cygserver.html
Cygserver - это программа, которая предназначена для работы в качестве фонового сервиса. Он предоставляет приложениям Cygwin сервисы, которые требуют арбитража безопасности или должны сохраняться, пока не запущено ни одно другое приложение cygwin.
Решение было, чтобы запустить cygserver-config
а потом net start cygserver
запустить службу Windows. После этого время запуска Cygwin значительно сократилось.
Все ответы относятся к более старым версиям bash_completion и не имеют отношения к последним bash_completion
,
Современный bash_completion переместил большинство файлов завершения в /usr/share/bash-completion/completions
по умолчанию проверьте путь в вашей системе, запустив
# pkg-config --variable=completionsdir bash-completion
/usr/share/bash-completion/completions
Там много файлов, по одному для каждой команды, но это не проблема, так как они загружаются по требованию при первом использовании завершения для каждой команды. Старый /etc/bash_completion.d
все еще поддерживается для совместимости, и все файлы оттуда загружены, когда bash_completion
начинается.
# pkg-config --variable=compatdir bash-completion
/etc/bash_completion.d
Используйте этот скрипт, чтобы проверить, остались ли старые файлы в старом каталоге.
#!/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
Он печатает список файлов в каталоге dat compat, которые также присутствуют в новом каталоге dir дополнений (по запросу). Если у вас нет особых причин хранить некоторые из них, просмотрите, создайте резервную копию и удалите все эти файлы.
В результате каталог compat должен быть в основном пустым.
Теперь для самой интересной части - проверка, почему bash
запуск идет медленно. Если вы просто бежите bash
, он запустит интерактивную оболочку без входа в систему - на исходнике Cygwin /etc/bash.bashrc
а потом ~/.bashrc
, Скорее всего, это не включает завершение bash, если вы не получили его из одного из файлов rc. Если вы бежите bash -l
(bash --login
), Начните Cygwin Terminal
(зависит от вашего cygwin.bat
), или войдите через SSH, он запустит логин, интерактивную оболочку - которая будет источником /etc/profile
, ~/.bash_profile
и вышеупомянутые файлы rc. /etc/profile
сам скрипт содержит все исполняемые файлы .sh
файлы в /etc/profile.d
,
Вы можете проверить, сколько времени занимает каждый файл к источнику. Найти этот код в /etc/profile
:
for file in /etc/profile.d/*.$1; do
[ -e "${file}" ] && . "${file}"
done
Сделайте резервную копию, затем замените это следующим:
for file in /etc/profile.d/*.$1; do
TIMEFORMAT="%3lR ${file}"
[ -e "${file}" ] && time . "${file}"
done
Начните bash
и вы увидите, сколько времени занял каждый файл. Исследуйте файлы, которые занимают много времени. В моем случае это было bash_completion.sh
а также fzf.sh
(fzf - нечеткий искатель, действительно хорошее дополнение к bash_completion). Теперь выбор состоит в том, чтобы отключить это или исследовать далее. Так как я хотел продолжать использовать fzf
я исследовал ярлыки в bash, нашел источник замедления, оптимизировал его и отправил свой патч в репозиторий fzf (надеюсь, он будет принят).
Теперь самый большой спонсор времени - bash_completion.sh
, В основном, что источники сценария /usr/share/bash-completion/bash_completion
, Я сделал резервную копию этого файла, а затем отредактировал его. На последней странице есть for
цикл, который получает все файлы в compat
дир - /etc/bash_completion.d
, Я снова добавил TIMEFORMAT
а также time
и увидел, какой скрипт вызывал медленный запуск. это было zzz-fzf
(fzf
пакет). Я исследовал и нашел подоболочку ($()
выполняется несколько раз в for
цикл, переписал эту часть без использования подоболочки, заставляя скрипт работать быстро. Я уже отправил свой патч в репозиторий fzf.
Главная причина всех этих замедлений: fork
не поддерживается моделью процессов Windows, Cygwin отлично поработал, эмулируя ее, но он мучительно медленный по сравнению с реальной UNIX. Подоболочка или конвейер, который выполняет очень мало работы, тратит большую часть своего времени на выполнение fork
-ную. Например, сравните время выполнения time echo msg
(0,000s на моем Cygwin) против time echo $(echo msg)
(0,042 с на моем Cygwin) - днем и ночью. echo
Сама команда не занимает заметного времени для выполнения, но создание подоболочки очень дорого. В моей системе Linux эти команды занимают 0,000 с и 0,001 с соответственно. Многие пакеты, разработанные Cygwin, разработаны людьми, использующими Linux или другие UNIX, и могут работать на Cygwin без изменений. Естественно, эти разработчики могут свободно использовать подоболочки, конвейеры и другие функции везде, где это удобно, поскольку они не чувствуют существенного снижения производительности в своей системе, но в Cygwin эти сценарии оболочки могут выполняться в десятки и сотни раз медленнее.
Итог, если скрипт оболочки медленно работает в Cygwin - попробуйте найти источник fork
вызывает и переписывает скрипт, чтобы максимально их устранить. Например cmd="$(printf "$1" "$2")"
(использует одну вилку для подоболочки) можно заменить на printf -v cmd "$1" "$2"
,
Мальчик, это вышло очень долго. Любые люди, все еще читающие здесь, - настоящие герои. Спасибо:)
Я знаю, что это старая ветка, но после новой установки Cygwin на этой неделе у меня все еще есть эта проблема.
Вместо того, чтобы вручную выбирать все файлы bash_completion, я использовал эту строку для реализации подхода @ me_and для всего, что не установлено на моей машине. Это значительно сократило время запуска bash для меня.
В /etc/bash_completion.d
выполните следующее:
for i in $(ls|grep -v /); do type $i >/dev/null 2>&1 || mv $i $i.bak; done
Новый ответ для старой темы, касающейся PATH
оригинального вопроса.
Большинство других ответов касаются запуска bash. Если вы видите медленное время загрузки при запуске bash -i
внутри оболочки они могут применяться.
В моем случае, bash -i
работал быстро, но каждый раз, когда я открывал новую оболочку (будь то в терминале или в xterm), это занимало очень много времени. Если bash -l
Это занимает много времени, это означает, что это время входа в систему.
Есть некоторые подходы в Cygwin FAQ по адресу https://cygwin.com/faq/faq.html, но они не работают для меня.
Оригинальный постер спросил о PATH
, который он диагностировал с помощью bash -x
, Я тоже обнаружил, что хотя bash -i
был быстрым, bash -xl
был медленным и показал много информации о PATH
,
Там была такая смехотворно длинная винда PATH
что процесс входа в систему продолжал запускать программы и искать весь PATH
для правильной программы.
Мое решение: редактировать Windows PATH
убрать что-нибудь лишнее. Я не уверен, какая часть, которую я удалил, которая сделала трюк, но запуск оболочки входа в систему пошел от 6 секунд до менее чем 1 секунды.
YMMV.
Я нахожусь в корпоративной сети с довольно сложной настройкой, и кажется, что это действительно убивает время запуска Cygwin. Что касается ответа npe, мне также пришлось выполнить некоторые шаги, изложенные здесь: https://cygwin.com/faq/faq.html
Другая причина для клиентской системы AD - медленные ответы DC, обычно наблюдаемые в конфигурациях с удаленным доступом DC. Cygwin DLL запрашивает информацию о каждой группе, в которой вы находитесь, чтобы заполнить локальный кеш при запуске. Вы можете немного ускорить этот процесс, кэшируя свою собственную информацию в локальных файлах. Запустите эти команды в терминале Cygwin с правами записи в / etc:
getent passwd $ (id -u)> / etc / passwd getent group $ (id -G)> / etc / group
Также установите /etc/nsswitch.conf следующим образом:
passwd: файлы базы данных группы: файлы базы данных
Это ограничит необходимость обращения Cygwin к контроллеру домена AD (DC), в то же время позволяя получать дополнительную информацию из DC, например, при перечислении удаленных каталогов.
После этого плюс запуска cygserver время запуска cygwin значительно сократилось.
Мой ответ такой же, как и выше. Но, поскольку я только что присоединился, я не могу комментировать или даже высказывать это! Я надеюсь, что этот пост не будет удален, потому что он дает уверенность любому, кто ищет ответ на ту же проблему.
Решение npee сработало для меня. Есть только одно предупреждение - мне пришлось закрыть все процессы cygwin, прежде чем я смог извлечь из этого максимум пользы. Это включает в себя запуск служб cygwin, таких как sshd, и ssh-agent, который я запускаю из своих сценариев входа. До этого окно для терминала cygwin появлялось мгновенно, но зависало на несколько секунд, прежде чем оно отображало подсказку. И он завис на несколько секунд после закрытия окна. После того, как я убил все процессы и запустил службу cygserver (кстати, я предпочитаю использовать путь Cygwin - "cygrunsrv -S cygserver", чем "net start cygserver"; я не знаю, имеет ли это какое-либо практическое значение), он запускается немедленно. Так что еще раз спасибо npe!
Как уже упоминалось выше, одной из возможных проблем является то, что переменная окружения PATH содержит слишком много пути, Cygwin будет искать их все. Я предпочитаю прямое редактирование /etc/profile, просто перезаписываю переменную PATH на путь, связанный с cygwin, например PATH="/usr/local/bin:/usr/bin"
, Добавьте дополнительный путь, если хотите.
Это действительно не проблема, потому что 2 секунды времени загрузки процессора второго поколения i7 и SSD на самом деле нормальные. Виновник более долгого времени загрузки, чем родная оболочка linux /etc/bash_completion
который входит в состав пакета Cygwin. Так что это проблема Cygwin. Я могу быть совершенно не прав, но, как я вижу, каждая программа, установленная через программу установки, профилируется. Больше обсуждения происходит здесь.
Я написал Bash-функцию с именем 'minimalcompletion' для инактивации ненужных сценариев завершения.
Сценарии завершения могут добавлять более одной спецификации завершения или иметь спецификации завершения для сборок оболочки, поэтому недостаточно сравнивать имена сценариев с исполняемыми файлами, найденными в $PATH.
Мое решение состоит в том, чтобы удалить все загруженные спецификации завершения, загрузить скрипт завершения и проверить, добавил ли он новые спецификации завершения. В зависимости от этого он деактивируется путем добавления.bak к имени файла скрипта или активируется путем удаления.bak. Выполнение этого для всех 182 сценариев в /etc/bash_completion.d приводит к 36 активным и 146 неактивным сценариям завершения, сокращающим время запуска Bash на 50% (но должно быть ясно, что это зависит от установленных пакетов).
Функция также проверяет инактивированные сценарии завершения, чтобы активировать их, когда они необходимы для новых установленных пакетов Cygwin. Все изменения могут быть отменены с помощью аргумента -a, который активирует все сценарии.
# 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"
}
Это пример вывода и результирующие времена:
$ 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