grep: pre-load userdiff drivers when threaded
authorJeff King <peff@peff.net>
Thu, 2 Feb 2012 08:24:28 +0000 (03:24 -0500)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Feb 2012 18:36:08 +0000 (10:36 -0800)
The low-level grep_source code will automatically load the
userdiff driver to see whether a file is binary. However,
when we are threaded, it will load the drivers in a
non-deterministic order, handling each one as its assigned
thread happens to be scheduled.

Meanwhile, the attribute lookup code (which underlies the
userdiff driver lookup) is optimized to handle paths in
sequential order (because they tend to share the same
gitattributes files). Multi-threading the lookups destroys
the locality and makes this optimization less effective.

We can fix this by pre-loading the userdiff driver in the
main thread, before we hand off the file to a worker thread.
My best-of-five for "git grep foo" on the linux-2.6
repository went from:

real 0m0.391s
user 0m1.708s
sys 0m0.584s

to:

real 0m0.360s
user 0m1.576s
sys 0m0.572s

Not a huge speedup, but it's quite easy to do. The only
trick is that we shouldn't perform this optimization if "-a"
was used, in which case we won't bother checking whether
the files are binary at all.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/grep.c
index c9b6a138fe343cad5e85c2b2ae4090d6eb514dff..e741aca18cc1c9c3e5cfef3db996d05956bedc2d 100644 (file)
@@ -85,8 +85,8 @@ static pthread_cond_t cond_result;
 
 static int skip_first_line;
 
-static void add_work(enum grep_source_type type, const char *name,
-                    const void *id)
+static void add_work(struct grep_opt *opt, enum grep_source_type type,
+                    const char *name, const void *id)
 {
        grep_lock();
 
@@ -95,6 +95,8 @@ static void add_work(enum grep_source_type type, const char *name,
        }
 
        grep_source_init(&todo[todo_end].source, type, name, id);
+       if (opt->binary != GREP_BINARY_TEXT)
+               grep_source_load_driver(&todo[todo_end].source);
        todo[todo_end].done = 0;
        strbuf_reset(&todo[todo_end].out);
        todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
@@ -333,7 +335,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               add_work(GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+               add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
                strbuf_release(&pathbuf);
                return 0;
        } else
@@ -362,7 +364,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               add_work(GREP_SOURCE_FILE, buf.buf, filename);
+               add_work(opt, GREP_SOURCE_FILE, buf.buf, filename);
                strbuf_release(&buf);
                return 0;
        } else