Skip to content

Commit

Permalink
gc benchmark init
Browse files Browse the repository at this point in the history
  • Loading branch information
ltzmaxwell committed Feb 26, 2025
1 parent 1b972a2 commit 3dc70b8
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 31 deletions.
6 changes: 6 additions & 0 deletions gnovm/cmd/benchops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ func main() {
if bm.OpsEnabled {
benchmarkOpCodes(bstore.gnoStore, dir)
}

if bm.GCEnabled {
benchmarkGC(bstore.gnoStore, dir)
}

if bm.StorageEnabled {
benchmarkStorage(bstore, dir)
}

bm.Finish()
stats(tmpFile)
err = os.Remove(tmpFile)
Expand Down
22 changes: 22 additions & 0 deletions gnovm/cmd/benchops/run.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"io"
"path/filepath"
"strings"
Expand All @@ -17,6 +18,7 @@ const (
)

func benchmarkOpCodes(bstore gno.Store, dir string) {
fmt.Println("Benchmarking opcodes, dir: ", dir)
opcodesPkgDir := filepath.Join(dir, "opcodes")

pv := addPackage(bstore, opcodesPkgDir, opcodesPkgPath)
Expand All @@ -26,6 +28,7 @@ func benchmarkOpCodes(bstore gno.Store, dir string) {
}

func callOpsBench(bstore gno.Store, pv *gno.PackageValue) {
fmt.Println("callOpsBench...")
// start
pb := pv.GetBlock(bstore)
for _, tv := range pb.Values {
Expand All @@ -36,6 +39,22 @@ func callOpsBench(bstore gno.Store, pv *gno.PackageValue) {
}
}

const (
gcPkgPath = "gno.land/r/x/benchmark/gc"
gcRounds = 1000
)

func benchmarkGC(bstore gno.Store, dir string) {
fmt.Println("Benchmarking GC, dir: ", dir)
fmt.Println("alloc: ", bstore.GetAllocator(), bstore.GetAllocator() == nil)
opcodesPkgDir := filepath.Join(dir, "gc")

pv := addPackage(bstore, opcodesPkgDir, gcPkgPath)
for i := 0; i < gcRounds; i++ {
callOpsBench(bstore, pv)
}
}

const storagePkgPath = "gno.land/r/x/benchmark/storage"

func benchmarkStorage(bstore BenchStore, dir string) {
Expand Down Expand Up @@ -85,6 +104,9 @@ func callFunc(gstore gno.Store, pv *gno.PackageValue, cx gno.Expr) []gno.TypedVa
Store: gstore,
})

gstore.GetAllocator().SetMachine(m)
m.Alloc = gstore.GetAllocator()

defer m.Release()

m.SetActivePackage(pv)
Expand Down
9 changes: 7 additions & 2 deletions gnovm/cmd/benchops/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type codeRecord struct {

// It reads binary record, calcuate and output the statistics of operations
func stats(binFile string) {
fmt.Printf("stats binFile: %s\n", binFile)
in, err := os.Open(binFile)
if err != nil {
panic("could not create benchmark file: " + err.Error())
Expand All @@ -48,9 +49,13 @@ func stats(binFile string) {
if !ok {
break
}
opName := gno.Op(record[0]).String()
if record[1] != 0 {
var opName string
if record[0] != 0 {
opName = gno.Op(record[0]).String()
} else if record[1] != 0 {
opName = bm.StoreCodeString(record[1])
} else if record[2] != 0 {
opName = bm.GCCodeString(record[2])
}

elapsedTime := binary.LittleEndian.Uint32(record[2:])
Expand Down
61 changes: 52 additions & 9 deletions gnovm/pkg/benchops/bench.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
package benchops

import (
"fmt"
"time"
)

const (
invalidCode = byte(0x00)
)

var measure bench
var measure *bench

type bench struct {
opCounts [256]int64
opAccumDur [256]time.Duration
opStartTime [256]time.Time
isOpCodeStarted bool
curOpCode byte
timeZero time.Time

storeCounts [256]int64
storeAccumDur [256]time.Duration
storeAccumSize [256]int64
storeStartTime [256]time.Time
curStoreCode byte

gcCounts [2]int64
gcAccumDur [2]time.Duration
gcStartTime [2]time.Time
isGCCodeStarted bool
curGCCode byte

timeZero time.Time
}

func InitMeasure() {
measure = bench{
// this will be called to reset each benchmarking
isOpCodeStarted: false,
curOpCode: invalidCode,
curStoreCode: invalidCode,
if measure != nil {
return
} else {
measure = &bench{
// this will be called to reset each benchmarking
isOpCodeStarted: false,
isGCCodeStarted: false,
curOpCode: invalidCode,
curStoreCode: invalidCode,
curGCCode: invalidCode,
}
}
}

Expand All @@ -52,7 +66,7 @@ func StartOpCode(code byte) {
func StopOpCode() {
code := measure.curOpCode
if measure.opStartTime[code] == measure.timeZero {
panic("Can not stop a stopped timer")
panic("Can not stop a stopped timer for OpCode")
}
measure.opAccumDur[code] += time.Since(measure.opStartTime[code])
measure.opStartTime[code] = measure.timeZero // stop the timer
Expand Down Expand Up @@ -106,11 +120,40 @@ func StopStore(size int) {
code := measure.curStoreCode

if measure.storeStartTime[code] == measure.timeZero {
panic("Can not stop a stopped timer")
panic("Can not stop a stopped timer for store")
}

measure.storeAccumDur[code] += time.Since(measure.storeStartTime[code])
measure.storeStartTime[code] = measure.timeZero // stop the timer
measure.storeAccumSize[code] += int64(size)
measure.curStoreCode = invalidCode
}

func StartGCCode(code byte) {
fmt.Println("======StartGCCode, code: ", code)
if code == invalidCode {
panic("the GCCode is invalid")
}
if measure.gcStartTime[code] != measure.timeZero {
panic("Can not start a non-stopped timer")
}

measure.gcStartTime[code] = time.Now()
measure.gcCounts[code]++
fmt.Println("gcCounts[code]: ", measure.gcCounts[code])

measure.isGCCodeStarted = true
measure.curGCCode = code
}

// Stop the current measurement
func StopGCCode() {
code := measure.curGCCode
if measure.gcStartTime[code] == measure.timeZero {
panic("Can not stop a stopped timer for GC")
}

measure.gcAccumDur[code] += time.Since(measure.gcStartTime[code])
measure.gcStartTime[code] = measure.timeZero // stop the timer
measure.isGCCodeStarted = false
}
39 changes: 32 additions & 7 deletions gnovm/pkg/benchops/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

// the byte size of a exported record
const RecordSize int = 10
const RecordSize int = 11

var fileWriter *exporter

Expand Down Expand Up @@ -43,9 +43,9 @@ func (e *exporter) export(code Code, elapsedTime time.Duration, size int64) {
log.Fatalf("size %d out of uint32 range", size)
}

buf := []byte{code[0], code[1], 0, 0, 0, 0, 0, 0, 0, 0}
binary.LittleEndian.PutUint32(buf[2:], uint32(elapsedTime))
binary.LittleEndian.PutUint32(buf[6:], uint32(size))
buf := []byte{code[0], code[1], code[2], 0, 0, 0, 0, 0, 0, 0, 0}
binary.LittleEndian.PutUint32(buf[3:], uint32(elapsedTime))
binary.LittleEndian.PutUint32(buf[7:], uint32(size))
_, err := e.file.Write(buf)
if err != nil {
panic("could not write to benchmark file: " + err.Error())
Expand All @@ -66,10 +66,10 @@ func FinishStore() {
}
// check unstopped timer
if measure.storeStartTime[i] != measure.timeZero {
panic("timer should have stopped before FinishRun")
panic("timer should have stopped before FinishStore")
}

code := [2]byte{0x00, byte(i)}
code := [3]byte{0x00, byte(i), 0x00}

fileWriter.export(
code,
Expand All @@ -89,12 +89,28 @@ func FinishRun() {
panic("timer should have stopped before FinishRun")
}

code := [2]byte{byte(i), 0x00}
code := [3]byte{byte(i), 0x00, 0x00}
fileWriter.export(code, measure.opAccumDur[i]/time.Duration(measure.opCounts[i]), 0)
}
ResetRun()
}

func FinishGC() {
for i := 0; i < len(measure.gcCounts); i++ {
if measure.gcCounts[i] == 0 {
continue
}
// check unstopped timer
if measure.gcStartTime[i] != measure.timeZero {
panic("timer should have stopped before FinishGC")
}

code := [3]byte{0x00, 0x00, byte(i)}
fileWriter.export(code, measure.gcAccumDur[i]/time.Duration(measure.gcCounts[i]), 0)
}
ResetGC()
}

// It reset each machine Runs
func ResetRun() {
measure.opCounts = [256]int64{}
Expand All @@ -104,6 +120,15 @@ func ResetRun() {
measure.isOpCodeStarted = false
}

// It reset each GC
func ResetGC() {
measure.gcCounts = [2]int64{}
measure.gcAccumDur = [2]time.Duration{}
measure.gcStartTime = [2]time.Time{}
measure.curGCCode = invalidCode
measure.isGCCodeStarted = false
}

func Finish() {
fileWriter.close()
}
5 changes: 5 additions & 0 deletions gnovm/pkg/benchops/gc_disabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build !benchmarkingops

package benchops

const GCEnabled = false
5 changes: 5 additions & 0 deletions gnovm/pkg/benchops/gc_enabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build benchmarkingops

package benchops

const GCEnabled = true
10 changes: 10 additions & 0 deletions gnovm/pkg/benchops/gno/gc/gc.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package gc

import "runtime"

func Alloc1() {
data := make([]byte, 100*1024*1024)
data = nil
runtime.GC()
println("MemStats after GC: ", runtime.MemStats())
}
1 change: 1 addition & 0 deletions gnovm/pkg/benchops/gno/gc/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/r/x/benchmark/gc
29 changes: 26 additions & 3 deletions gnovm/pkg/benchops/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ var storeCodeNames = []string{
"FinalizeTx",
}

type Code [2]byte
type Code [3]byte

func VMOpCode(opCode byte) Code {
return [2]byte{opCode, 0x00}
return [3]byte{opCode, 0x00, 0x00}
}

func StoreCode(storeCode byte) Code {
return [2]byte{0x00, storeCode}
return [3]byte{0x00, storeCode, 0x00}
}

func GCCode(gcCode byte) Code {
return [3]byte{0x00, 0x00, gcCode}
}

func StoreCodeString(storeCode byte) string {
Expand All @@ -70,3 +74,22 @@ func StoreCodeString(storeCode byte) string {
}
return storeCodeNames[storeCode]
}

// gc code
const (
invalidGCCode string = "GCInvalid"
VisitObject byte = 0x01
)

// the index of the code string should match with the constant code number above.
var gcCodeNames = []string{
invalidGCCode,
"VisitObject",
}

func GCCodeString(gcCode byte) string {
if int(gcCode) >= len(gcCodeNames) {
return invalidStoreCode
}
return gcCodeNames[gcCode]
}
8 changes: 6 additions & 2 deletions gnovm/pkg/gnolang/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func NewAllocator(maxBytes int64, m *Machine) *Allocator {
}
}

func (alloc *Allocator) SetMachine(m *Machine) {
alloc.m = m
}

func (alloc *Allocator) MemStats() string {
if alloc == nil {
return "nil allocator"
Expand Down Expand Up @@ -123,7 +127,7 @@ func (alloc *Allocator) Allocate(size int64) {
if left, ok := alloc.m.GarbageCollect(); !ok {
panic("allocation limit exceeded")
} else { // retry
debug2.Printf2("%d left after GC: \n", left)
debug2.Printf2("%d left after GC, size: %d \n", left, size)
alloc.bytes += size
if alloc.bytes > alloc.maxBytes {
panic("allocation limit exceeded")
Expand Down Expand Up @@ -348,7 +352,7 @@ func (p *PackageValue) GetShallowSize() int64 {
return allocPackage
}
func (b *Block) GetShallowSize() int64 {
debug2.Println2("GetShallowSize: ", b)
//debug2.Println2("GetShallowSize: ", b)
return allocBlock
}

Expand Down
4 changes: 2 additions & 2 deletions gnovm/pkg/gnolang/debug_false.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ package gnolang

const debug debugging = false

//const debug2 debugging = true
const debug2 debugging = true

const debug2 debugging = false
//const debug2 debugging = false
Loading

0 comments on commit 3dc70b8

Please sign in to comment.