Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I profile my .zshrc/.zshenv?

Tags:

profiling

zsh

It seems like my shell is taking way too long to start up. Is there any way to profile it so I can figure out what's slowing it down so much?

like image 812
Jason Baker Avatar asked Dec 04 '10 00:12

Jason Baker


People also ask

What is the difference between Zshrc and Zshenv?

zshenv is read before /etc/zprofile and that script will probably overwrite your PATH setting. I wouldn't use it at all. . zshrc runs for all interactive shells so it will run if you even just type zsh on the command line.

What's the difference between Zprofile and Zshrc?

zshrc sets the environment for interactive shells. . zshrc gets loaded after . zprofile . It is a place where you “set and forget” things.

Where is zsh profile stored?

zshrc file will be located in the users home directory, or ~/, and this user . zshrc file is where you'd place customizations to the z shell. If you have not yet manually created a . zshrc file, the file will not exist by default.

How do I access my zsh profile?

The zsh shell provides the . zprofile under the user home directory in order to load profile related configuration. The path is ~/. zprofile and can be used like a bash profile file with zsh commands.


3 Answers

Try adding this at the beginning of the file:

# set the trace prompt to include seconds, nanoseconds, script name and line number
# This is GNU date syntax; by default Macs ship with the BSD date program, which isn't compatible
PS4='+$(date "+%s:%N") %N:%i> '
# save file stderr to file descriptor 3 and redirect stderr (including trace 
# output) to a file with the script's PID as an extension
exec 3>&2 2>/tmp/startlog.$$
# set options to turn on tracing and expansion of commands contained in the prompt
setopt xtrace prompt_subst

and this at the end:

# turn off tracing
unsetopt xtrace
# restore stderr to the value saved in FD 3
exec 2>&3 3>&-

And you should get a detailed log showing the epoch_second.nanosecond time of the execution of each line. Note that GNU date (and OS support) is required to have nanosecond output.

Edit:

added comments

Edit 2:

If you have zsh 4.3.12 or later, you should be able to set PS4 like this instead of using the date command:

zmodload zsh/datetime
setopt promptsubst
PS4='+$EPOCHREALTIME %N:%i> '

which should work on both Linux and OS X to give you nanosecond precision.

like image 196
Dennis Williamson Avatar answered Oct 16 '22 08:10

Dennis Williamson


You can start your timer at the first suspicious point in your ~/.zshrc (or at the beginning):

integer t0=$(date '+%s')  # move this around
... maybe something suspect ...

# End of zshrc
function {
    local -i t1 startup
    t1=$(date '+%s')
    startup=$(( t1 - t0 ))
    [[ $startup -gt 1 ]] && print "Hmm, poor shell startup time: $startup"
}
unset t0

This alerts me if ever I see a too-slow startup, and I leave it in as a permanent wrapper.

For more sophisticated measurements, there is a zsh module called zprof. It's as simple as temporarily wrapping the contents of your ~/.zshrc in a zmodload zsh/zprof and zprof. This will dump some verbose profiling tables that are easy enough to interpret.

More info in zshmodules(1) manpage.

When I find things that are particularly slow (rbenv init, vcs_info check-for-changes, antigen, nvm, zsh-mime-setup, interpreter version checking, etc) I add SLOW comments as reminders, and try to find workarounds. Slow startups can cause a lot grief, so I tend to avoid zsh packages/framewords whose inner workings I don't grok. compinit is the slowest thing I'm willing to live with and is ~half of total startup time.

like image 36
Micah Elliott Avatar answered Oct 16 '22 07:10

Micah Elliott


Zsh has a profiling module. At the beginning of ~/.zshrc or ~/.zshenv add it like:

# Uncomment to use the profiling module
# zmodload zsh/zprof

Uncomment it, start a new interactive shell then run the command zprof. You will get a detailed list of items you can review to better understand where your performance bottlenecks are:

num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1           7.29     7.29   19.60%      7.29     7.29   19.60%  _p9k_init_ssh
 2)    2           6.72     3.36   18.06%      6.63     3.31   17.81%  gitstatus_start_impl
 3)    1           4.00     4.00   10.75%      4.00     4.00   10.75%  _p9k_must_init
 4)    3          19.28     6.43   51.80%      3.82     1.27   10.28%  (anon)
 5)    1           1.63     1.63    4.37%      1.63     1.63    4.37%  _p9k_restore_state_impl
 6)    1          16.92    16.92   45.46%      1.61     1.61    4.32%  _p9k_precmd_impl
 7)    1           7.13     7.13   19.16%      0.87     0.87    2.33%  _p9k_set_prompt
 8)   22           6.26     0.28   16.83%      0.84     0.04    2.27%  _p9k_build_segment
 9)   17           0.82     0.05    2.19%      0.82     0.05    2.19%  _p9k_param
10)    6           2.24     0.37    6.02%      0.74     0.12    1.98%  _p9k_left_prompt_segment
11)    5           0.59     0.12    1.60%      0.59     0.12    1.60%  add-zsh-hook
12)    1           3.05     3.05    8.20%      0.58     0.58    1.56%  prompt_dir

And here's a one-liner from speeding up zsh you'll appreciate if start time feels sporadic:

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

Run that job and you should see output like:

        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys
        0.05 real         0.02 user         0.02 sys

Profit.

like image 1
vhs Avatar answered Oct 16 '22 06:10

vhs