grep: enable threading with -p and -W using lazy attribute lookup

Lazily load the userdiff attributes in match_funcname(). Use a separate mutex around this loading to protect the (not thread-safe) attributes machinery. This lets us re-enable threading with -p and -W while reducing the overhead caused by looking up attributes. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Thomas Rast committed Dec 12, 2011 at 22:16 UTC 0579f91dd74a0902e52d1e6e839cc31b99f12cfc
3 files changed +63 -33
builtin/grep.c
+9 -4
@@ -17,7 +17,6 @@
17 #include "grep.h"
18 #include "quote.h"
19 #include "dir.h"
20 -#include "thread-utils.h"
20
21 static char const * const grep_usage[] = {
22 "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
@@ -256,6 +255,7 @@ static void start_threads(struct grep_opt *opt)
255
256 pthread_mutex_init(&grep_mutex, NULL);
257 pthread_mutex_init(&read_sha1_mutex, NULL);
258 + pthread_mutex_init(&grep_attr_mutex, NULL);
259 pthread_cond_init(&cond_add, NULL);
260 pthread_cond_init(&cond_write, NULL);
261 pthread_cond_init(&cond_result, NULL);
@@ -303,6 +303,7 @@ static int wait_all(void)
303
304 pthread_mutex_destroy(&grep_mutex);
305 pthread_mutex_destroy(&read_sha1_mutex);
306 + pthread_mutex_destroy(&grep_attr_mutex);
307 pthread_cond_destroy(&cond_add);
308 pthread_cond_destroy(&cond_write);
309 pthread_cond_destroy(&cond_result);
@@ -1002,17 +1003,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
1003 opt.regflags |= REG_ICASE;
1004
1005 #ifndef NO_PTHREADS
1005 - if (online_cpus() == 1 || !grep_threads_ok(&opt))
1006 + if (online_cpus() == 1)
1007 use_threads = 0;
1008 +#else
1009 + use_threads = 0;
1010 +#endif
1011 +
1012 + opt.use_threads = use_threads;
1013
1014 +#ifndef NO_PTHREADS
1015 if (use_threads) {
1016 if (opt.pre_context || opt.post_context || opt.file_break ||
1017 opt.funcbody)
1018 skip_first_line = 1;
1019 start_threads(&opt);
1020 }
1014 -#else
1015 - use_threads = 0;
1021 #endif
1022
1023 compile_grep_patterns(&opt);
grep.c
+44 -29
@@ -806,10 +806,46 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
806 opt->output(opt, "\n", 1);
807 }
808
809 -static int match_funcname(struct grep_opt *opt, char *bol, char *eol)
809 +#ifndef NO_PTHREADS
810 +/*
811 + * This lock protects access to the gitattributes machinery, which is
812 + * not thread-safe.
813 + */
814 +pthread_mutex_t grep_attr_mutex;
815 +
816 +static inline void grep_attr_lock(struct grep_opt *opt)
817 +{
818 + if (opt->use_threads)
819 + pthread_mutex_lock(&grep_attr_mutex);
820 +}
821 +
822 +static inline void grep_attr_unlock(struct grep_opt *opt)
823 +{
824 + if (opt->use_threads)
825 + pthread_mutex_unlock(&grep_attr_mutex);
826 +}
827 +#else
828 +#define grep_attr_lock(opt)
829 +#define grep_attr_unlock(opt)
830 +#endif
831 +
832 +static int match_funcname(struct grep_opt *opt, const char *name, char *bol, char *eol)
833 {
834 xdemitconf_t *xecfg = opt->priv;
812 - if (xecfg && xecfg->find_func) {
835 + if (xecfg && !xecfg->find_func) {
836 + struct userdiff_driver *drv;
837 + grep_attr_lock(opt);
838 + drv = userdiff_find_by_path(name);
839 + grep_attr_unlock(opt);
840 + if (drv && drv->funcname.pattern) {
841 + const struct userdiff_funcname *pe = &drv->funcname;
842 + xdiff_set_find_func(xecfg, pe->pattern, pe->cflags);
843 + } else {
844 + xecfg = opt->priv = NULL;
845 + }
846 + }
847 +
848 + if (xecfg) {
849 char buf[1];
850 return xecfg->find_func(bol, eol - bol, buf, 1,
851 xecfg->find_func_priv) >= 0;
@@ -835,7 +871,7 @@ static void show_funcname_line(struct grep_opt *opt, const char *name,
871 if (lno <= opt->last_shown)
872 break;
873
838 - if (match_funcname(opt, bol, eol)) {
874 + if (match_funcname(opt, name, bol, eol)) {
875 show_line(opt, bol, eol, name, lno, '=');
876 break;
877 }
@@ -848,7 +884,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
884 unsigned cur = lno, from = 1, funcname_lno = 0;
885 int funcname_needed = !!opt->funcname;
886
851 - if (opt->funcbody && !match_funcname(opt, bol, end))
887 + if (opt->funcbody && !match_funcname(opt, name, bol, end))
888 funcname_needed = 2;
889
890 if (opt->pre_context < lno)
@@ -864,7 +900,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
900 while (bol > buf && bol[-1] != '\n')
901 bol--;
902 cur--;
867 - if (funcname_needed && match_funcname(opt, bol, eol)) {
903 + if (funcname_needed && match_funcname(opt, name, bol, eol)) {
904 funcname_lno = cur;
905 funcname_needed = 0;
906 }
@@ -942,19 +978,6 @@ static int look_ahead(struct grep_opt *opt,
978 return 0;
979 }
980
945 -int grep_threads_ok(const struct grep_opt *opt)
946 -{
947 - /* If this condition is true, then we may use the attribute
948 - * machinery in grep_buffer_1. The attribute code is not
949 - * thread safe, so we disable the use of threads.
950 - */
951 - if ((opt->funcname || opt->funcbody)
952 - && !opt->unmatch_name_only && !opt->status_only && !opt->name_only)
953 - return 0;
954 -
955 - return 1;
956 -}
957 -
981 static void std_output(struct grep_opt *opt, const void *buf, size_t size)
982 {
983 fwrite(buf, size, 1, stdout);
@@ -1008,16 +1031,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
1031 }
1032
1033 memset(&xecfg, 0, sizeof(xecfg));
1011 - if ((opt->funcname || opt->funcbody)
1012 - && !opt->unmatch_name_only && !opt->status_only &&
1013 - !opt->name_only && !binary_match_only && !collect_hits) {
1014 - struct userdiff_driver *drv = userdiff_find_by_path(name);
1015 - if (drv && drv->funcname.pattern) {
1016 - const struct userdiff_funcname *pe = &drv->funcname;
1017 - xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
1018 - opt->priv = &xecfg;
1019 - }
1020 - }
1034 + opt->priv = &xecfg;
1035 +
1036 try_lookahead = should_lookahead(opt);
1037
1038 while (left) {
@@ -1093,7 +1108,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
1108 show_function = 1;
1109 goto next_line;
1110 }
1096 - if (show_function && match_funcname(opt, bol, eol))
1111 + if (show_function && match_funcname(opt, name, bol, eol))
1112 show_function = 0;
1113 if (show_function ||
1114 (last_hit && lno <= last_hit + opt->post_context)) {
grep.h
+10
@@ -8,6 +8,7 @@ typedef int pcre;
8 typedef int pcre_extra;
9 #endif
10 #include "kwset.h"
11 +#include "thread-utils.h"
12
13 enum grep_pat_token {
14 GREP_PATTERN,
@@ -115,6 +116,7 @@ struct grep_opt {
116 int show_hunk_mark;
117 int file_break;
118 int heading;
119 + int use_threads;
120 void *priv;
121
122 void (*output)(struct grep_opt *opt, const void *data, size_t size);
@@ -131,4 +133,12 @@ extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsign
133 extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt);
134 extern int grep_threads_ok(const struct grep_opt *opt);
135
136 +#ifndef NO_PTHREADS
137 +/*
138 + * Mutex used around access to the attributes machinery if
139 + * opt->use_threads. Must be initialized/destroyed by callers!
140 + */
141 +extern pthread_mutex_t grep_attr_mutex;
142 +#endif
143 +
144 #endif