lbcd/mempool/memusage.go

90 lines
2.2 KiB
Go

// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package mempool
import (
"fmt"
"reflect"
)
var (
dynamicMemUsageAssert = false
dynamicMemUsageDebug = false
dynamicMemUsageMaxDepth = 10
)
func dynamicMemUsage(v reflect.Value) uintptr {
return dynamicMemUsageCrawl(v, 0)
}
func dynamicMemUsageCrawl(v reflect.Value, depth int) uintptr {
t := v.Type()
bytes := t.Size()
if dynamicMemUsageDebug {
println("[", depth, "]", t.Kind().String(), "(", t.String(), ") ->", t.Size())
}
if depth >= dynamicMemUsageMaxDepth {
if dynamicMemUsageAssert {
panic("crawl reached maximum depth")
}
return bytes
}
// For complex types, we need to peek inside slices/arrays/structs and chase pointers.
switch t.Kind() {
case reflect.Pointer, reflect.Interface:
if !v.IsNil() {
bytes += dynamicMemUsageCrawl(v.Elem(), depth+1)
}
case reflect.Array, reflect.Slice:
for j := 0; j < v.Len(); j++ {
vi := v.Index(j)
k := vi.Type().Kind()
if dynamicMemUsageDebug {
println("[", depth, "] index:", j, "kind:", k.String())
}
elemBytes := uintptr(0)
if t.Kind() == reflect.Array {
if (k == reflect.Pointer || k == reflect.Interface) && !vi.IsNil() {
elemBytes += dynamicMemUsageCrawl(vi.Elem(), depth+1)
}
} else { // slice
elemBytes += dynamicMemUsageCrawl(vi, depth+1)
}
if k == reflect.Uint8 {
// short circuit for byte slice/array
bytes += elemBytes * uintptr(v.Len())
if dynamicMemUsageDebug {
println("...", v.Len(), "elements")
}
break
}
bytes += elemBytes
}
case reflect.Struct:
for _, f := range reflect.VisibleFields(t) {
vf := v.FieldByIndex(f.Index)
k := vf.Type().Kind()
if dynamicMemUsageDebug {
println("[", depth, "] field:", f.Name, "kind:", k.String())
}
if (k == reflect.Pointer || k == reflect.Interface) && !vf.IsNil() {
bytes += dynamicMemUsageCrawl(vf.Elem(), depth+1)
} else if k == reflect.Array || k == reflect.Slice {
bytes -= vf.Type().Size()
bytes += dynamicMemUsageCrawl(vf, depth+1)
}
}
case reflect.Uint8:
default:
if dynamicMemUsageAssert {
panic(fmt.Sprintf("unsupported kind: %v", t.Kind()))
}
}
return bytes
}