Speeding up Mercurial on NFS
Martin Geisler
mg at lazybytes.net
Tue Dec 7 09:34:26 CST 2010
Matt Mackall <mpm at selenic.com> writes:
> On Mon, 2010-12-06 at 08:23 -0800, mg at lazybytes.net wrote:
>
>> Two years ago, someone asked if Git could be made to run faster over
>> NFS. The result was a patch that made Git use threads to preload data
>> in parallel. This gave a 5 time speedup:
>>
>> http://kerneltrap.org/mailarchive/git/2008/11/14/4089834/thread
>>
>> I have tried to replicate these results with some simple test
>> programs:
>>
>> http://bitbucket.org/mg/parallelwalk
>>
>> The 'walker' program is a single-threaded C-based program that will
>> walk a directory tree as fast as possible, 'pywalker' is a
>> Python-based version of it, but with support for multiple threads.
>
> Hmm, to the extent that pywalker spends its time waiting in syscalls,
> it might avoid the GIL.
Yes, that's the idea: each thread releases the GIL (I checked the Python
source) when it does os.lstat and lets another thread run Python byte
code until that thread hits os.lstat.
>> The results of these tests:
>>
>> processes threads
>> 1: 24 sec 24 sec
>> 2: 24 sec 19 sec
>> 4: 26 sec 20 sec
>> 6: 24 sec 19 sec
>> 8: 23 sec 19 sec
>
> What do your C results look like?
I only have a single threaded C program, and it was about 30% faster
than the Python program, if I recall correctly. I can test on the office
machine tomorrow.
>> This is on a NFS setup where I export a directory and mount it back
>> on localhost. I add an artificial network delay of 0.2 ms (0.1 ms in
>> each direction) with
>>
>> % sudo tc qdisc change dev lo root netem delay 0.1ms
>>
>> and I empty the disk cache before each run:
>>
>> % sync; sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
>
> Is this the cache on the client or server?
Sort of both -- I'm using the same machine as client and server with the
NFS export mounted back on localhost.
>> While investigating this, I discovered that the NFS protocol has two
>> commands for listing filenames in a directory: READDIR and
>> READDIRPLUS. The latter will also return stat information for each
>> file found -- this saves a lot of round-trips. Unfortunately, I saw
>> the kernel use READDIRPLUS only once in a while -- this is a shame
>> since the speed advantage of READDIRPLUS is huge. Does anybody know
>> if it is possible for a user-space program like Mercurial to
>> influence how the kernel chooses each operation?
>
> A good question. You should try tracing ls(1) or find(1) and see if
> it's doing the right thing for starters. If not, you're probably
> screwed.
Yeah, I think I'm screwed... I see no clear pattern as to when the
kernel issues a READDIR call and when it uses READDIRPLUS. I tried
reading the code in fs/nfs/ in the Linux kernel, and in inode.c I found
a constant that limits READDIRPLUS:
/* Don't use READDIRPLUS on directories that we believe are too large */
#define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
Apart from that, I got the impression that READDIRPLUS is used as much
as possible. But when I run ls(1) or find(1) repeatedly, it is only used
sometimes.
My guess is that READDIRPLUS is used when opendir() is called. However,
directories are cached with a timeout of 30 seconds by default and files
are only cached for 3 seconds by default -- so on the second run, stat
information for the directories may well be cached whereas the file stat
info has expired => a GETATTR call per file instead of a few READDIRPLUS
calls.
--
Martin Geisler
Mercurial links: http://mercurial.ch/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20101207/05863c54/attachment.pgp>
More information about the Mercurial-devel
mailing list