Como reduzir o impacto de alterar o valor da matriz 'fpath' no horário de início do zsh?

1

Estou usando zsh versão 5.1.1 e tmux versão 2.3 e recentemente notei que iniciar um novo shell (por meio de uma nova janela ou painel em tmux ) leva mais tempo do que antes.

É o suficiente para eu digitar cerca de 5 caracteres antes que o prompt seja exibido. Eu gostaria de reduzir esse tempo, então eu escrevi uma instrução return em várias posições dentro do meu arquivo zshrc até encontrar a linha que foi responsável pelo aumento do tempo de início. Parece ser:

fpath=(~/.zsh/completion $fpath)

E eu posso reproduzir meu problema com o seguinte zshrc :

fpath=(~/.zsh/completion $fpath)
autoload -Uz compinit
compinit

A primeira linha preenche o caminho ~/.zsh/completion para a matriz fpath . Eu faço isso porque quero gravar os arquivos que contêm o código das minhas funções de conclusão personalizadas dentro desse diretório.

Para ter uma noção de quanto tempo leva para um shell começar, encontrei este comando:

for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done

Começa e sai 10 conchas consecutivamente, cada vez medindo o tempo que demorou. Aqui está o que reporta com o mínimo zshrc :

0.36user 0.04system 0:00.42elapsed 96%CPU (0avgtext+0avgdata 6056maxresident)k
0inputs+160outputs (0major+9087minor)pagefaults 0swaps
0.30user 0.04system 0:00.36elapsed 96%CPU (0avgtext+0avgdata 5900maxresident)k
0inputs+160outputs (0major+8949minor)pagefaults 0swaps
0.30user 0.05system 0:00.37elapsed 96%CPU (0avgtext+0avgdata 6080maxresident)k
0inputs+160outputs (0major+8992minor)pagefaults 0swaps
0.31user 0.04system 0:00.37elapsed 95%CPU (0avgtext+0avgdata 5936maxresident)k
0inputs+160outputs (0major+8956minor)pagefaults 0swaps
0.30user 0.04system 0:00.36elapsed 96%CPU (0avgtext+0avgdata 6052maxresident)k
0inputs+160outputs (0major+9089minor)pagefaults 0swaps
0.32user 0.04system 0:00.38elapsed 96%CPU (0avgtext+0avgdata 5944maxresident)k
0inputs+160outputs (0major+8948minor)pagefaults 0swaps
0.32user 0.04system 0:00.37elapsed 95%CPU (0avgtext+0avgdata 6004maxresident)k
0inputs+160outputs (0major+8991minor)pagefaults 0swaps
0.32user 0.02system 0:00.36elapsed 96%CPU (0avgtext+0avgdata 6056maxresident)k
0inputs+160outputs (0major+9109minor)pagefaults 0swaps
0.30user 0.05system 0:00.36elapsed 96%CPU (0avgtext+0avgdata 6072maxresident)k
0inputs+160outputs (0major+9003minor)pagefaults 0swaps
0.31user 0.04system 0:00.36elapsed 96%CPU (0avgtext+0avgdata 6040maxresident)k
0inputs+160outputs (0major+9055minor)pagefaults 0swaps

Não tenho certeza se leio corretamente, mas parece indicar que, em média, um shell precisa de 0.32 segundo para iniciar.

Veja o que o mesmo comando produz com o mesmo zshrc mínimo após comentar a linha fpath=(...) :

0.08user 0.02system 0:00.10elapsed 97%CPU (0avgtext+0avgdata 5608maxresident)k
0inputs+0outputs (0major+1721minor)pagefaults 0swaps
0.06user 0.00system 0:00.07elapsed 97%CPU (0avgtext+0avgdata 5660maxresident)k
0inputs+0outputs (0major+1723minor)pagefaults 0swaps
0.05user 0.00system 0:00.06elapsed 92%CPU (0avgtext+0avgdata 5680maxresident)k
0inputs+0outputs (0major+1720minor)pagefaults 0swaps
0.05user 0.00system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5724maxresident)k
0inputs+0outputs (0major+1734minor)pagefaults 0swaps
0.04user 0.02system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5748maxresident)k
0inputs+0outputs (0major+1730minor)pagefaults 0swaps
0.05user 0.00system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5692maxresident)k
0inputs+0outputs (0major+1724minor)pagefaults 0swaps
0.04user 0.01system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5636maxresident)k
0inputs+0outputs (0major+1728minor)pagefaults 0swaps
0.04user 0.01system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5628maxresident)k
0inputs+0outputs (0major+1727minor)pagefaults 0swaps
0.04user 0.01system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5684maxresident)k
0inputs+0outputs (0major+1722minor)pagefaults 0swaps
0.05user 0.00system 0:00.06elapsed 95%CPU (0avgtext+0avgdata 5728maxresident)k
0inputs+0outputs (0major+1731minor)pagefaults 0swaps

Agora, em média, parece levar apenas 0.05 segundo.

Por padrão, o valor de FPATH é:

/usr/local/share/zsh/site-functions:/usr/share/zsh/vendor-functions:/usr/share/zsh/vendor-completions:/usr/share/zsh/functions/Calendar:/usr/share/zsh/functions/Chpwd:/usr/share/zsh/functions/Completion:/usr/share/zsh/functions/Completion/AIX:/usr/share/zsh/functions/Completion/BSD:/usr/share/zsh/functions/Completion/Base:/usr/share/zsh/functions/Completion/Cygwin:/usr/share/zsh/functions/Completion/Darwin:/usr/share/zsh/functions/Completion/Debian:/usr/share/zsh/functions/Completion/Linux:/usr/share/zsh/functions/Completion/Mandriva:/usr/share/zsh/functions/Completion/Redhat:/usr/share/zsh/functions/Completion/Solaris:/usr/share/zsh/functions/Completion/Unix:/usr/share/zsh/functions/Completion/X:/usr/share/zsh/functions/Completion/Zsh:/usr/share/zsh/functions/Completion/openSUSE:/usr/share/zsh/functions/Exceptions:/usr/share/zsh/functions/MIME:/usr/share/zsh/functions/Misc:/usr/share/zsh/functions/Newuser:/usr/share/zsh/functions/Prompts:/usr/share/zsh/functions/TCP:/usr/share/zsh/functions/VCS_Info:/usr/share/zsh/functions/VCS_Info/Backends:/usr/share/zsh/functions/Zftp:/usr/share/zsh/functions/Zle

No início da variável, notei o caminho /usr/local/share/zsh/site-functions .
Era um diretório vazio, então o removi e substituí-lo por um link simbólico cujo destino é meu diretório de conclusão:

cd /usr/local/share/zsh; sudo rm site-functions; sudo ln -s ~/.zsh/completion site-functions

Com esse link simbólico, não preciso alterar o valor de fpath . As funções de conclusão ainda funcionam e o tempo de início dos shells foi dividido por 4 , de cerca de 0.32 second para cerca de 0.08 second. A diferença é perceptível para mim. No entanto, não parece certo usar um diretório para todo o sistema.

Existe outra maneira melhor de alcançar o mesmo resultado?

Editar:

Obrigado a @thrig , percebi que meu diretório ~/.zsh/ era, na verdade, um link simbólico para um diretório do Dropbox:

ls -l .zsh
lrwxrwxrwx 1 user user 16 jan. 18 18:54 .zsh -> Dropbox/conf/zsh

Eu fiz isso para ter um backup da minha configuração, e porque eu não sei como usar o git.

Se eu mover as funções de conclusão para um diretório fora do Dropbox, zsh tempo de início será muito menor.

Editar 2:

Eu não entendo, agora parece que zsh começa lentamente novamente, mesmo que eu coloque minhas funções de conclusão fora do diretório do Dropbox.

Caso isso ajude, carreguei em um site semelhante a pastebin a saída do seguinte comando:

strace -e trace=desc -o log -r zsh

De acordo com man strace , a opção -e trace=desc deve rastrear todas as chamadas do sistema relacionadas ao descritor de arquivo. E a opção -r deve imprimir um registro de data e hora relativo na entrada de cada chamada de sistema.

Aqui está um link para o log quando fpath não é alterado .
E aqui está um segundo link para o log quando fpath é alterado .

Não consigo interpretar os arquivos de log, mas há uma grande diferença de tamanho. O primeiro parece incluir apenas 4000 das chamadas do sistema, enquanto o segundo tem cerca de 67000 .

Editar 3:

Eu também gravei a saída do seguinte comando:

PS4='+[%D{%H:%M:%S.%.}]%N:%i> ' zsh -x

… com o utilitário script .

Aqui está um link para o arquivo de log quando fpath não é alterado .
E aqui está um link para o arquivo de log quando fpath é alterado .

Desta vez, o primeiro arquivo de log tem apenas cerca de 600 linhas, enquanto o segundo tem cerca de 100000 linhas.

No arquivo de log em que fpath é alterado, as funções que são chamadas com mais frequência são compdef (em torno de 69000 times), compinit (em torno de 16000 times) e compdump 14000 vezes).

Obrigado por toda a ajuda dada nos comentários.

    
por user547381 08.06.2017 / 20:43

1 resposta

0

Eu pensei que talvez o problema veio da minha versão zsh, então eu purgou o pacote zsh e compilou da fonte:

% sudo aptitude install git-core gcc make autoconf yodl libncursesw5-dev texinfo

% git clone git://zsh.git.sf.net/gitroot/zsh/zsh
% cd zsh
% git checkout zsh-5.3.1

% ./Util/preconfig

% ./configure --build=x86_64-linux-gnu \
--prefix=/usr \
--includedir=/usr/include \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--sysconfdir=/etc \
--localstatedir=/var \
--libdir=/usr/lib/x86_64-linux-gnu \
--libexecdir=/usr/lib/x86_64-linux-gnu \
--bindir=/bin \
LDFLAGS="-Wl,--as-needed -g" \
--enable-maildir-support \
--enable-etcdir=/etc/zsh \
--enable-function-subdirs \
--enable-site-fndir=/usr/local/share/zsh/site-functions \
--enable-fndir=/usr/share/zsh/functions \
--with-tcsetpgrp \
--with-term-lib="ncursesw tinfo" \
--enable-cap \
--enable-pcre \
--enable-readnullcmd=pager \
--enable-custom-patchlevel=Debian \
--enable-additional-fpath=/usr/share/zsh/vendor-functions,/usr/share/zsh/vendor-completions \
--disable-ansi2knr

Encontrei as dependências e as opções de configuração lendo o arquivo INSTALL , bem como a essência encontrada no Google:

https://gist.github.com/nicoulaj/715855

… e observando como o Ubuntu desenvolve os pacotes zsh mais recentes:

https://launchpadlibrarian.net/280509421/buildlog_ubuntu-yakkety-amd64.zsh_5.2-5ubuntu1_BUILDING.txt.gz

Havia algumas opções que foram escritas duas vezes ou não foram reconhecidas pelo zsh, então eu as removi. O valor que o Ubuntu deu para o LDFLAGS não funcionou na minha máquina, então eu copiei o da essência no Github. As opções que mantive são descritas por ./configure --help :

--build=BUILD           configure for building on BUILD [guessed]

--prefix=PREFIX         install architecture-independent files in PREFIX
                        [/usr/local]

--includedir=DIR        C header files [PREFIX/include]

--mandir=DIR            man documentation [DATAROOTDIR/man]

--infodir=DIR           info documentation [DATAROOTDIR/info]

--sysconfdir=DIR        read-only single-machine data [PREFIX/etc]

--localstatedir=DIR     modifiable single-machine data [PREFIX/var]

--libdir=DIR            object code libraries [EPREFIX/lib]

--libexecdir=DIR        program executables [EPREFIX/libexec]

--bindir=DIR            user executables [EPREFIX/bin]

 LDFLAGS                linker flags, e.g. -L<lib dir> if you have libraries in a
                            nonstandard directory <lib dir>

--enable-maildir-support
                        enable maildir support in MAIL and MAILPATH

--enable-etcdir=DIR     the default directory for global zsh scripts

--enable-function-subdirs
                        install functions in subdirectories

--enable-site-fndir=DIR same for site functions (not version specific)

--enable-fndir=DIR      the directory in which to install functions

--with-tcsetpgrp        assumes that tcsetpgrp() exists and works correctly

 --with-term-lib=LIBS   search space-separated LIBS for terminal handling

 --enable-cap           enable the search for POSIX capabilities (may
                        require additional headers to be added by hand)

--enable-pcre           enable the search for the pcre library (may create
                        run-time library dependencies)

--enable-readnullcmd=PAGER
                        pager used when READNULLCMD is not set

--enable-custom-patchlevel
                        set a custom ZSH_PATCHLEVEL value

--enable-additional-fpath=DIR
                        add directories to default function path

--enable-ansi2knr       translate source to K&R C before compiling

A compilação funcionou, mas houve 2 falhas entre os 48 testes realizados pelo comando make check :

% make
% make check
…
**************************************
46 successful test scripts, 2 failures, 0 skipped
**************************************
Makefile:187: recipe for target 'check' failed
make[1]: *** [check] Error 1
make[1]: Leaving directory '/home/user/GitRepos/zsh/Test'
Makefile:263: recipe for target 'check' failed
make: *** [check] Error 2

Eu não consegui me livrar deles.

Por fim, em vez de usar make install para instalar o binário, usei checkinstall para ter um .deb que eu possa remove se eu precisar mudar o shell no futuro (com dpkg -r zsh ):

% sudo checkinstall

Durante a instalação, tive que dar uma breve descrição (usei shell with lots of features ), e mais importante eu tive que dar uma versão. Sem uma versão compatível com a política do Debian, checkinstall não geraria .deb . Eu olhei para a saída de apt-cache policy zsh para verificar qual é o esquema de nomes usado pelo Debian, e escolheu 5.3.1-1ubuntu2 .

% echo /bin/zsh >> /etc/shells
% chsh  →  /bin/zsh

Essas duas linhas foram necessárias para fazer o Ubuntu reconhecer /bin/zsh como um shell de login válido e torná-lo meu shell padrão.

Agora, a versão do shell é 5.3.1 (em vez de 5.1.1 ):

% zsh --version
    zsh 5.3.1 (x86_64-pc-linux-gnu)

E o shell é iniciado rapidamente (em torno de 0.04s ):

% repeat 10 =time zsh -i -c exit

    0.06user 0.03system 0:00.12elapsed 80%CPU (0avgtext+0avgdata 5592maxresident)k
    0inputs+0outputs (0major+5668minor)pagefaults 0swaps
    0.06user 0.01system 0:00.09elapsed 77%CPU (0avgtext+0avgdata 5480maxresident)k
    0inputs+0outputs (0major+5634minor)pagefaults 0swaps
    0.04user 0.01system 0:00.07elapsed 82%CPU (0avgtext+0avgdata 5736maxresident)k
    0inputs+0outputs (0major+5641minor)pagefaults 0swaps
    0.04user 0.01system 0:00.07elapsed 77%CPU (0avgtext+0avgdata 5652maxresident)k
    0inputs+0outputs (0major+5645minor)pagefaults 0swaps
    0.03user 0.03system 0:00.07elapsed 82%CPU (0avgtext+0avgdata 5736maxresident)k
    0inputs+0outputs (0major+5634minor)pagefaults 0swaps
    0.04user 0.01system 0:00.07elapsed 78%CPU (0avgtext+0avgdata 5548maxresident)k
    0inputs+0outputs (0major+5624minor)pagefaults 0swaps
    0.04user 0.02system 0:00.07elapsed 78%CPU (0avgtext+0avgdata 5612maxresident)k
    0inputs+0outputs (0major+5655minor)pagefaults 0swaps
    0.04user 0.01system 0:00.07elapsed 77%CPU (0avgtext+0avgdata 5780maxresident)k
    0inputs+0outputs (0major+5624minor)pagefaults 0swaps
    0.03user 0.02system 0:00.07elapsed 78%CPU (0avgtext+0avgdata 5584maxresident)k
    0inputs+0outputs (0major+5641minor)pagefaults 0swaps
    0.03user 0.02system 0:00.07elapsed 78%CPU (0avgtext+0avgdata 5668maxresident)k

Na primeira vez que compilei, esqueci de mudar para o ramo de lançamento mais recente, então estava em master .
Esta versão de desenvolvimento de zsh teve um tempo de partida ainda pior do que a versão dos repositórios do Ubuntu. Em torno de 0.42s para iniciar um shell. Mas, novamente, somente se eu adicionasse um diretório a fpath em zshrc e criasse um arquivo dentro do último (um simples touch file era suficiente).

Então, pergunto-me se o problema veio das opções de compilação ou da versão de lançamento. Espero que a versão que eu compile permaneça rápida…

Obrigado @ thrigh e @ Stéphane Chazelas por me ajudar nos comentários.

    
por 10.06.2017 / 01:01