* cmd/geth, mobile: add memsize to pprof server This is a temporary change, to be reverted before the next release. * cmd/geth: fix variable name
		
			
				
	
	
		
			120 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package memsize
 | 
						|
 | 
						|
import (
 | 
						|
	"math/bits"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	uintptrBits  = 32 << (uint64(^uintptr(0)) >> 63)
 | 
						|
	uintptrBytes = uintptrBits / 8
 | 
						|
	bmBlockRange = 1 * 1024 * 1024 // bytes covered by bmBlock
 | 
						|
	bmBlockWords = bmBlockRange / uintptrBits
 | 
						|
)
 | 
						|
 | 
						|
// bitmap is a sparse bitmap.
 | 
						|
type bitmap struct {
 | 
						|
	blocks map[uintptr]*bmBlock
 | 
						|
}
 | 
						|
 | 
						|
func newBitmap() *bitmap {
 | 
						|
	return &bitmap{make(map[uintptr]*bmBlock)}
 | 
						|
}
 | 
						|
 | 
						|
// markRange sets n consecutive bits starting at addr.
 | 
						|
func (b *bitmap) markRange(addr, n uintptr) {
 | 
						|
	for end := addr + n; addr < end; {
 | 
						|
		block, baddr := b.block(addr)
 | 
						|
		for i := baddr; i < bmBlockRange && addr < end; i++ {
 | 
						|
			block.mark(i)
 | 
						|
			addr++
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// isMarked returns the value of the bit at the given address.
 | 
						|
func (b *bitmap) isMarked(addr uintptr) bool {
 | 
						|
	block, baddr := b.block(addr)
 | 
						|
	return block.isMarked(baddr)
 | 
						|
}
 | 
						|
 | 
						|
// countRange returns the number of set bits in the range (addr,addr+n).
 | 
						|
func (b *bitmap) countRange(addr, n uintptr) uintptr {
 | 
						|
	c := uintptr(0)
 | 
						|
	for end := addr + n; addr < end; {
 | 
						|
		block, baddr := b.block(addr)
 | 
						|
		bend := uintptr(bmBlockRange - 1)
 | 
						|
		if baddr+(end-addr) < bmBlockRange {
 | 
						|
			bend = baddr + (end - addr)
 | 
						|
		}
 | 
						|
		c += uintptr(block.count(baddr, bend))
 | 
						|
		// Move addr to next block.
 | 
						|
		addr += bmBlockRange - baddr
 | 
						|
	}
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
// block finds the block corresponding to the given memory address.
 | 
						|
// It also returns the block's starting address.
 | 
						|
func (b *bitmap) block(addr uintptr) (*bmBlock, uintptr) {
 | 
						|
	index := addr / bmBlockRange
 | 
						|
	block := b.blocks[index]
 | 
						|
	if block == nil {
 | 
						|
		block = new(bmBlock)
 | 
						|
		b.blocks[index] = block
 | 
						|
	}
 | 
						|
	return block, addr % bmBlockRange
 | 
						|
}
 | 
						|
 | 
						|
// size returns the sum of the byte sizes of all blocks.
 | 
						|
func (b *bitmap) size() uintptr {
 | 
						|
	return uintptr(len(b.blocks)) * bmBlockWords * uintptrBytes
 | 
						|
}
 | 
						|
 | 
						|
// utilization returns the mean percentage of one bits across all blocks.
 | 
						|
func (b *bitmap) utilization() float32 {
 | 
						|
	var avg float32
 | 
						|
	for _, block := range b.blocks {
 | 
						|
		avg += float32(block.count(0, bmBlockRange-1)) / float32(bmBlockRange)
 | 
						|
	}
 | 
						|
	return avg / float32(len(b.blocks))
 | 
						|
}
 | 
						|
 | 
						|
// bmBlock is a bitmap block.
 | 
						|
type bmBlock [bmBlockWords]uintptr
 | 
						|
 | 
						|
// mark sets the i'th bit to one.
 | 
						|
func (b *bmBlock) mark(i uintptr) {
 | 
						|
	b[i/uintptrBits] |= 1 << (i % uintptrBits)
 | 
						|
}
 | 
						|
 | 
						|
// isMarked returns the value of the i'th bit.
 | 
						|
func (b *bmBlock) isMarked(i uintptr) bool {
 | 
						|
	return (b[i/uintptrBits] & (1 << (i % uintptrBits))) != 0
 | 
						|
}
 | 
						|
 | 
						|
// count returns the number of set bits in the range (start,end).
 | 
						|
func (b *bmBlock) count(start, end uintptr) (count int) {
 | 
						|
	br := b[start/uintptrBits : end/uintptrBits+1]
 | 
						|
	for i, w := range br {
 | 
						|
		if i == 0 {
 | 
						|
			w &= blockmask(start)
 | 
						|
		}
 | 
						|
		if i == len(br)-1 {
 | 
						|
			w &^= blockmask(end)
 | 
						|
		}
 | 
						|
		count += onesCountPtr(w)
 | 
						|
	}
 | 
						|
	return count
 | 
						|
}
 | 
						|
 | 
						|
func blockmask(x uintptr) uintptr {
 | 
						|
	return ^uintptr(0) << (x % uintptrBits)
 | 
						|
}
 | 
						|
 | 
						|
func onesCountPtr(x uintptr) int {
 | 
						|
	if uintptrBits == 64 {
 | 
						|
		return bits.OnesCount64(uint64(x))
 | 
						|
	}
 | 
						|
	return bits.OnesCount32(uint32(x))
 | 
						|
}
 |