diff options
author | haya14busa <haya14busa@gmail.com> | 2017-03-17 00:41:58 +0900 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2017-03-23 00:02:55 +0000 |
commit | 8a16d7d40a371e61f6d30604224039cf9a46d106 (patch) | |
tree | bb4f502cc193995fb145cb291f824afbd8adec2f /src/regexp | |
parent | 9e6b79a5dfb2f6fe4301ced956419a0da83bd025 (diff) | |
download | go-git-8a16d7d40a371e61f6d30604224039cf9a46d106.tar.gz |
regexp: reduce allocs in regexp.Match for onepass regex
There were no allocations in regexp.Match for *non* onepass regex
because m.matchcap length is reset to zero (ncap=0 for regexp.Match).
But, as for onepass regex, m.matchcap length remains as it is even when
ncap=0 and it leads needless allocations.
benchmark old ns/op new ns/op delta
BenchmarkMatch_onepass_regex/32-4 6465 4628 -28.41%
BenchmarkMatch_onepass_regex/1K-4 208324 151558 -27.25%
BenchmarkMatch_onepass_regex/32K-4 7230259 5834492 -19.30%
BenchmarkMatch_onepass_regex/1M-4 234379810 166310682 -29.04%
BenchmarkMatch_onepass_regex/32M-4 7903529363 4981119950 -36.98%
benchmark old MB/s new MB/s speedup
BenchmarkMatch_onepass_regex/32-4 4.95 6.91 1.40x
BenchmarkMatch_onepass_regex/1K-4 4.92 6.76 1.37x
BenchmarkMatch_onepass_regex/32K-4 4.53 5.62 1.24x
BenchmarkMatch_onepass_regex/1M-4 4.47 6.30 1.41x
BenchmarkMatch_onepass_regex/32M-4 4.25 6.74 1.59x
benchmark old allocs new allocs delta
BenchmarkMatch_onepass_regex/32-4 32 0 -100.00%
BenchmarkMatch_onepass_regex/1K-4 1024 0 -100.00%
BenchmarkMatch_onepass_regex/32K-4 32768 0 -100.00%
BenchmarkMatch_onepass_regex/1M-4 1048576 0 -100.00%
BenchmarkMatch_onepass_regex/32M-4 104559255 0 -100.00%
benchmark old bytes new bytes delta
BenchmarkMatch_onepass_regex/32-4 512 0 -100.00%
BenchmarkMatch_onepass_regex/1K-4 16384 0 -100.00%
BenchmarkMatch_onepass_regex/32K-4 524288 0 -100.00%
BenchmarkMatch_onepass_regex/1M-4 16777216 0 -100.00%
BenchmarkMatch_onepass_regex/32M-4 2019458128 0 -100.00%
Fixes #19573
Change-Id: I033982d0003ebb0360bb40b92eb3941c781ec74d
Reviewed-on: https://go-review.googlesource.com/38270
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/regexp')
-rw-r--r-- | src/regexp/exec.go | 6 | ||||
-rw-r--r-- | src/regexp/exec_test.go | 29 |
2 files changed, 33 insertions, 2 deletions
diff --git a/src/regexp/exec.go b/src/regexp/exec.go index 977619cb28..f8fe7b5def 100644 --- a/src/regexp/exec.go +++ b/src/regexp/exec.go @@ -309,12 +309,14 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty // onepass runs the machine over the input starting at pos. // It reports whether a match was found. // If so, m.matchcap holds the submatch information. -func (m *machine) onepass(i input, pos int) bool { +// ncap is the number of captures. +func (m *machine) onepass(i input, pos, ncap int) bool { startCond := m.re.cond if startCond == ^syntax.EmptyOp(0) { // impossible return false } m.matched = false + m.matchcap = m.matchcap[:ncap] for i := range m.matchcap { m.matchcap[i] = -1 } @@ -428,7 +430,7 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i size = len(s) } if m.op != notOnePass { - if !m.onepass(i, pos) { + if !m.onepass(i, pos, ncap) { re.put(m) return nil } diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go index 766394de6e..5f8e747b17 100644 --- a/src/regexp/exec_test.go +++ b/src/regexp/exec_test.go @@ -681,6 +681,35 @@ func BenchmarkMatch(b *testing.B) { } } +func BenchmarkMatch_onepass_regex(b *testing.B) { + isRaceBuilder := strings.HasSuffix(testenv.Builder(), "-race") + r := MustCompile(`(?s)\A.*\z`) + if r.get().op == notOnePass { + b.Fatalf("want onepass regex, but %q is not onepass", r) + } + for _, size := range benchSizes { + if isRaceBuilder && size.n > 1<<10 { + continue + } + t := makeText(size.n) + bs := make([][]byte, len(t)) + for i, s := range t { + bs[i] = []byte{s} + } + b.Run(size.name, func(b *testing.B) { + b.SetBytes(int64(size.n)) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, byts := range bs { + if !r.Match(byts) { + b.Fatal("not match!") + } + } + } + }) + } +} + var benchData = []struct{ name, re string }{ {"Easy0", "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"}, {"Easy0i", "(?i)ABCDEFGHIJklmnopqrstuvwxyz$"}, |