From 658dd48c8572d0db49719cbef6605d384621d87c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 9 May 2009 14:57:30 -0700 Subject: [PATCH 1/2] Avoid unnecessary 'lstat()' calls in 'get_stat_data()' When we ask get_stat_data() to get the mode and size of an index entry, we can avoid the lstat() call if we have marked the index entry as being uptodate due to earlier lstat() calls. This avoids a lot of unnecessary lstat() calls in eg 'git checkout', where the last phase shows the differences to the working tree (requiring a diff), but earlier phases have already verified the index. On the kernel repo (with a fast machine and everything cached), this changes timings of a nul 'git checkout' from - Before (best of ten): 0.14user 0.05system 0:00.19elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+13237minor)pagefaults 0swaps - After 0.11user 0.03system 0:00.15elapsed 98%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+13235minor)pagefaults 0swaps so it can obviously be noticeable, although equally obviously it's not a show-stopper on this particular machine. The difference is likely larger on slower machines, or with operating systems that don't do as good a job of name caching. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff-lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff-lib.c b/diff-lib.c index ae96c64ca2..d230efc146 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -222,7 +222,7 @@ static int get_stat_data(struct cache_entry *ce, const unsigned char *sha1 = ce->sha1; unsigned int mode = ce->ce_mode; - if (!cached) { + if (!cached && !ce_uptodate(ce)) { int changed; struct stat st; changed = check_removed(ce, &st); From 53996fe5397ff37c5934bb5e9b23ef5985b3d152 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 9 May 2009 15:11:17 -0700 Subject: [PATCH 2/2] Teach 'git checkout' to preload the index contents This makes git checkout know to use the threaded index preloading if it is enabled in the config file. You need to have [core] preloadindex = true in your config file to see it, and for that feature to make sense your filesystem needs to be able to do concurrent 'lstat()' lookups, but when that is the case (especially NFS over a high-latency network), this can be a noticeable performance win. But with a low-latency network and at least older Linux NFS clients, this will clearly potentially cause a lot of lock contention. It may still speed up the uncached case, but the threading and locking overhead will result in the cached case likely slowing down. That was almost certainly fixed by Linux commit fc0f684c2 ("NFS: Remove BKL from NFS lookup code"), but that one got merged into 2.6.27-rc1, so older kernel versions than 2.6.27 will not scale very well. But regardless, it's the right thing to do. If your filesystem doesn't scale, don't enable index preloading. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-checkout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index b5dd9c07b4..f1342abd02 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -228,7 +228,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 1); - if (read_cache() < 0) + if (read_cache_preload(pathspec) < 0) return error("corrupt index file"); if (source_tree) @@ -373,7 +373,7 @@ static int merge_working_tree(struct checkout_opts *opts, struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); int newfd = hold_locked_index(lock_file, 1); - if (read_cache() < 0) + if (read_cache_preload(NULL) < 0) return error("corrupt index file"); if (opts->force) {