Skip to content

Commit 1510a91

Browse files
committed
cmd/viewcore: handle 1.14 free spans
Free spans are now implicit. Derive the free span information by finding all the memory in the inuse address ranges that isn't attributed to any span. Fixes viewcore for all versions of 1.14. Also works for tip. Fixes golang/go#38638 Change-Id: Ied283f59391aad8ed5b1b657d2fd6e89e9e9ae6c Reviewed-on: https://go-review.googlesource.com/c/debug/+/232161 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent cdf388b commit 1510a91

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

internal/gocore/gocore_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,5 @@ func TestVersions(t *testing.T) {
270270
loadExampleVersion(t, "1.12.zip")
271271
loadExampleVersion(t, "1.13.zip")
272272
loadExampleVersion(t, "1.13.3.zip")
273+
loadExampleVersion(t, "1.14.zip")
273274
}

internal/gocore/process.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package gocore
77
import (
88
"debug/dwarf"
99
"fmt"
10+
"math/bits"
1011
"strings"
1112
"sync"
1213

@@ -306,7 +307,7 @@ func (p *Process) readSpans(mheap region, arenas []arena) {
306307
panic("weird mapping " + m.Perm().String())
307308
}
308309
}
309-
if mheap.HasField("curArena") {
310+
if mheap.HasField("curArena") { // go1.13.3 and up
310311
// Subtract from the heap unallocated space
311312
// in the current arena.
312313
ca := mheap.Field("curArena")
@@ -431,6 +432,54 @@ func (p *Process) readSpans(mheap region, arenas []arena) {
431432
}
432433
}
433434
}
435+
if mheap.HasField("pages") { // go1.14+
436+
// There are no longer "free" mspans to represent unused pages.
437+
// Instead, there are just holes in the pagemap into which we can allocate.
438+
// Look through the page allocator and count the total free space.
439+
// Also keep track of how much has been scavenged.
440+
pages := mheap.Field("pages")
441+
chunks := pages.Field("chunks")
442+
arenaBaseOffset := p.rtConstants["arenaBaseOffset"]
443+
pallocChunkBytes := p.rtConstants["pallocChunkBytes"]
444+
pallocChunksL1Bits := p.rtConstants["pallocChunksL1Bits"]
445+
pallocChunksL2Bits := p.rtConstants["pallocChunksL2Bits"]
446+
inuse := pages.Field("inUse")
447+
ranges := inuse.Field("ranges")
448+
for i := int64(0); i < ranges.SliceLen(); i++ {
449+
r := ranges.SliceIndex(i)
450+
base := core.Address(r.Field("base").Uintptr())
451+
limit := core.Address(r.Field("limit").Uintptr())
452+
chunkBase := (int64(base) + arenaBaseOffset) / pallocChunkBytes
453+
chunkLimit := (int64(limit) + arenaBaseOffset) / pallocChunkBytes
454+
for chunkIdx := chunkBase; chunkIdx < chunkLimit; chunkIdx++ {
455+
var l1, l2 int64
456+
if pallocChunksL1Bits == 0 {
457+
l2 = chunkIdx
458+
} else {
459+
l1 = chunkIdx >> uint(pallocChunksL2Bits)
460+
l2 = chunkIdx & (1<<uint(pallocChunksL2Bits) - 1)
461+
}
462+
chunk := chunks.ArrayIndex(l1).Deref().ArrayIndex(l2)
463+
// Count the free bits in this chunk.
464+
alloc := chunk.Field("pallocBits")
465+
for i := int64(0); i < pallocChunkBytes/pageSize/64; i++ {
466+
freeSpanSize += int64(bits.OnesCount64(^alloc.ArrayIndex(i).Uint64())) * pageSize
467+
}
468+
// Count the scavenged bits in this chunk.
469+
scavenged := chunk.Field("scavenged")
470+
for i := int64(0); i < pallocChunkBytes/pageSize/64; i++ {
471+
releasedSpanSize += int64(bits.OnesCount64(scavenged.ArrayIndex(i).Uint64())) * pageSize
472+
}
473+
}
474+
}
475+
// Also count pages in the page cache for each P.
476+
allp := p.rtGlobals["allp"]
477+
for i := int64(0); i < allp.SliceLen(); i++ {
478+
pcache := allp.SliceIndex(i).Deref().Field("pcache")
479+
freeSpanSize += int64(bits.OnesCount64(pcache.Field("cache").Uint64())) * pageSize
480+
releasedSpanSize += int64(bits.OnesCount64(pcache.Field("scav").Uint64())) * pageSize
481+
}
482+
}
434483

435484
p.stats = &Stats{"all", all, []*Stats{
436485
&Stats{"text", text, nil},

internal/gocore/testdata/1.14.zip

784 KB
Binary file not shown.

0 commit comments

Comments
 (0)