mirror of
https://github.com/golang/go
synced 2024-11-23 18:40:03 -07:00
runtime: eliminate one heapBitsForObject from scanobject
scanobject with ptrmask!=nil is only ever called with the base pointer of a heap object. Currently, scanobject calls heapBitsForObject, which goes to a great deal of trouble to check that the pointer points into the heap and to find the base of the object it points to, both of which are completely unnecessary in this case. Replace this call to heapBitsForObject with much simpler logic to fetch the span and compute the heap bits. Benchmark results with five runs: name old mean new mean delta BenchmarkBinaryTree17 9.21s × (0.95,1.02) 8.55s × (0.91,1.03) -7.16% (p=0.022) BenchmarkFannkuch11 2.65s × (1.00,1.00) 2.62s × (1.00,1.00) -1.10% (p=0.000) BenchmarkFmtFprintfEmpty 73.2ns × (0.99,1.01) 71.7ns × (1.00,1.01) -1.99% (p=0.004) BenchmarkFmtFprintfString 302ns × (0.99,1.00) 292ns × (0.98,1.02) -3.31% (p=0.020) BenchmarkFmtFprintfInt 281ns × (0.98,1.01) 279ns × (0.96,1.02) ~ (p=0.596) BenchmarkFmtFprintfIntInt 482ns × (0.98,1.01) 488ns × (0.95,1.02) ~ (p=0.419) BenchmarkFmtFprintfPrefixedInt 382ns × (0.99,1.01) 365ns × (0.96,1.02) -4.35% (p=0.015) BenchmarkFmtFprintfFloat 475ns × (0.99,1.01) 472ns × (1.00,1.00) ~ (p=0.108) BenchmarkFmtManyArgs 1.89µs × (1.00,1.01) 1.90µs × (0.94,1.02) ~ (p=0.883) BenchmarkGobDecode 22.4ms × (0.99,1.01) 21.9ms × (0.92,1.04) ~ (p=0.332) BenchmarkGobEncode 24.7ms × (0.98,1.02) 23.9ms × (0.87,1.07) ~ (p=0.407) BenchmarkGzip 397ms × (0.99,1.01) 398ms × (0.99,1.01) ~ (p=0.718) BenchmarkGunzip 96.7ms × (1.00,1.00) 96.9ms × (1.00,1.00) ~ (p=0.230) BenchmarkHTTPClientServer 71.5µs × (0.98,1.01) 68.5µs × (0.92,1.06) ~ (p=0.243) BenchmarkJSONEncode 46.1ms × (0.98,1.01) 44.9ms × (0.98,1.03) -2.51% (p=0.040) BenchmarkJSONDecode 86.1ms × (0.99,1.01) 86.5ms × (0.99,1.01) ~ (p=0.343) BenchmarkMandelbrot200 4.12ms × (1.00,1.00) 4.13ms × (1.00,1.00) +0.23% (p=0.000) BenchmarkGoParse 5.89ms × (0.96,1.03) 5.82ms × (0.96,1.04) ~ (p=0.522) BenchmarkRegexpMatchEasy0_32 141ns × (0.99,1.01) 142ns × (1.00,1.00) ~ (p=0.178) BenchmarkRegexpMatchEasy0_1K 408ns × (1.00,1.00) 392ns × (0.99,1.00) -3.83% (p=0.000) BenchmarkRegexpMatchEasy1_32 122ns × (1.00,1.00) 122ns × (1.00,1.00) ~ (p=0.178) BenchmarkRegexpMatchEasy1_1K 626ns × (1.00,1.01) 624ns × (0.99,1.00) ~ (p=0.122) BenchmarkRegexpMatchMedium_32 202ns × (0.99,1.00) 205ns × (0.99,1.01) +1.58% (p=0.001) BenchmarkRegexpMatchMedium_1K 54.4µs × (1.00,1.00) 55.5µs × (1.00,1.00) +1.86% (p=0.000) BenchmarkRegexpMatchHard_32 2.68µs × (1.00,1.00) 2.71µs × (1.00,1.00) +0.97% (p=0.002) BenchmarkRegexpMatchHard_1K 79.8µs × (1.00,1.01) 80.5µs × (1.00,1.01) +0.94% (p=0.003) BenchmarkRevcomp 590ms × (0.99,1.01) 585ms × (1.00,1.00) ~ (p=0.066) BenchmarkTemplate 111ms × (0.97,1.02) 112ms × (0.99,1.01) ~ (p=0.201) BenchmarkTimeParse 392ns × (1.00,1.00) 385ns × (1.00,1.00) -1.69% (p=0.000) BenchmarkTimeFormat 449ns × (0.98,1.01) 448ns × (0.99,1.01) ~ (p=0.550) Change-Id: Ie7c3830c481d96c9043e7bf26853c6c1d05dc9f4 Reviewed-on: https://go-review.googlesource.com/9364 Reviewed-by: Rick Hudson <rlh@golang.org>
This commit is contained in:
parent
05d53165ce
commit
63caec5dee
@ -561,11 +561,12 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the object b of size n bytes, adding pointers to wbuf.
|
||||
// If ptrmask != nil, it specifies where pointers are in b.
|
||||
// If ptrmask == nil, the GC bitmap should be consulted.
|
||||
// In this case, n may be an overestimate of the size; the GC bitmap
|
||||
// must also be used to make sure the scan stops at the end of b.
|
||||
// scanobject scans memory starting at b, adding pointers to gcw.
|
||||
// If ptrmask != nil, it specifies the pointer mask starting at b and
|
||||
// n specifies the number of bytes to scan.
|
||||
// If ptrmask == nil, b must point to the beginning of a heap object
|
||||
// and scanobject consults the GC bitmap for the pointer mask and the
|
||||
// spans for the size of the object (it ignores n).
|
||||
//go:nowritebarrier
|
||||
func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWork) {
|
||||
arena_start := mheap_.arena_start
|
||||
@ -576,11 +577,10 @@ func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWork) {
|
||||
var hbits heapBits
|
||||
|
||||
if ptrmask == nil {
|
||||
var s *mspan
|
||||
b, hbits, s = heapBitsForObject(b)
|
||||
if b == 0 {
|
||||
return
|
||||
}
|
||||
// b must point to the beginning of a heap object, so
|
||||
// we can get its bits and span directly.
|
||||
hbits = heapBitsForAddr(b)
|
||||
s := spanOfUnchecked(b)
|
||||
n = s.elemsize
|
||||
if n == 0 {
|
||||
throw("scanobject n == 0")
|
||||
|
@ -73,6 +73,7 @@ type gcWork struct {
|
||||
}
|
||||
|
||||
// put enqueues a pointer for the garbage collector to trace.
|
||||
// obj must point to the beginning of a heap object.
|
||||
//go:nowritebarrier
|
||||
func (ww *gcWork) put(obj uintptr) {
|
||||
w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
|
||||
|
@ -192,6 +192,25 @@ func inheap(b uintptr) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: spanOf and spanOfUnchecked are open-coded in a lot of places.
|
||||
// Use the functions instead.
|
||||
|
||||
// spanOf returns the span of p. If p does not point into the heap or
|
||||
// no span contains p, spanOf returns nil.
|
||||
func spanOf(p uintptr) *mspan {
|
||||
if p == 0 || p < mheap_.arena_start || p >= mheap_.arena_used {
|
||||
return nil
|
||||
}
|
||||
return spanOfUnchecked(p)
|
||||
}
|
||||
|
||||
// spanOfUnchecked is equivalent to spanOf, but the caller must ensure
|
||||
// that p points into the heap (that is, mheap_.arena_start <= p <
|
||||
// mheap_.arena_used).
|
||||
func spanOfUnchecked(p uintptr) *mspan {
|
||||
return h_spans[(p-mheap_.arena_start)>>_PageShift]
|
||||
}
|
||||
|
||||
func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
|
||||
_g_ := getg()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user