mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	 b839eda2a9
			
		
	
	b839eda2a9
	
	
	
		
			
			Prefetch the entire memory of structs and arrays and cache it instead of issuing readMemory calls only when we get down to primitive types. This reduces the number of system calls to ptrace that variables makes. Improves performance in general, greatly improving it in some particular cases (involving large structs). Benchmarks without prefetching: BenchmarkArray-4 10 132189944 ns/op 0.06 MB/s BenchmarkArrayPointer-4 5 202538503 ns/op 0.04 MB/s BenchmarkMap-4 500 3804336 ns/op 0.27 MB/s BenchmarkGoroutinesInfo-4 10 126397104 ns/op BenchmarkLocalVariables-4 500 2494846 ns/op Benchmarks with prefetching: BenchmarkArray-4 200 10719087 ns/op 0.76 MB/s BenchmarkArrayPointer-4 100 11931326 ns/op 0.73 MB/s BenchmarkMap-4 1000 1466479 ns/op 0.70 MB/s BenchmarkGoroutinesInfo-4 10 103407004 ns/op BenchmarkLocalVariables-4 1000 1530395 ns/op Improvement factors: BenchmarkArray 12.33x BenchmarkArrayPointer 16.97x BenchmarkMap 2.59x BenchmarkGoroutinesInfo 1.22x BenchmarkLocalVariables 1.63x
		
			
				
	
	
		
			55 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			55 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package proc
 | |
| 
 | |
| const cacheEnabled = true
 | |
| 
 | |
| type memoryReadWriter interface {
 | |
| 	readMemory(addr uintptr, size int) (data []byte, err error)
 | |
| 	writeMemory(addr uintptr, data []byte) (written int, err error)
 | |
| }
 | |
| 
 | |
| type memCache struct {
 | |
| 	cacheAddr uintptr
 | |
| 	cache     []byte
 | |
| 	mem       memoryReadWriter
 | |
| }
 | |
| 
 | |
| func (m *memCache) contains(addr uintptr, size int) bool {
 | |
| 	return addr >= m.cacheAddr && (addr+uintptr(size)) <= (m.cacheAddr+uintptr(len(m.cache)))
 | |
| }
 | |
| 
 | |
| func (m *memCache) readMemory(addr uintptr, size int) (data []byte, err error) {
 | |
| 	if m.contains(addr, size) {
 | |
| 		d := make([]byte, size)
 | |
| 		copy(d, m.cache[addr-m.cacheAddr:])
 | |
| 		return d, nil
 | |
| 	}
 | |
| 
 | |
| 	return m.mem.readMemory(addr, size)
 | |
| }
 | |
| 
 | |
| func (m *memCache) writeMemory(addr uintptr, data []byte) (written int, err error) {
 | |
| 	return m.mem.writeMemory(addr, data)
 | |
| }
 | |
| 
 | |
| func cacheMemory(mem memoryReadWriter, addr uintptr, size int) memoryReadWriter {
 | |
| 	if !cacheEnabled {
 | |
| 		return mem
 | |
| 	}
 | |
| 	if cacheMem, isCache := mem.(*memCache); isCache {
 | |
| 		if cacheMem.contains(addr, size) {
 | |
| 			return mem
 | |
| 		} else {
 | |
| 			cache, err := cacheMem.mem.readMemory(addr, size)
 | |
| 			if err != nil {
 | |
| 				return mem
 | |
| 			}
 | |
| 			return &memCache{addr, cache, mem}
 | |
| 		}
 | |
| 	}
 | |
| 	cache, err := mem.readMemory(addr, size)
 | |
| 	if err != nil {
 | |
| 		return mem
 | |
| 	}
 | |
| 	return &memCache{addr, cache, mem}
 | |
| }
 |