mirror of
https://github.com/golang/go
synced 2024-11-24 05:50:13 -07:00
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>
This commit is contained in:
parent
9e6b79a5df
commit
8a16d7d40a
@ -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
|
||||
}
|
||||
|
@ -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$"},
|
||||
|
Loading…
Reference in New Issue
Block a user