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>maint
							parent
							
								
									b8ffedca6f
								
							
						
					
					
						commit
						0579f91dd7
					
				|  | @ -17,7 +17,6 @@ | |||
| #include "grep.h" | ||||
| #include "quote.h" | ||||
| #include "dir.h" | ||||
| #include "thread-utils.h" | ||||
|  | ||||
| static char const * const grep_usage[] = { | ||||
| 	"git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]", | ||||
|  | @ -256,6 +255,7 @@ static void start_threads(struct grep_opt *opt) | |||
|  | ||||
| 	pthread_mutex_init(&grep_mutex, NULL); | ||||
| 	pthread_mutex_init(&read_sha1_mutex, NULL); | ||||
| 	pthread_mutex_init(&grep_attr_mutex, NULL); | ||||
| 	pthread_cond_init(&cond_add, NULL); | ||||
| 	pthread_cond_init(&cond_write, NULL); | ||||
| 	pthread_cond_init(&cond_result, NULL); | ||||
|  | @ -303,6 +303,7 @@ static int wait_all(void) | |||
|  | ||||
| 	pthread_mutex_destroy(&grep_mutex); | ||||
| 	pthread_mutex_destroy(&read_sha1_mutex); | ||||
| 	pthread_mutex_destroy(&grep_attr_mutex); | ||||
| 	pthread_cond_destroy(&cond_add); | ||||
| 	pthread_cond_destroy(&cond_write); | ||||
| 	pthread_cond_destroy(&cond_result); | ||||
|  | @ -1002,17 +1003,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix) | |||
| 		opt.regflags |= REG_ICASE; | ||||
|  | ||||
| #ifndef NO_PTHREADS | ||||
| 	if (online_cpus() == 1 || !grep_threads_ok(&opt)) | ||||
| 	if (online_cpus() == 1) | ||||
| 		use_threads = 0; | ||||
| #else | ||||
| 	use_threads = 0; | ||||
| #endif | ||||
|  | ||||
| 	opt.use_threads = use_threads; | ||||
|  | ||||
| #ifndef NO_PTHREADS | ||||
| 	if (use_threads) { | ||||
| 		if (opt.pre_context || opt.post_context || opt.file_break || | ||||
| 		    opt.funcbody) | ||||
| 			skip_first_line = 1; | ||||
| 		start_threads(&opt); | ||||
| 	} | ||||
| #else | ||||
| 	use_threads = 0; | ||||
| #endif | ||||
|  | ||||
| 	compile_grep_patterns(&opt); | ||||
|  |  | |||
							
								
								
									
										73
									
								
								grep.c
								
								
								
								
							
							
						
						
									
										73
									
								
								grep.c
								
								
								
								
							|  | @ -806,10 +806,46 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, | |||
| 	opt->output(opt, "\n", 1); | ||||
| } | ||||
|  | ||||
| static int match_funcname(struct grep_opt *opt, char *bol, char *eol) | ||||
| #ifndef NO_PTHREADS | ||||
| /* | ||||
|  * This lock protects access to the gitattributes machinery, which is | ||||
|  * not thread-safe. | ||||
|  */ | ||||
| pthread_mutex_t grep_attr_mutex; | ||||
|  | ||||
| static inline void grep_attr_lock(struct grep_opt *opt) | ||||
| { | ||||
| 	if (opt->use_threads) | ||||
| 		pthread_mutex_lock(&grep_attr_mutex); | ||||
| } | ||||
|  | ||||
| static inline void grep_attr_unlock(struct grep_opt *opt) | ||||
| { | ||||
| 	if (opt->use_threads) | ||||
| 		pthread_mutex_unlock(&grep_attr_mutex); | ||||
| } | ||||
| #else | ||||
| #define grep_attr_lock(opt) | ||||
| #define grep_attr_unlock(opt) | ||||
| #endif | ||||
|  | ||||
| static int match_funcname(struct grep_opt *opt, const char *name, char *bol, char *eol) | ||||
| { | ||||
| 	xdemitconf_t *xecfg = opt->priv; | ||||
| 	if (xecfg && xecfg->find_func) { | ||||
| 	if (xecfg && !xecfg->find_func) { | ||||
| 		struct userdiff_driver *drv; | ||||
| 		grep_attr_lock(opt); | ||||
| 		drv = userdiff_find_by_path(name); | ||||
| 		grep_attr_unlock(opt); | ||||
| 		if (drv && drv->funcname.pattern) { | ||||
| 			const struct userdiff_funcname *pe = &drv->funcname; | ||||
| 			xdiff_set_find_func(xecfg, pe->pattern, pe->cflags); | ||||
| 		} else { | ||||
| 			xecfg = opt->priv = NULL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (xecfg) { | ||||
| 		char buf[1]; | ||||
| 		return xecfg->find_func(bol, eol - bol, buf, 1, | ||||
| 					xecfg->find_func_priv) >= 0; | ||||
|  | @ -835,7 +871,7 @@ static void show_funcname_line(struct grep_opt *opt, const char *name, | |||
| 		if (lno <= opt->last_shown) | ||||
| 			break; | ||||
|  | ||||
| 		if (match_funcname(opt, bol, eol)) { | ||||
| 		if (match_funcname(opt, name, bol, eol)) { | ||||
| 			show_line(opt, bol, eol, name, lno, '='); | ||||
| 			break; | ||||
| 		} | ||||
|  | @ -848,7 +884,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, | |||
| 	unsigned cur = lno, from = 1, funcname_lno = 0; | ||||
| 	int funcname_needed = !!opt->funcname; | ||||
|  | ||||
| 	if (opt->funcbody && !match_funcname(opt, bol, end)) | ||||
| 	if (opt->funcbody && !match_funcname(opt, name, bol, end)) | ||||
| 		funcname_needed = 2; | ||||
|  | ||||
| 	if (opt->pre_context < lno) | ||||
|  | @ -864,7 +900,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, | |||
| 		while (bol > buf && bol[-1] != '\n') | ||||
| 			bol--; | ||||
| 		cur--; | ||||
| 		if (funcname_needed && match_funcname(opt, bol, eol)) { | ||||
| 		if (funcname_needed && match_funcname(opt, name, bol, eol)) { | ||||
| 			funcname_lno = cur; | ||||
| 			funcname_needed = 0; | ||||
| 		} | ||||
|  | @ -942,19 +978,6 @@ static int look_ahead(struct grep_opt *opt, | |||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int grep_threads_ok(const struct grep_opt *opt) | ||||
| { | ||||
| 	/* If this condition is true, then we may use the attribute | ||||
| 	 * machinery in grep_buffer_1. The attribute code is not | ||||
| 	 * thread safe, so we disable the use of threads. | ||||
| 	 */ | ||||
| 	if ((opt->funcname || opt->funcbody) | ||||
| 	    && !opt->unmatch_name_only && !opt->status_only && !opt->name_only) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void std_output(struct grep_opt *opt, const void *buf, size_t size) | ||||
| { | ||||
| 	fwrite(buf, size, 1, stdout); | ||||
|  | @ -1008,16 +1031,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, | |||
| 	} | ||||
|  | ||||
| 	memset(&xecfg, 0, sizeof(xecfg)); | ||||
| 	if ((opt->funcname || opt->funcbody) | ||||
| 	    && !opt->unmatch_name_only && !opt->status_only && | ||||
| 	    !opt->name_only && !binary_match_only && !collect_hits) { | ||||
| 		struct userdiff_driver *drv = userdiff_find_by_path(name); | ||||
| 		if (drv && drv->funcname.pattern) { | ||||
| 			const struct userdiff_funcname *pe = &drv->funcname; | ||||
| 			xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); | ||||
| 			opt->priv = &xecfg; | ||||
| 		} | ||||
| 	} | ||||
| 	opt->priv = &xecfg; | ||||
|  | ||||
| 	try_lookahead = should_lookahead(opt); | ||||
|  | ||||
| 	while (left) { | ||||
|  | @ -1093,7 +1108,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, | |||
| 				show_function = 1; | ||||
| 			goto next_line; | ||||
| 		} | ||||
| 		if (show_function && match_funcname(opt, bol, eol)) | ||||
| 		if (show_function && match_funcname(opt, name, bol, eol)) | ||||
| 			show_function = 0; | ||||
| 		if (show_function || | ||||
| 		    (last_hit && lno <= last_hit + opt->post_context)) { | ||||
|  |  | |||
							
								
								
									
										10
									
								
								grep.h
								
								
								
								
							
							
						
						
									
										10
									
								
								grep.h
								
								
								
								
							|  | @ -8,6 +8,7 @@ typedef int pcre; | |||
| typedef int pcre_extra; | ||||
| #endif | ||||
| #include "kwset.h" | ||||
| #include "thread-utils.h" | ||||
|  | ||||
| enum grep_pat_token { | ||||
| 	GREP_PATTERN, | ||||
|  | @ -115,6 +116,7 @@ struct grep_opt { | |||
| 	int show_hunk_mark; | ||||
| 	int file_break; | ||||
| 	int heading; | ||||
| 	int use_threads; | ||||
| 	void *priv; | ||||
|  | ||||
| 	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 | |||
| extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt); | ||||
| extern int grep_threads_ok(const struct grep_opt *opt); | ||||
|  | ||||
| #ifndef NO_PTHREADS | ||||
| /* | ||||
|  * Mutex used around access to the attributes machinery if | ||||
|  * opt->use_threads.  Must be initialized/destroyed by callers! | ||||
|  */ | ||||
| extern pthread_mutex_t grep_attr_mutex; | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Thomas Rast
						Thomas Rast