Why Is Cygwin So Slow

Why does Cygwin execute shell commands very slowly?

Finally, I found the source - a service named "QQPCMgr RTP Service" running on my office computer, it's the real time protection service of "QQ PC Manager".

By disabling it, the time of the script in the question falls back to:

real    0m0.943s
user 0m0.105s
sys 0m0.231s

I have told the developers of QQPCMgr about this, hope they will find the reason.

This still much slower than Linux, but gets the same "real time" of other cygwin computers.

Thank you all!

Startup is really slow for all Cygwin applications

Eventually I found what causes this issue, but I'm still not sure why. Cygwin works for other people in same environment very well.

Cause: On the start of every Cygwin application it tries to get credentials as it is described in etc/nsswitch.conf file. For some reason, it takes a lots of time for my account as it contacts with several Active Directory domain controllers via LDAP.

Solution 1: You can save the current user and group in etc/passwd and etc/group files and set Cygwin to check them before Active Directory.

  1. Start mintty.exe and wait till it opens
  2. Run mkpasswd -c and save its output to etc/passwd file (you will have to create it, output should be one line)
  3. Run mkgroup -c and save its output to etc/group file (you will have to create it, output should be one line)
  4. Open etc/nsswitch.conf and write

nsswitch.conf contents:

passwd: files # db
group: files # db

Now your Cygwin should start immediately.

Solution 2: There is special CygServer application, shipped with Cygwin, which can be started as an NT service or as a simple process (just run usr/sbin/cygserver.exe). It caches credentials and propagates them to every next Cygwin process while cygserver is running.

Add it to startup or start it before your Cygwin session and you're good — cygserver startup will take time, but every next Cygwin process will start immediately.

Is it your case? I want to share my investigation steps, so you could check, if your case is same to mine.

  • Install MS Network Monitor as it is able to show traffic from a specific process. Run it as administrator.
  • Create New capture tab and click Start (you don't have to add any filters or anything).
  • Start mintty and you will see its connections in netmon: netmon-screenshot
  • You will see list of mintty connections in the tree view on the left and TCP and LDAP frames on the right after selecting on of those connections.
  • Additionally, you can get name of those remote machines by IP address. Run nbtstat -a 8.8.8.8 in command line (replace 8.8.8.8 by one of IP addresses from netmon).

Going deeper: I'm still playing with etc/nsswitch.conf file to get local credentials or maybe cached ones so it will run faster without cygserver. But no luck yet.

Cygwin commands from CMD are slow; from bash are fast

A section in Cygwin's FAQ addresses slow startup times. Cygwin recently changed to using Active Directory lookups for authentication, rather than using flat files. Changing the defaults in /etc/nsswitch.conf from

passwd:   files db
group: files db

to

passwd:   files
group: files

skips the AD lookup. My Cygwin commands are now speedy again.

Slow load time of bash in cygwin

As you've noted in your answer, the problem is Cygwin's bash-completion package. The quick and easy fix is to disable bash-completion, and the correct way to do that is to run Cygwin's setup.exe (download it again if you need to) and select to uninstall that package.

The longer solution is to work through the files in /etc/bash_completion.d and disable the ones you don't need. On my system, the biggest culprits for slowing down Bash's load time (mailman, shadow, dsniff and e2fsprogs) all did exactly nothing, since the tools they were created to complete weren't installed.

If you rename a file in /etc/bash_completion.d to have a .bak extension, it'll stop that script being loaded. Having disabled all but a select 37 scripts on one of my systems in that manner, I've cut the average time for bash_completion to load by 95% (6.5 seconds to 0.3 seconds).

How to speed up Cygwin?

The problem you're running into is not some arbitrary limit in Cygwin that you can make go away with a settings change. It's an inherent aspect of the way Cygwin has to work to get the POSIX semantics programs built under it expect.

The POSIX fork() system call has no native equivalent on Windows, so Cygwin is forced to emulate it in a very inefficient way. Shell scripts cause a call to fork() every time they execute an external process, which happens quite a lot since the shell script languages are so impoverished relative to what we'd normally call a programming language. External programs are how shell scripts get anything of consequence done.

There are other inefficiencies in Cygwin, though if you profiled it, you'd probably find that that's the number one speed hit. In most places, the Cygwin layer between a program built using it and the underlying OS is pretty thin. The developers of Cygwin take a lot of pains to keep the layer as thin as possible while still providing correct POSIX semantics. The current uncommon thickness in the fork() call emulation is unavoidable short of Microsoft adding a native fork() type facility to their OS. Their incentives to do that aren't very good.

The solutions posted above as comments aren't bad.

Another possibility is to go through the drush script and see if there are calls to external programs you can replace with shell intrinsics or more efficient constructs. I wouldn't expect a huge speed improvement by doing that, but it has the nice property that you'll speed things up on the Linux side as well. (fork() is efficient on Linux, but starting external programs is still a big speed hit that you may not have to pay as often as you currently do.) For instance:

numlines=`grep somepattern $somefile | wc -l`
if [ $numlines -gt 0 ] ; then ...

would run faster as:

if grep -q somepattern $somefile ; then ...

The first version is arguably clearer, but it requires at least three external program invocations, and with primitive shells, four. (Do you see all of them?) The replacement requires only one external program invocation.



Related Topics



Leave a reply



Submit