Skip to content

Commit

Permalink
For objects, use a callback iterator instead of an explicit list of o…
Browse files Browse the repository at this point in the history
…bject pointers.

Saves on the space for the object ptrs.	Also matches ForEachPtr	and ForEachRootPtr APIs.
  • Loading branch information
randall77 committed Oct 1, 2017
1 parent 0f7d32a commit 80e4e4d
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 29 deletions.
6 changes: 0 additions & 6 deletions gocore/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,6 @@ func (p *Program) readObjects() {
p.heapInfo[x.Addr.Add(j).Sub(p.arenaStart)/512].firstIdx = i
}
}

// Build array-of-pointers for easy iteration over objects.
p.objPtrs = make([]*Object, len(p.objects))
for i := range p.objects {
p.objPtrs[i] = &p.objects[i]
}
}

// isPtr reports whether the inferior at address a contains a pointer.
Expand Down
12 changes: 8 additions & 4 deletions gocore/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ type Program struct {

// All live objects in the heap.
objects []Object
objPtrs []*Object

// memory usage by category
stats *Stats
Expand All @@ -59,9 +58,14 @@ func (p *Program) Goroutines() []*Goroutine {
return p.goroutines
}

// Objects returns all live objects in the heap.
func (p *Program) Objects() []*Object {
return p.objPtrs
// ForEachObject calls fn with each object in the Go heap.
// If fn returns false, ForEachObject returns immediately.
func (p *Program) ForEachObject(fn func(o *Object) bool) {
for i := 0; i < len(p.objects); i++ {
if !fn(&p.objects[i]) {
return
}
}
}

// Stats returns a breakdown of the program's memory use by category.
Expand Down
43 changes: 24 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,29 +153,30 @@ func main() {
}
var buckets []*bucket
m := map[string]*bucket{}
for _, obj := range c.Objects() {
c.ForEachObject(func(x *gocore.Object) bool {
var name string
if obj.Type == nil {
name = fmt.Sprintf("unk%d", obj.Size)
if x.Type == nil {
name = fmt.Sprintf("unk%d", x.Size)
} else {
name = obj.Type.String()
n := obj.Size / obj.Type.Size
name = x.Type.String()
n := x.Size / x.Type.Size
if n > 1 {
if obj.Repeat < n {
name = fmt.Sprintf("[%d+%d?]%s", obj.Repeat, n-obj.Repeat, name)
if x.Repeat < n {
name = fmt.Sprintf("[%d+%d?]%s", x.Repeat, n-x.Repeat, name)
} else {
name = fmt.Sprintf("[%d]%s", obj.Repeat, name)
name = fmt.Sprintf("[%d]%s", x.Repeat, name)
}
}
}
b := m[name]
if b == nil {
b = &bucket{name: name, size: obj.Size}
b = &bucket{name: name, size: x.Size}
buckets = append(buckets, b)
m[name] = b
}
b.count++
}
return true
})
sort.Slice(buckets, func(i, j int) bool {
return buckets[i].size*buckets[i].count > buckets[j].size*buckets[j].count
})
Expand All @@ -188,9 +189,10 @@ func main() {

case "breakdown":
var total int64
for _, obj := range c.Objects() {
total += obj.Size
}
c.ForEachObject(func(x *gocore.Object) bool {
total += x.Size
return true
})
alloc := c.Stats().Child("heap").Child("in use spans").Child("alloc")
alloc.Children = []*gocore.Stats{
&gocore.Stats{"live", total, nil},
Expand Down Expand Up @@ -257,7 +259,7 @@ func main() {
}
}
}
for _, x := range c.Objects() {
c.ForEachObject(func(x *gocore.Object) bool {
fmt.Fprintf(w, "o%x [label=\"%s\\n%d\"]\n", x.Addr, typeName(x), x.Size)
c.ForEachPtr(x, func(i int64, y *gocore.Object, j int64) bool {
fmt.Fprintf(w, "o%x -> o%x [label=\"%s\"", x.Addr, y.Addr, fieldName(x, i))
Expand All @@ -267,13 +269,15 @@ func main() {
fmt.Fprintf(w, "]\n")
return true
})
}
return true
})
fmt.Fprintf(w, "}")
w.Close()
case "objects":
for _, x := range c.Objects() {
c.ForEachObject(func(x *gocore.Object) bool {
fmt.Printf("%16x %s\n", x.Addr, typeName(x))
}
return true
})

case "reachable":
if len(args) < 3 {
Expand All @@ -299,15 +303,16 @@ func main() {

for {
changed := false
for _, x := range c.Objects() {
c.ForEachObject(func(x *gocore.Object) bool {
c.ForEachPtr(x, func(_ int64, y *gocore.Object, _ int64) bool {
if m[y] != 0 && (m[x] == 0 || m[x] > m[y]+1) {
m[x] = m[y] + 1
changed = true
}
return true
})
}
return true
})
if !changed {
break
}
Expand Down

0 comments on commit 80e4e4d

Please sign in to comment.