Медленная загрузка bash в cygwin

На данный момент загрузка bash занимает около 2 секунд. Я запустил bash с флагом -x, и я вижу вывод, и кажется, что PATH загружается много раз в cygwin. Самое смешное, что я использую тот же файл в среде Linux, но он работает нормально, без проблем с перезагрузкой. Может ли следующее вызвать проблему?

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

person Forethinker    schedule 20.03.2013    source источник
comment
Кажется, вы задаете здесь две проблемы: есть ли в bash --startuptime и что не так с этим .bashrc. Вам повезет, если вы зададите каждый вопрос отдельно, а для второго вопроса объясните, что конкретно идет не так.   -  person me_and    schedule 21.03.2013
comment
Я не смог найти опцию --startuptime для bash нигде на странице руководства, а также в Интернете. Я думаю, что эти вопросы сочетаются друг с другом, поэтому я задал их вместе.   -  person Forethinker    schedule 23.03.2013
comment
@me_and: я думаю, ты прав. Я должен был отделить их. Соответственно, я изменю свой вопрос.   -  person Forethinker    schedule 24.03.2013
comment
Интересно, может ли время быть медленным? Может так лучше Bash loads slowly in Cygwin? Дело не в вашем английском, а в том, чтобы сделать хороший вопрос еще лучше.   -  person ForceBru    schedule 11.03.2015


Ответы (9)


Как вы отметили в своем ответе, проблема заключается в пакете Cygwin bash-completion. Быстрое и простое решение — отключить завершение bash, и правильный способ сделать это — запустить Cygwin's setup.exe (загрузить его снова, если вам нужно) и выберите удаление этого пакета.

Более длительное решение — просмотреть файлы в /etc/bash_completion.d и отключить те, которые вам не нужны. В моей системе самые большие виновники замедления времени загрузки Bash (mailman, shadow, dsniff и e2fsprogs) абсолютно ничего не делали, поскольку инструменты, для которых они были созданы, не были установлены.

Если вы переименуете файл в /etc/bash_completion.d, чтобы он имел расширение .bak, это остановит загрузку этого скрипта. Отключив таким образом все сценарии, кроме избранных 37, в одной из моих систем, я сократил среднее время загрузки bash_completion на 95% (с 6,5 до 0,3 секунды).

person me_and    schedule 26.03.2013
comment
Между прочим, я сам проводил некоторые исследования по этому вопросу и поделился своими выводами и предложения в списке рассылки Cygwin. - person me_and; 27.03.2013

В моем случае это был контроллер домена Windows. Я сделал это, чтобы найти проблему:

Я начал с простого, 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 значительно сократилось.

person npe    schedule 18.02.2015
comment
Я не видел подобного вывода в своей трассировке стека, и я не запускаю экземпляр cygserver.exe, но спасибо, что поделились этой информацией. Не могли бы вы также поделиться версией cygwin, которую вы используете? - person Forethinker; 18.02.2015
comment
Версия Cygwin: 1.7.34(0.285/5/3) 2015-02-04 12:12 i686 - person npe; 18.02.2015
comment
Это определенно был ответ, который решил мою проблему; Я тоже работал в среде контроллера домена Windows. Спасибо, что разобрались. - person Milos Ivanovic; 21.02.2015
comment
Спасибо за совет strace.exe, который подтвердил, что это была моя проблема. Я видел время запуска более 15 секунд, и исправление сработало отлично. Это началось сразу после обновления моей установки Cygwin сегодня. Почему это не было нужно несколько месяцев назад или когда-либо раньше? - person Kevin Condon; 26.02.2015
comment
@KevinCondon Трудно сказать - они что-то изменили в Cygwin 1.7.34 - см. FAQ: cygwin.com/faq/faq.html#faq.using.startup-slow. Я думаю, что это могло быть причиной для вас, хотя удаление файлов, как было предложено в FAQ, мне совершенно не помогло. И на самом деле я столкнулся с этими серьезными задержками в прошлом году, просто другая корпорация с другим доменом AD, так что это может быть не связано в конце концов. - person npe; 27.02.2015
comment
+1 Это также устранило мои проблемы с производительностью после обновления (у меня не был установлен bash_completion). Спасибо, что показали, как использовать strace, а также как запустить службу. - person EdH; 04.03.2015

Все ответы относятся к более старым версиям 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

Он печатает список файлов в каталоге совместимости, которые также присутствуют в более новом (по запросу) каталоге дополнений. Если у вас нет конкретных причин для сохранения некоторых из них, просмотрите, создайте резервную копию и удалите все эти файлы.

В результате каталог совместимости должен быть в основном пуст.

Теперь самое интересное - проверка почему 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-ing. Например. сравните время выполнения time echo msg (0,000 с на моем 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".

Блин, получилось очень долго. Все, кто дочитал до этого места, — настоящие герои. Спасибо :)

person Gene Pavlovsky    schedule 23.04.2016

Я знаю, что это старая тема, но после новой установки 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
person grocky    schedule 24.10.2014
comment
Это отличный ответ! Для тех, кто думал так же, как и я (что, безусловно, все в этом каталоге анализируется независимо от расширения), при чтении /etc/bash_completion выясняется, что файлы .bak игнорируются вместе с некоторыми другими. Еще одна рекомендация - посмотреть файлы завершения с новым расширением .bak, потому что некоторые из них являются исключениями из вышеперечисленного (например, configure, встроенные модули bash), а некоторые могут быть установлены позже, поэтому стоит помнить, что вы сделали это если вы обнаружите, что завершение bash не работает должным образом при установке gcc! - person fquinner; 25.11.2014

Новый ответ на старую тему, касающуюся PATH исходного вопроса.

Большинство других ответов касаются запуска bash. Если вы наблюдаете медленную загрузку при запуске bash -i в оболочке, это может быть применимо.

В моем случае bash -i работал быстро, но каждый раз, когда я открывал новую оболочку (будь то в терминале или в xterm), это занимало очень много времени. Если bash -l занимает много времени, это означает, что пришло время входа в систему.

Некоторые подходы можно найти в FAQ по Cygwin по адресу https://cygwin.com/faq/faq.html#faq.using.startup-slow, но мне они не подошли.

Оригинальный постер спрашивал о PATH, который он диагностировал с помощью bash -x. Я тоже обнаружил, что хотя bash -i работает быстро, bash -xl работает медленно и показывает много информации о PATH.

Была такая смехотворно длинная Windows PATH, что процесс входа в систему продолжал запускать программы и искать нужную программу по всему PATH.

Мое решение: отредактируйте Windows PATH, чтобы удалить все лишнее. Я не уверен, какую часть я удалил, что помогло, но запуск оболочки входа в систему сократился с 6 секунд до менее 1 секунды.

YMMV.

person MCK    schedule 11.03.2015

Мой ответ такой же, как и у npe выше. Но, поскольку я только что присоединился, я не могу комментировать или даже голосовать за это! Я надеюсь, что этот пост не будет удален, потому что он дает уверенность всем, кто ищет ответ на ту же проблему.

решение npe сработало для меня. Есть только одно предостережение - мне пришлось закрыть все процессы cygwin, прежде чем я извлек из этого максимум пользы. Это включает в себя запуск служб cygwin, таких как sshd, и ssh-agent, который я запускаю из своих сценариев входа. До этого окно терминала cygwin появлялось мгновенно, но зависало на несколько секунд, прежде чем отображалось приглашение. И завис на несколько секунд при закрытии окна. После того, как я убил все процессы и запустил службу cygserver (кстати, я предпочитаю использовать способ Cygwin - «cygrunsrv -S cygserver», чем «net start cygserver»; я не знаю, имеет ли это какое-либо практическое значение), он запускается немедленно. Так что спасибо npe еще раз!

person Nikolay Mihaylov    schedule 20.02.2015

Я нахожусь в корпоративной сети с довольно сложной настройкой, и кажется, что это действительно убивает время запуска cygwin. Что касается ответа npe, мне также пришлось выполнить некоторые шаги, изложенные здесь: https://cygwin.com/faq/faq.html#faq.using.startup-slow

Другой причиной клиентской системы AD являются медленные ответы контроллера домена, обычно наблюдаемые в конфигурациях с удаленным доступом к контроллеру домена. Cygwin DLL запрашивает информацию о каждой группе, в которой вы находитесь, для заполнения локального кэша при запуске. Вы можете немного ускорить этот процесс, кэшируя свою информацию в локальных файлах. Запустите эти команды в терминале Cygwin с правом записи в /etc:

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

Также установите /etc/nsswitch.conf следующим образом:

passwd: files db
group: files db

Это ограничит потребность Cygwin в контакте с контроллером домена AD (DC), но при этом позволит получать дополнительную информацию из DC, например, при перечислении удаленных каталогов.

После этого плюс запуск cygserver мое время запуска cygwin значительно сократилось.

person eresonance    schedule 01.06.2015

Как упоминалось выше, одной из возможных проблем является то, что переменная среды PATH содержит слишком много путей, cygwin будет искать их все. Я предпочитаю прямое редактирование /etc/profile, просто перезаписав переменную PATH на путь, связанный с cygwin, например PATH="/usr/local/bin:/usr/bin". Добавьте дополнительный путь, если хотите.

person Howard Gong    schedule 19.10.2015

Я написал функцию Bash под названием «minimizecompletion» для деактивации ненужных сценариев завершения.

Сценарии завершения могут добавлять более одной спецификации завершения или иметь спецификации завершения для сборок оболочки, поэтому недостаточно сравнивать имена сценариев с исполняемыми файлами, найденными в $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
person Bastian    schedule 22.01.2016