зеркало из https://github.com/microsoft/git.git
grep: add support for the PCRE v1 JIT API
Change the grep PCRE v1 code to use JIT when available. When PCRE
support was initially added in commit 63e7e9d8b6
("git-grep: Learn
PCRE", 2011-05-09) PCRE had no JIT support, it was integrated into
8.20 released on 2011-10-21.
Enabling JIT support usually improves performance by more than
40%. The pattern compilation times are relatively slower, but those
relative numbers are tiny, and are easily made back in all but the
most trivial cases of grep. Detailed benchmarks & overview of
compilation times is at: http://sljit.sourceforge.net/pcre.html
With this change the difference in a t/perf/p7820-grep-engines.sh run
is, with just the /perl/ tests shown:
$ GIT_PERF_REPEAT_COUNT=30 GIT_PERF_LARGE_REPO=~/g/linux GIT_PERF_MAKE_OPTS='-j8 USE_LIBPCRE=YesPlease CC=~/perl5/installed/bin/gcc NO_R_TO_GCC_LINKER=YesPlease CFLAGS=-O3 LIBPCREDIR=/home/avar/g/pcre/inst LDFLAGS=-Wl,-rpath,/home/avar/g/pcre/inst/lib' ./run HEAD~ HEAD p7820-grep-engines.sh
Test HEAD~ HEAD
---------------------------------------------------------------------------------------
7820.3: perl grep 'how.to' 0.35(1.11+0.43) 0.23(0.42+0.46) -34.3%
7820.7: perl grep '^how to' 0.64(2.71+0.36) 0.27(0.66+0.44) -57.8%
7820.11: perl grep '[how] to' 0.63(2.51+0.42) 0.33(0.98+0.39) -47.6%
7820.15: perl grep '(e.t[^ ]*|v.ry) rare' 1.17(5.61+0.35) 0.34(1.08+0.46) -70.9%
7820.19: perl grep 'm(ú|u)lt.b(æ|y)te' 0.43(1.52+0.44) 0.30(0.88+0.42) -30.2%
The conditional support for JIT is implemented as suggested in the
pcrejit(3) man page. E.g. defining PCRE_STUDY_JIT_COMPILE to 0 if it's
not present.
The implementation is relatively verbose because even if
PCRE_CONFIG_JIT is defined only a call to pcre_config() can determine
if the JIT is available, and if so the faster pcre_jit_exec() function
should be called instead of pcre_exec(), and a different (but not
complimentary!) function needs to be called to free pcre1_extra_info.
There's no graceful fallback if pcre_jit_stack_alloc() fails under
PCRE_CONFIG_JIT, instead the program will simply abort. I don't think
this is worth handling gracefully, it'll only fail in cases where
malloc() doesn't work, in which case we're screwed anyway.
That there's no assignment of `p->pcre1_jit_on = 0` when
PCRE_CONFIG_JIT isn't defined isn't a bug. The create_grep_pat()
function allocates the grep_pat allocates it with calloc(), so it's
guaranteed to be 0 when PCRE_CONFIG_JIT isn't defined.
I you're bisecting and find this change, check that your PCRE isn't
older than 8.32. This change intentionally broke really old versions
of PCRE, but that's fixed in follow-up commits.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
7531a2dd87
Коммит
fbaceaac47
40
grep.c
40
grep.c
|
@ -365,9 +365,22 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
|
|||
if (!p->pcre1_regexp)
|
||||
compile_regexp_failed(p, error);
|
||||
|
||||
p->pcre1_extra_info = pcre_study(p->pcre1_regexp, 0, &error);
|
||||
p->pcre1_extra_info = pcre_study(p->pcre1_regexp, PCRE_STUDY_JIT_COMPILE, &error);
|
||||
if (!p->pcre1_extra_info && error)
|
||||
die("%s", error);
|
||||
|
||||
#ifdef PCRE_CONFIG_JIT
|
||||
pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
|
||||
if (p->pcre1_jit_on == 1) {
|
||||
p->pcre1_jit_stack = pcre_jit_stack_alloc(1, 1024 * 1024);
|
||||
if (!p->pcre1_jit_stack)
|
||||
die("Couldn't allocate PCRE JIT stack");
|
||||
pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack);
|
||||
} else if (p->pcre1_jit_on != 0) {
|
||||
die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d",
|
||||
p->pcre1_jit_on);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
|
||||
|
@ -378,8 +391,19 @@ static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
|
|||
if (eflags & REG_NOTBOL)
|
||||
flags |= PCRE_NOTBOL;
|
||||
|
||||
ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line, eol - line,
|
||||
0, flags, ovector, ARRAY_SIZE(ovector));
|
||||
#ifdef PCRE_CONFIG_JIT
|
||||
if (p->pcre1_jit_on) {
|
||||
ret = pcre_jit_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
|
||||
eol - line, 0, flags, ovector,
|
||||
ARRAY_SIZE(ovector), p->pcre1_jit_stack);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
|
||||
eol - line, 0, flags, ovector,
|
||||
ARRAY_SIZE(ovector));
|
||||
}
|
||||
|
||||
if (ret < 0 && ret != PCRE_ERROR_NOMATCH)
|
||||
die("pcre_exec failed with error code %d", ret);
|
||||
if (ret > 0) {
|
||||
|
@ -394,7 +418,15 @@ static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
|
|||
static void free_pcre1_regexp(struct grep_pat *p)
|
||||
{
|
||||
pcre_free(p->pcre1_regexp);
|
||||
pcre_free(p->pcre1_extra_info);
|
||||
#ifdef PCRE_CONFIG_JIT
|
||||
if (p->pcre1_jit_on) {
|
||||
pcre_free_study(p->pcre1_extra_info);
|
||||
pcre_jit_stack_free(p->pcre1_jit_stack);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
pcre_free(p->pcre1_extra_info);
|
||||
}
|
||||
pcre_free((void *)p->pcre1_tables);
|
||||
}
|
||||
#else /* !USE_LIBPCRE1 */
|
||||
|
|
6
grep.h
6
grep.h
|
@ -3,9 +3,13 @@
|
|||
#include "color.h"
|
||||
#ifdef USE_LIBPCRE1
|
||||
#include <pcre.h>
|
||||
#ifndef PCRE_STUDY_JIT_COMPILE
|
||||
#define PCRE_STUDY_JIT_COMPILE 0
|
||||
#endif
|
||||
#else
|
||||
typedef int pcre;
|
||||
typedef int pcre_extra;
|
||||
typedef int pcre_jit_stack;
|
||||
#endif
|
||||
#include "kwset.h"
|
||||
#include "thread-utils.h"
|
||||
|
@ -48,7 +52,9 @@ struct grep_pat {
|
|||
regex_t regexp;
|
||||
pcre *pcre1_regexp;
|
||||
pcre_extra *pcre1_extra_info;
|
||||
pcre_jit_stack *pcre1_jit_stack;
|
||||
const unsigned char *pcre1_tables;
|
||||
int pcre1_jit_on;
|
||||
kwset_t kws;
|
||||
unsigned fixed:1;
|
||||
unsigned ignore_case:1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче