Skip to content

Commit c39918a

Browse files
committed
cmd/compile: disable various write barrier optimizations
Several of our current write barrier elision optimizations are invalid with the hybrid barrier. Eliding the hybrid barrier requires that *both* the current and new pointer be already shaded and, since we don't have the flow analysis to figure out anything about the slot's current value, for now we have to just disable several of these optimizations. This has a slight impact on binary size. On linux/amd64, the go tool binary increases by 0.7% and the compile binary increases by 1.5%. It also has a slight impact on performance, as one would expect. We'll win some of this back in subsequent commits. name old time/op new time/op delta BinaryTree17-12 2.38s ± 1% 2.40s ± 1% +0.82% (p=0.000 n=18+20) Fannkuch11-12 2.84s ± 1% 2.70s ± 0% -4.97% (p=0.000 n=18+18) FmtFprintfEmpty-12 44.2ns ± 1% 46.4ns ± 2% +4.89% (p=0.000 n=16+18) FmtFprintfString-12 131ns ± 0% 134ns ± 1% +2.05% (p=0.000 n=12+19) FmtFprintfInt-12 114ns ± 1% 117ns ± 1% +3.26% (p=0.000 n=19+20) FmtFprintfIntInt-12 176ns ± 1% 181ns ± 1% +3.25% (p=0.000 n=20+20) FmtFprintfPrefixedInt-12 185ns ± 1% 190ns ± 1% +2.77% (p=0.000 n=19+18) FmtFprintfFloat-12 249ns ± 1% 254ns ± 1% +1.71% (p=0.000 n=18+20) FmtManyArgs-12 747ns ± 1% 743ns ± 1% -0.58% (p=0.000 n=19+18) GobDecode-12 6.57ms ± 1% 6.61ms ± 0% +0.73% (p=0.000 n=19+20) GobEncode-12 5.58ms ± 1% 5.60ms ± 0% +0.27% (p=0.001 n=18+18) Gzip-12 223ms ± 1% 223ms ± 1% ~ (p=0.351 n=19+20) Gunzip-12 37.9ms ± 0% 37.9ms ± 1% ~ (p=0.095 n=16+20) HTTPClientServer-12 77.8µs ± 1% 78.5µs ± 1% +0.97% (p=0.000 n=19+20) JSONEncode-12 14.8ms ± 1% 14.8ms ± 1% ~ (p=0.079 n=20+19) JSONDecode-12 53.7ms ± 1% 54.2ms ± 1% +0.92% (p=0.000 n=20+19) Mandelbrot200-12 3.81ms ± 1% 3.81ms ± 0% ~ (p=0.916 n=19+18) GoParse-12 3.19ms ± 1% 3.19ms ± 1% ~ (p=0.175 n=20+19) RegexpMatchEasy0_32-12 71.9ns ± 1% 70.6ns ± 1% -1.87% (p=0.000 n=19+20) RegexpMatchEasy0_1K-12 946ns ± 0% 944ns ± 0% -0.22% (p=0.000 n=19+16) RegexpMatchEasy1_32-12 67.3ns ± 2% 66.8ns ± 1% -0.72% (p=0.008 n=20+20) RegexpMatchEasy1_1K-12 374ns ± 1% 384ns ± 1% +2.69% (p=0.000 n=18+20) RegexpMatchMedium_32-12 107ns ± 1% 107ns ± 1% ~ (p=1.000 n=20+20) RegexpMatchMedium_1K-12 34.3µs ± 1% 34.6µs ± 1% +0.90% (p=0.000 n=20+20) RegexpMatchHard_32-12 1.78µs ± 1% 1.80µs ± 1% +1.45% (p=0.000 n=20+19) RegexpMatchHard_1K-12 53.6µs ± 0% 54.5µs ± 1% +1.52% (p=0.000 n=19+18) Revcomp-12 417ms ± 5% 391ms ± 1% -6.42% (p=0.000 n=16+19) Template-12 61.1ms ± 1% 64.2ms ± 0% +5.07% (p=0.000 n=19+20) TimeParse-12 302ns ± 1% 305ns ± 1% +0.90% (p=0.000 n=18+18) TimeFormat-12 319ns ± 1% 315ns ± 1% -1.25% (p=0.000 n=18+18) [Geo mean] 54.0µs 54.3µs +0.58% name old time/op new time/op delta XGarbage-12 2.24ms ± 2% 2.28ms ± 1% +1.68% (p=0.000 n=18+17) XHTTP-12 11.4µs ± 1% 11.6µs ± 2% +1.63% (p=0.000 n=18+18) XJSON-12 11.6ms ± 0% 12.5ms ± 0% +7.84% (p=0.000 n=18+17) Updates #17503. Change-Id: I1899f8e35662971e24bf692b517dfbe2b533c00c Reviewed-on: https://go-review.googlesource.com/31572 Reviewed-by: Keith Randall <[email protected]>
1 parent c3163d2 commit c39918a

File tree

5 files changed

+30
-34
lines changed

5 files changed

+30
-34
lines changed

src/cmd/compile/internal/gc/order.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func ordermapassign(n *Node, order *Order) {
423423
// We call writebarrierfat only for values > 4 pointers long. See walk.go.
424424
// TODO(mdempsky): writebarrierfat doesn't exist anymore, but removing that
425425
// logic causes net/http's tests to become flaky; see CL 21242.
426-
if needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr) && !isaddrokay(n.Right) {
426+
if needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr) && n.Right != nil && !isaddrokay(n.Right) {
427427
m := n.Left
428428
n.Left = ordertemp(m.Type, order, false)
429429
a := nod(OAS, m, n.Left)

src/cmd/compile/internal/gc/sinit.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,8 +750,13 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
750750
switch kind {
751751
case initKindStatic:
752752
a = walkexpr(a, init) // add any assignments in r to top
753+
if a.Op == OASWB {
754+
// Static initialization never needs
755+
// write barriers.
756+
a.Op = OAS
757+
}
753758
if a.Op != OAS {
754-
Fatalf("fixedlit: not as")
759+
Fatalf("fixedlit: not as, is %v", a)
755760
}
756761
a.IsStatic = true
757762
case initKindDynamic, initKindLocalCode:

src/cmd/compile/internal/gc/walk.go

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,8 @@ opswitch:
721721
break
722722
}
723723

724-
if n.Right == nil || iszero(n.Right) && !instrumenting {
724+
if n.Right == nil {
725+
// TODO(austin): Check all "implicit zeroing"
725726
break
726727
}
727728

@@ -2255,52 +2256,41 @@ func needwritebarrier(l *Node, r *Node) bool {
22552256
return false
22562257
}
22572258

2258-
// No write barrier for implicit zeroing.
2259-
if r == nil {
2260-
return false
2261-
}
2262-
22632259
// No write barrier if this is a pointer to a go:notinheap
22642260
// type, since the write barrier's inheap(ptr) check will fail.
22652261
if l.Type.IsPtr() && l.Type.Elem().NotInHeap {
22662262
return false
22672263
}
22682264

2265+
// Implicit zeroing is still zeroing, so it needs write
2266+
// barriers. In practice, these are all to stack variables
2267+
// (even if isstack isn't smart enough to figure that out), so
2268+
// they'll be eliminated by the backend.
2269+
if r == nil {
2270+
return true
2271+
}
2272+
22692273
// Ignore no-op conversions when making decision.
22702274
// Ensures that xp = unsafe.Pointer(&x) is treated
22712275
// the same as xp = &x.
22722276
for r.Op == OCONVNOP {
22732277
r = r.Left
22742278
}
22752279

2276-
// No write barrier for zeroing or initialization to constant.
2277-
if iszero(r) || r.Op == OLITERAL {
2278-
return false
2279-
}
2280-
2281-
// No write barrier for storing static (read-only) data.
2282-
if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
2283-
return false
2284-
}
2280+
// TODO: We can eliminate write barriers if we know *both* the
2281+
// current and new content of the slot must already be shaded.
2282+
// We know a pointer is shaded if it's nil, or points to
2283+
// static data, a global (variable or function), or the stack.
2284+
// The nil optimization could be particularly useful for
2285+
// writes to just-allocated objects. Unfortunately, knowing
2286+
// the "current" value of the slot requires flow analysis.
22852287

22862288
// No write barrier for storing address of stack values,
22872289
// which are guaranteed only to be written to the stack.
22882290
if r.Op == OADDR && isstack(r.Left) {
22892291
return false
22902292
}
22912293

2292-
// No write barrier for storing address of global, which
2293-
// is live no matter what.
2294-
if r.Op == OADDR && r.Left.isGlobal() {
2295-
return false
2296-
}
2297-
2298-
// No write barrier for storing global function, which is live
2299-
// no matter what.
2300-
if r.Op == ONAME && r.Class == PFUNC {
2301-
return false
2302-
}
2303-
23042294
// Otherwise, be conservative and use write barrier.
23052295
return true
23062296
}

test/fixedbugs/issue15747.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func f1(q *Q, xx []byte) interface{} { // ERROR "live at entry to f1: xx" "live
3434
//go:noinline
3535
func f2(d []byte, n int) (odata, res []byte, e interface{}) { // ERROR "live at entry to f2: d"
3636
if n > len(d) {
37-
return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d"
37+
return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d" "live at call to writebarrierptr: d"
3838
}
3939
res = d[:n]
4040
odata = d[n:]

test/writebarrier.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,9 @@ type T17 struct {
164164
}
165165

166166
func f17(x *T17) {
167-
// See golang.org/issue/13901
168-
x.f = f17 // no barrier
167+
// Originally from golang.org/issue/13901, but the hybrid
168+
// barrier requires both to have barriers.
169+
x.f = f17 // ERROR "write barrier"
169170
x.f = func(y *T17) { *y = *x } // ERROR "write barrier"
170171
}
171172

@@ -207,8 +208,8 @@ func f21(x *int) {
207208
// Global -> heap pointer updates must have write barriers.
208209
x21 = x // ERROR "write barrier"
209210
y21.x = x // ERROR "write barrier"
210-
x21 = &z21 // no barrier
211-
y21.x = &z21 // no barrier
211+
x21 = &z21 // ERROR "write barrier"
212+
y21.x = &z21 // ERROR "write barrier"
212213
y21 = struct{ x *int }{x} // ERROR "write barrier"
213214
}
214215

0 commit comments

Comments
 (0)