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>
This commit is contained in:
parent
b8ffedca6f
commit
0579f91dd7
@ -17,7 +17,6 @@
|
|||||||
#include "grep.h"
|
#include "grep.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "thread-utils.h"
|
|
||||||
|
|
||||||
static char const * const grep_usage[] = {
|
static char const * const grep_usage[] = {
|
||||||
"git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
|
"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(&grep_mutex, NULL);
|
||||||
pthread_mutex_init(&read_sha1_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_add, NULL);
|
||||||
pthread_cond_init(&cond_write, NULL);
|
pthread_cond_init(&cond_write, NULL);
|
||||||
pthread_cond_init(&cond_result, NULL);
|
pthread_cond_init(&cond_result, NULL);
|
||||||
@ -303,6 +303,7 @@ static int wait_all(void)
|
|||||||
|
|
||||||
pthread_mutex_destroy(&grep_mutex);
|
pthread_mutex_destroy(&grep_mutex);
|
||||||
pthread_mutex_destroy(&read_sha1_mutex);
|
pthread_mutex_destroy(&read_sha1_mutex);
|
||||||
|
pthread_mutex_destroy(&grep_attr_mutex);
|
||||||
pthread_cond_destroy(&cond_add);
|
pthread_cond_destroy(&cond_add);
|
||||||
pthread_cond_destroy(&cond_write);
|
pthread_cond_destroy(&cond_write);
|
||||||
pthread_cond_destroy(&cond_result);
|
pthread_cond_destroy(&cond_result);
|
||||||
@ -1002,17 +1003,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
|||||||
opt.regflags |= REG_ICASE;
|
opt.regflags |= REG_ICASE;
|
||||||
|
|
||||||
#ifndef NO_PTHREADS
|
#ifndef NO_PTHREADS
|
||||||
if (online_cpus() == 1 || !grep_threads_ok(&opt))
|
if (online_cpus() == 1)
|
||||||
use_threads = 0;
|
use_threads = 0;
|
||||||
|
#else
|
||||||
|
use_threads = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
opt.use_threads = use_threads;
|
||||||
|
|
||||||
|
#ifndef NO_PTHREADS
|
||||||
if (use_threads) {
|
if (use_threads) {
|
||||||
if (opt.pre_context || opt.post_context || opt.file_break ||
|
if (opt.pre_context || opt.post_context || opt.file_break ||
|
||||||
opt.funcbody)
|
opt.funcbody)
|
||||||
skip_first_line = 1;
|
skip_first_line = 1;
|
||||||
start_threads(&opt);
|
start_threads(&opt);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
use_threads = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
compile_grep_patterns(&opt);
|
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);
|
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;
|
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];
|
char buf[1];
|
||||||
return xecfg->find_func(bol, eol - bol, buf, 1,
|
return xecfg->find_func(bol, eol - bol, buf, 1,
|
||||||
xecfg->find_func_priv) >= 0;
|
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)
|
if (lno <= opt->last_shown)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (match_funcname(opt, bol, eol)) {
|
if (match_funcname(opt, name, bol, eol)) {
|
||||||
show_line(opt, bol, eol, name, lno, '=');
|
show_line(opt, bol, eol, name, lno, '=');
|
||||||
break;
|
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;
|
unsigned cur = lno, from = 1, funcname_lno = 0;
|
||||||
int funcname_needed = !!opt->funcname;
|
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;
|
funcname_needed = 2;
|
||||||
|
|
||||||
if (opt->pre_context < lno)
|
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')
|
while (bol > buf && bol[-1] != '\n')
|
||||||
bol--;
|
bol--;
|
||||||
cur--;
|
cur--;
|
||||||
if (funcname_needed && match_funcname(opt, bol, eol)) {
|
if (funcname_needed && match_funcname(opt, name, bol, eol)) {
|
||||||
funcname_lno = cur;
|
funcname_lno = cur;
|
||||||
funcname_needed = 0;
|
funcname_needed = 0;
|
||||||
}
|
}
|
||||||
@ -942,19 +978,6 @@ static int look_ahead(struct grep_opt *opt,
|
|||||||
return 0;
|
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)
|
static void std_output(struct grep_opt *opt, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
fwrite(buf, size, 1, stdout);
|
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));
|
memset(&xecfg, 0, sizeof(xecfg));
|
||||||
if ((opt->funcname || opt->funcbody)
|
opt->priv = &xecfg;
|
||||||
&& !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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try_lookahead = should_lookahead(opt);
|
try_lookahead = should_lookahead(opt);
|
||||||
|
|
||||||
while (left) {
|
while (left) {
|
||||||
@ -1093,7 +1108,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
|
|||||||
show_function = 1;
|
show_function = 1;
|
||||||
goto next_line;
|
goto next_line;
|
||||||
}
|
}
|
||||||
if (show_function && match_funcname(opt, bol, eol))
|
if (show_function && match_funcname(opt, name, bol, eol))
|
||||||
show_function = 0;
|
show_function = 0;
|
||||||
if (show_function ||
|
if (show_function ||
|
||||||
(last_hit && lno <= last_hit + opt->post_context)) {
|
(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;
|
typedef int pcre_extra;
|
||||||
#endif
|
#endif
|
||||||
#include "kwset.h"
|
#include "kwset.h"
|
||||||
|
#include "thread-utils.h"
|
||||||
|
|
||||||
enum grep_pat_token {
|
enum grep_pat_token {
|
||||||
GREP_PATTERN,
|
GREP_PATTERN,
|
||||||
@ -115,6 +116,7 @@ struct grep_opt {
|
|||||||
int show_hunk_mark;
|
int show_hunk_mark;
|
||||||
int file_break;
|
int file_break;
|
||||||
int heading;
|
int heading;
|
||||||
|
int use_threads;
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
||||||
void (*output)(struct grep_opt *opt, const void *data, size_t size);
|
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 struct grep_opt *grep_opt_dup(const struct grep_opt *opt);
|
||||||
extern int grep_threads_ok(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
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user