This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
Cygwin Filesystem Performance degradation 1.7.5 vs 1.7.7, and methods for improving performance
- From: Yoni Londner <yonihola2 at gmail dot com>
- To: cygwin-patches at cygwin dot com
- Date: Mon, 06 Sep 2010 12:52:47 +0300
- Subject: Cygwin Filesystem Performance degradation 1.7.5 vs 1.7.7, and methods for improving performance
Hi,
Abstract: I prepared a patch that improves Cygwin Filesystem performance
by x4 on Cygwin 1.7.5 (1.7.5 vanilla 530ms --> 1.7.5 patched 120ms). I
ported the patch to 1.7.7, did tests, and found out that 1.7.7 had a
very serious 9x (!) performance degradation from 1.7.5 (1.7.5 vanilla
530ms --> 1.7.7 vanilla 3900ms --> 1.7.7 patched 3500ms), which does
makes this patch useless until the performance degradation is fixed.
=======================================================================
My patch:
------------
As a cygwin user, I wanted to make cygwin faster, since Cygwin is my
host for Win32 Windows development platform (make, cvs, grep etc).
I saw that simple file access operations were x10 to x50 times slower
than on Windows.
And x10 to x50 slower than VMWare linux accessing the drive using HostFS
(which allows Linux VM to access the Windows C: drive).
So I did some performace test on Cygwin 1.7.5, and found out the biggest
bottleneck were:
- CreateFile()/CloseHandle() on syscalls that only need file node info
retrival, not file contents retrival (such as stat()). This can be
solved by calling Win32 that do not open the File handle itself, rather
query by name, or opening the directory handle (which is MUCH faster).
- repetitive Win32 Kernel calls on a single syscall (stat() would call
up to 5 CreateFile/CloseHandle pairs plus another additional 5 to 10
Win32 APIs).
on stat() system calls, managed to improve the performance of ls approx.
by 4 times. This can be solved by caching: first time in a syscall the
API is called the result is stored, so the second time the info is
needed, it is re-used.
- ACLs: Windows is not a secure system. And its ACL model is strange to
say the least... Most cygwin users do not use the unix permissions
system on cygwin to achieve security. All they want is that the unix
tools will run on Windows. The ACL calls are over 50% (!) of the time
spent during cygwin filesystem syscalls, including stat. For application
such as chmod/chown/chgrp etc I added automatic enabling of ACLs. For
all other applications: the ACLs can be enabled via envirnoment. This
gives the cygwin end user choice: run everything at x2 the speed with no
ACLs, or slow - but with ACL support.
- stat inode number and inode link count: getting the inode in Windows
requires a File handle or Directory handle (not possible to get inode by
file name). Very few applications actually need a REAL inode number. So
using the 'get file info by name' apis are used (and of course there is
an envirnoment if you really want real inode numbers).
- GetVolumeInfo: The C:\ drive does not tend to be changed every
millisecond! Therefore no reason for every filesystem syscall to call
it. Caching this further increased the performance.
- File security check: GetSecurityInfo() is implemented in Windows in
usermode dll (Advapi32.dll). It calls at the end
NtQuerySecurityObject(). So I implemented a faster version:
zGetSecurityInfo() which does the same... just faster.
- symbolic link files: Opening a file and reading its contents is an
expensive operation. All file cygwin operations must check whether the
file is a symbolic link or not, which is done by opening the file and
reading its contents and checking whether it has the symlink magic at
the beginning of this. Since symbolic link must be at least 8 bytes long
(to include the symlink magic header), and cannot be longer than
MAX_PATH+magic size - there is no reason to read the file contents that
is smaller or bigger than this. Since MOST of the files are outside of
this range, we save a LOT of CreateFile/ReadFile/CloseHanlde calls on
every single file operation!
I did all the above work on cygwin 1.7.5. I did a simple test: 'ls
/bin', where bin holds 3500 files.
Cygwin 1.7.5 vanilla took 530 ms. After all my above improvements, the
patched version did this in 120 ms. Thats more than 4x improvement! I
then checked all other applications (grep, make, rsync, cvs, perl code
etc...): they all had this same 4x improvement!
I think this is a very important patch that should find its way into the
Cygwin source code, since it helps to dramatically reduce the x10-x50
filesystem performance gap between Cygwin and native Win32 code.
And once part of standard cygwin, I have many more ideas how the
filesystem performance can be further improved.
==============================================================================
The checks:
The check is did was 'ls > /dev/null' in /bin directory, which contain
about 3500 files.
I did all that for version 1.7.5.
When i wanted to merge my changes to version 1.7.7 i noticed a major
performance degradation.
with 1.7.5 'ls' in /bin took 530ms (with original version), and with
1.7.7 it took almost 4 seconds!
You can see all the details below.
So, I think someone should have a look, and find out what is causing the
performance degradation.
I also want to merge my patch to cygwin CVS, so everybody can enjoy it
(me, and about 10 more people are using a patched cygwin1.dll for about
4 month without any problems).
/bin$ ls /bin | wc -l
3580
The Win32 comparison (... yes: I know cmd.exe's version of ls collects
less info)
/bin$ time cmd /c 'dir > nul:'
real 0m0.113s
user 0m0.015s
sys 0m0.015s
_Without my patch:_
/bin$ uname -a
CYGWIN_NT-5.1 yoni 1.7.5(0.225/5/3) 2010-04-12 19:07 i686 Cygwin
/bin$ time ls > /dev/null
real *0m0.530s*
user 0m0.140s
sys 0m0.421s
~$ uname -a
CYGWIN_NT-5.1 yoni 1.7.7(0.230/5/3) 2010-08-31 09:58 i686 Cygwin
/bin$ time ls > /dev/null
real *0m3.949s*
user 0m0.171s
sys 0m0.546s
_With my patch:_
$ uname -a
CYGWIN_NT-5.1 yoni 1.7.5(0.228/5/3) 2010-07-18 14:53 i686 Cygwin
~$ cd /bin/
/bin$ time ls > /dev/null
real *0m0.123s*
user 0m0.030s
sys 0m0.124s
/bin$ uname -a
CYGWIN_NT-5.1 yoni 1.7.7(0.230/5/3) 2010-09-01 17:14 i686 Cygwin
/bin$ time ls > /dev/null
real *0m3.575s*
user 0m0.108s
sys 0m0.374s
Best regards,
Yoni.
Attachment:
cygwin_1_7_5.patch
Description: Text document
Attachment:
cygwin_1_7_7.patch
Description: Text document