mirror of
https://github.com/golang/go
synced 2024-11-19 07:54:43 -07:00
cmd/internal/gc: speed up large string switches
Switch statements do a binary search on long runs of constants. Doing a less-than comparison on a string is much more expensive than on (say) an int. Use two part comparison for strings: First compare length, then the strings themselves. Benchmarks from issue 10000: benchmark old ns/op new ns/op delta BenchmarkIf0 3.36 3.35 -0.30% BenchmarkIf1 4.45 4.47 +0.45% BenchmarkIf2 5.22 5.26 +0.77% BenchmarkIf3 5.56 5.58 +0.36% BenchmarkIf4 10.5 10.6 +0.95% BenchmarkIfNewStr0 5.26 5.30 +0.76% BenchmarkIfNewStr1 7.19 7.15 -0.56% BenchmarkIfNewStr2 7.23 7.16 -0.97% BenchmarkIfNewStr3 7.47 7.43 -0.54% BenchmarkIfNewStr4 12.4 12.2 -1.61% BenchmarkSwitch0 9.56 4.24 -55.65% BenchmarkSwitch1 8.64 5.58 -35.42% BenchmarkSwitch2 9.38 10.1 +7.68% BenchmarkSwitch3 8.66 5.00 -42.26% BenchmarkSwitch4 7.99 8.18 +2.38% BenchmarkSwitchNewStr0 11.3 6.12 -45.84% BenchmarkSwitchNewStr1 11.1 8.33 -24.95% BenchmarkSwitchNewStr2 11.0 11.1 +0.91% BenchmarkSwitchNewStr3 10.3 6.93 -32.72% BenchmarkSwitchNewStr4 11.0 11.2 +1.82% Fixes #10000 Change-Id: Ia2fffc32e9843425374c274064f709ec7ee46d80 Reviewed-on: https://go-review.googlesource.com/7698 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
6ffed3020c
commit
4bc9badd75
@ -314,7 +314,16 @@ func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
|
||||
// find the middle and recur
|
||||
half := len(cc) / 2
|
||||
a := Nod(OIF, nil, nil)
|
||||
a.Ntest = Nod(OLE, s.exprname, cc[half-1].node.Left)
|
||||
mid := cc[half-1].node.Left
|
||||
le := Nod(OLE, s.exprname, mid)
|
||||
if Isconst(mid, CTSTR) {
|
||||
// Search by length and then by value; see exprcmp.
|
||||
lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
|
||||
leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
|
||||
a.Ntest = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
|
||||
} else {
|
||||
a.Ntest = le
|
||||
}
|
||||
typecheck(&a.Ntest, Erv)
|
||||
a.Nbody = list1(s.walkCases(cc[:half]))
|
||||
a.Nelse = list1(s.walkCases(cc[half:]))
|
||||
@ -750,7 +759,19 @@ func exprcmp(c1, c2 *caseClause) int {
|
||||
case CTINT, CTRUNE:
|
||||
return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval)
|
||||
case CTSTR:
|
||||
return cmpslit(n1, n2)
|
||||
// Sort strings by length and then by value.
|
||||
// It is much cheaper to compare lengths than values,
|
||||
// and all we need here is consistency.
|
||||
// We respect this sorting in exprSwitch.walkCases.
|
||||
a := n1.Val.U.Sval
|
||||
b := n2.Val.U.Sval
|
||||
if len(a) < len(b) {
|
||||
return -1
|
||||
}
|
||||
if len(a) > len(b) {
|
||||
return +1
|
||||
}
|
||||
return stringsCompare(a, b)
|
||||
}
|
||||
|
||||
return 0
|
||||
|
Loading…
Reference in New Issue
Block a user