• Inphi's avatar
    cannon: Fix GC emulation of Go programs (#11704) · 7ff5e6ed
    Inphi authored
    * cannon: Fix GC emulation of Go programs
    
    Improves Linux/MIPS32 emulation for Go programs that utilize the garbage
    collector and goroutine scheduling.
    
    This adds support for the following syscalls:
    
    - getpid - used by the go scheduler
    - clock_gettime - used by the go scheduler and for GC assists and to properly emulate
      time related operations such as `time.Sleep`.
    
    Note on GC assists:
    
    The Go GC relies on `clock_gettime` for GC "assists", whereby a mutator can perform a little bit
    of GC without waiting for the scheduler to do so.
    A monotonic clock (runtime.nanotime) is used to compute the current goroutine's compute budget.
    By modeling a MIPS32 CPU that runs at some clock speed (ex: 10 MHz), we can provide a consistent
    emulation of monotonic time needed by the Go runtime.
    All other clock_gettime flags are handled as unimplemented syscalls.
    
    * fix unsupported syscalls test
    
    * fix some review comments
    
    * address review comments
    
    * update snapshots
    
    * fuzz invalid memory proof
    
    * reduce test runtime
    
    * tweak realtime emulation
    
    * reduce test runtime
    
    * set a high timeout for heavy fuzz tests
    
    * simplify fuzz
    
    * fix heavy tests
    7ff5e6ed
main.go 1 KB
package main

import (
	"encoding/binary"
	"fmt"
	"runtime"

	preimage "github.com/ethereum-optimism/optimism/op-preimage"
)

func main() {
	var mem []byte
	po := preimage.NewOracleClient(preimage.ClientPreimageChannel())
	numAllocs := binary.LittleEndian.Uint64(po.Get(preimage.LocalIndexKey(0)))
	allocSize := binary.LittleEndian.Uint64(po.Get(preimage.LocalIndexKey(1)))

	fmt.Printf("alloc program. numAllocs=%d allocSize=%d\n", numAllocs, allocSize)
	var alloc int
	for i := 0; i < int(numAllocs); i++ {
		mem = make([]byte, allocSize)
		alloc += len(mem)
		// touch a couple pages to prevent the runtime from overcommitting memory
		for j := 0; j < len(mem); j += 1024 {
			mem[j] = 0xFF
		}
		printGCStats(alloc)
	}

	fmt.Println("alloc program exit")
	printGCStats(alloc)
}

func printGCStats(alloc int) {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	fmt.Printf("allocated %d bytes. memstats: heap_alloc=%d next_gc=%d frees=%d mallocs=%d num_gc=%d\n",
		alloc, m.HeapAlloc, m.NextGC, m.Frees, m.Mallocs, m.NumGC)
}