go/test/opt_branchlikely.go
David Chase 6b3462c784 [dev.ssa] cmd/compile: adjust branch likeliness for calls/loops
Static branch predictions (which guide block ordering) are
adjusted based on:

loop/not-loop     (favor looping)
abnormal-exit/not (avoid panic)
call/not-call     (avoid call)
ret/default       (treat returns as rare)

This appears to make no difference in performance of real
code, meaning the compiler itself.  The earlier version of
this has been stripped down to help make the cost of this
only-aesthetic-on-Intel phase be as cheap as possible (we
probably want information about inner loops for improving
register allocation, but because register allocation follows
close behind this pass, conceivably the information could be
reused -- so we might do this anyway just to normalize
output).

For a ./make.bash that takes 200 user seconds, about .75
second is reported in likelyadjust (summing nanoseconds
reported with -d=ssa/likelyadjust/time ).

Upstream predictions are respected.
Includes test, limited to build on amd64 only.
Did several iterations on the debugging output to allow
some rough checks on behavior.
Debug=1 logging notes agree/disagree with earlier passes,
allowing analysis like the following:

Run on make.bash:
GO_GCFLAGS=-d=ssa/likelyadjust/debug \
   ./make.bash >& lkly5.log

grep 'ranch prediction' lkly5.log | wc -l
   78242 // 78k predictions

grep 'ranch predi' lkly5.log | egrep -v 'agrees with' | wc -l
   29633 // 29k NEW predictions

grep 'disagrees' lkly5.log | wc -l
     444 // contradicted 444 times

grep '< exit' lkly5.log | wc -l
   10212 // 10k exit predictions

grep '< exit' lkly5.log | egrep 'disagrees' | wc -l
       5 // 5 contradicted by previous prediction

grep '< exit' lkly5.log | egrep -v 'agrees' | wc -l
     702 // 702-5 redundant with previous prediction

grep '< call' lkly5.log | egrep -v 'agrees' | wc -l
   16699 // 16k new call predictions

grep 'stay in loop' lkly5.log | egrep -v 'agrees' | wc -l
    3951 // 4k new "remain in loop" predictions

Fixes #11451.

Change-Id: Iafb0504f7030d304ef4b6dc1aba9a5789151a593
Reviewed-on: https://go-review.googlesource.com/19995
Run-TryBot: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-03-01 20:09:41 +00:00

86 lines
1.9 KiB
Go

// +build amd64
// errorcheck -0 -d=ssa/likelyadjust/debug=1
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that branches have some prediction properties.
package foo
func f(x, y, z int) int {
a := 0
for i := 0; i < x; i++ { // ERROR "Branch prediction rule stay in loop"
for j := 0; j < y; j++ { // ERROR "Branch prediction rule stay in loop"
a += j
}
for k := 0; k < z; k++ { // ERROR "Branch prediction rule stay in loop"
a -= x + y + z
}
}
return a
}
func g(x, y, z int) int {
a := 0
if y == 0 { // ERROR "Branch prediction rule default < call"
y = g(y, z, x)
} else {
y++
}
if y == x { // ERROR "Branch prediction rule default < call"
y = g(y, z, x)
} else {
}
if y == 2 { // ERROR "Branch prediction rule default < call"
z++
} else {
y = g(z, x, y)
}
if y+z == 3 { // ERROR "Branch prediction rule call < exit"
println("ha ha")
} else {
panic("help help help")
}
if x != 0 { // ERROR "Branch prediction rule default < ret"
for i := 0; i < x; i++ { // ERROR "Branch prediction rule stay in loop"
if x == 4 { // ERROR "Branch prediction rule stay in loop"
return a
}
for j := 0; j < y; j++ { // ERROR "Branch prediction rule stay in loop"
for k := 0; k < z; k++ { // ERROR "Branch prediction rule stay in loop"
a -= j * i
}
a += j
}
}
}
return a
}
func h(x, y, z int) int {
a := 0
for i := 0; i < x; i++ { // ERROR "Branch prediction rule stay in loop"
for j := 0; j < y; j++ { // ERROR "Branch prediction rule stay in loop"
a += j
if i == j { // ERROR "Branch prediction rule stay in loop"
break
}
a *= j
}
for k := 0; k < z; k++ { // ERROR "Branch prediction rule stay in loop"
a -= k
if i == k {
continue
}
a *= k
}
}
if a > 0 { // ERROR "Branch prediction rule default < call"
a = g(x, y, z)
} else {
a = -a
}
return a
}