Подтвердить что ты не робот

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

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

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

Ответ 1

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

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

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

Ответ 2

В моем случае это был контроллер домена 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 значительно снизилось.

Ответ 3

Я знаю, что это старый поток, но после новой установки 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

Ответ 4

Новый ответ для старого потока, относящийся к 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.

Ответ 5

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

Используйте этот script, чтобы проверить, остались ли в старой директории устаревшие файлы.

#!/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

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

В результате, каталог 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 script выводит все исполняемые файлы .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 repo (надеюсь, он будет принят).

Теперь для самого большого времени spender - bash_completion.sh. В основном это script источники /usr/share/bash-completion/bash_completion. Я сделал резервную копию этого файла, а затем отредактировал его. На последней странице есть цикл for, который выводит все файлы в compat dir - /etc/bash_completion.d. Опять же, я добавил TIMEFORMAT и time и увидел, какой из script вызывает медленный запуск. Это был пакет zzz-fzf (fzf). Я исследовал и обнаружил, что подоболочка ($()) выполняется несколько раз в цикле for, переписала эту часть без использования подоболочки, что ускоряет работу script. Я уже отправил свой патч в fzf repo.

Самая большая причина для всех этих замедлений: fork не поддерживается моделью процессов Windows, Cygwin отлично справлялся с ней, но она мучительно медленна по сравнению с реальной UNIX. Подселл или конвейер, который очень мало работает сам, тратит большую часть времени выполнения на fork -ing. Например. сравните время выполнения time echo msg (0.000s на моем Cygwin) vs time echo $(echo msg) (0.042s на моем Cygwin) - день и ночь. Команда echo сама по себе не делает сколько-нибудь заметного времени для выполнения, но создание подоболочки очень дорого. В моей системе Linux эти команды занимают соответственно 0,000 и 0,001. Многие пакеты Cygwin разрабатываются людьми, которые используют Linux или другую UNIX, и могут работать на Cygwin без изменений. Поэтому, естественно, эти разработчики могут свободно использовать подоболочки, конвейеры и другие функции везде, где это удобно, поскольку они не ощущают существенной производительности в своей системе, но на Cygwin эти сценарии оболочки могут работать в десятки и сотни раз медленнее.

Нижняя строка, если оболочка script медленно работает в Cygwin - попытайтесь найти источник вызовов fork и перепишите script, чтобы устранить их как можно больше. Например. cmd="$(printf "$1" "$2")" (использует одну вилку для подоболочки) можно заменить на printf -v cmd "$1" "$2".

Мальчик, он вышел очень долго. Любые люди, которые до сих пор читают здесь, являются настоящими героями. Спасибо:)

Ответ 6

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

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

Ответ 7

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

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

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

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

passwd: файлы db группа: файлы db

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

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

Ответ 8

Это действительно не проблема, потому что 2 секунды времени загрузки процессора 2-го поколения i7 и SSD на самом деле нормальные. Преступником более длительного времени загрузки, чем нативная оболочка linux bash, является /etc/bash_completion, которая входит в состав пакета cygwin. Так что это особая проблема cygwin. Я мог быть совершенно не прав, но из того, что я вижу, каждая программа, установленная через установку, профилируется. Далее обсуждается здесь.

Ответ 9

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

Ответ 10

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

Сценарии завершения могут добавлять более одной спецификации завершения или иметь спецификации завершения для оболочек оболочки, поэтому недостаточно сопоставить имена script с исполняемыми файлами, найденными в $PATH.

Мое решение - удалить все загруженные спецификации завершения, загрузить завершение script и проверить, добавили ли он новые спецификации завершения. В зависимости от этого он инактивируется путем добавления .bak к имени файла script или активируется путем удаления .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