[PATCH 2/2] grep: don't call regexec() for fixed strings
- From
René Scharfe <rene.scharfe@lsrfire.ath.cx>
- Date
- Jan 9, 2009, 23:18 UTC
- Message-ID
- <4967DB4A.2000702@lsrfire.ath.cx>
- In-Reply-To
- <4967D8F8.9070508@lsrfire.ath.cx>
Add the new flag "fixed" to struct grep_pat and set it if the pattern is doesn't contain any regex control characters in addition to if the flag -F/--fixed-strings was specified.
This gives a nice speed up on msysgit, where regexec() seems to be extra slow. Before (best of five runs):
$ time git grep grep v1.6.1 >/dev/null
real 0m0.552s user 0m0.000s sys 0m0.000s
$ time git grep -F grep v1.6.1 >/dev/null
real 0m0.170s user 0m0.000s sys 0m0.015s
With the patch:
$ time git grep grep v1.6.1 >/dev/null
real 0m0.173s user 0m0.000s sys 0m0.000s
The difference is much smaller on Linux, but still measurable.
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> --- grep.c | 29 +++++++++++++++++++++++++---- grep.h | 1 + 2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/grep.c b/grep.c index 394703b..a1092df 100644 --- a/grep.c +++ b/grep.c @@ -28,9 +28,31 @@ void append_grep_pattern(struct grep_opt *opt, const char *pat, p->next = NULL; } +static int isregexspecial(int c) +{ + return isspecial(c) || c == '$' || c == '(' || c == ')' || c == '+' || + c == '.' || c == '^' || c == '{' || c == '|'; +} + +static int is_fixed(const char *s) +{ + while (!isregexspecial(*s)) + s++; + return !*s; +} + static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) { - int err = regcomp(&p->regexp, p->pattern, opt->regflags); + int err; + + if (opt->fixed || is_fixed(p->pattern)) + p->fixed = 1; + if (opt->regflags & REG_ICASE) + p->fixed = 0; + if (p->fixed) + return; + + err = regcomp(&p->regexp, p->pattern, opt->regflags); if (err) { char errbuf[1024]; char where[1024]; @@ -159,8 +181,7 @@ void compile_grep_patterns(struct grep_opt *opt) case GREP_PATTERN: /* atom */ case GREP_PATTERN_HEAD: case GREP_PATTERN_BODY: - if (!opt->fixed) - compile_regexp(p, opt); + compile_regexp(p, opt); break; default: opt->extended = 1; @@ -314,7 +335,7 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol } again: - if (!opt->fixed) { + if (!p->fixed) { regex_t *exp = &p->regexp; hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), pmatch, 0); diff --git a/grep.h b/grep.h index 45a222d..5102ce3 100644 --- a/grep.h +++ b/grep.h @@ -30,6 +30,7 @@ struct grep_pat { const char *pattern; enum grep_header_field field; regex_t regexp; + unsigned fixed:1; }; enum grep_expr_node {
-- 1.6.1