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>
			
			
				maint
			
			
		
							parent
							
								
									7531a2dd87
								
							
						
					
					
						commit
						fbaceaac47
					
				
							
								
								
									
										38
									
								
								grep.c
								
								
								
								
							
							
						
						
									
										38
									
								
								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); | ||||
| #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; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Ævar Arnfjörð Bjarmason
						Ævar Arnfjörð Bjarmason