github.com/lbryio/lbcd@v0.22.119/mempool/memusage.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package mempool
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  )
    11  
    12  var (
    13  	dynamicMemUsageAssert   = false
    14  	dynamicMemUsageDebug    = false
    15  	dynamicMemUsageMaxDepth = 10
    16  )
    17  
    18  func dynamicMemUsage(v reflect.Value) uintptr {
    19  	return dynamicMemUsageCrawl(v, 0)
    20  }
    21  
    22  func dynamicMemUsageCrawl(v reflect.Value, depth int) uintptr {
    23  	t := v.Type()
    24  	bytes := t.Size()
    25  	if dynamicMemUsageDebug {
    26  		println("[", depth, "]", t.Kind().String(), "(", t.String(), ") ->", t.Size())
    27  	}
    28  
    29  	if depth >= dynamicMemUsageMaxDepth {
    30  		if dynamicMemUsageAssert {
    31  			panic("crawl reached maximum depth")
    32  		}
    33  		return bytes
    34  	}
    35  
    36  	// For complex types, we need to peek inside slices/arrays/structs and chase pointers.
    37  	switch t.Kind() {
    38  	case reflect.Pointer, reflect.Interface:
    39  		if !v.IsNil() {
    40  			bytes += dynamicMemUsageCrawl(v.Elem(), depth+1)
    41  		}
    42  	case reflect.Array, reflect.Slice:
    43  		for j := 0; j < v.Len(); j++ {
    44  			vi := v.Index(j)
    45  			k := vi.Type().Kind()
    46  			if dynamicMemUsageDebug {
    47  				println("[", depth, "] index:", j, "kind:", k.String())
    48  			}
    49  			elemBytes := uintptr(0)
    50  			if t.Kind() == reflect.Array {
    51  				if (k == reflect.Pointer || k == reflect.Interface) && !vi.IsNil() {
    52  					elemBytes += dynamicMemUsageCrawl(vi.Elem(), depth+1)
    53  				}
    54  			} else { // slice
    55  				elemBytes += dynamicMemUsageCrawl(vi, depth+1)
    56  			}
    57  			if k == reflect.Uint8 {
    58  				// short circuit for byte slice/array
    59  				bytes += elemBytes * uintptr(v.Len())
    60  				if dynamicMemUsageDebug {
    61  					println("...", v.Len(), "elements")
    62  				}
    63  				break
    64  			}
    65  			bytes += elemBytes
    66  		}
    67  	case reflect.Struct:
    68  		for _, f := range reflect.VisibleFields(t) {
    69  			vf := v.FieldByIndex(f.Index)
    70  			k := vf.Type().Kind()
    71  			if dynamicMemUsageDebug {
    72  				println("[", depth, "] field:", f.Name, "kind:", k.String())
    73  			}
    74  			if (k == reflect.Pointer || k == reflect.Interface) && !vf.IsNil() {
    75  				bytes += dynamicMemUsageCrawl(vf.Elem(), depth+1)
    76  			} else if k == reflect.Array || k == reflect.Slice {
    77  				bytes -= vf.Type().Size()
    78  				bytes += dynamicMemUsageCrawl(vf, depth+1)
    79  			}
    80  		}
    81  	case reflect.Uint8:
    82  	default:
    83  		if dynamicMemUsageAssert {
    84  			panic(fmt.Sprintf("unsupported kind: %v", t.Kind()))
    85  		}
    86  	}
    87  
    88  	return bytes
    89  }