wa-lang.org/wazero@v1.0.2/internal/engine/compiler/compiler_bench_test.go (about)

     1  package compiler
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  	"unsafe"
     8  
     9  	"wa-lang.org/wazero/internal/wasm"
    10  	"wa-lang.org/wazero/internal/wazeroir"
    11  )
    12  
    13  func BenchmarkCompiler_compileMemoryCopy(b *testing.B) {
    14  	sizes := []uint32{5, 17, 128, 10000, 64000}
    15  
    16  	for _, size := range sizes {
    17  		for _, overlap := range []bool{false, true} {
    18  			b.Run(fmt.Sprintf("%v-%v", size, overlap), func(b *testing.B) {
    19  				env := newCompilerEnvironment()
    20  
    21  				mem := env.memory()
    22  				testMem := make([]byte, len(mem))
    23  				for i := 0; i < len(mem); i++ {
    24  					mem[i] = byte(i)
    25  					testMem[i] = byte(i)
    26  				}
    27  
    28  				compiler, _ := newCompiler(&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}}, false)
    29  				err := compiler.compilePreamble()
    30  				requireNoError(b, err)
    31  
    32  				var destOffset, sourceOffset uint32
    33  				if !overlap {
    34  					destOffset, sourceOffset = 1, 777
    35  				} else {
    36  					destOffset, sourceOffset = 777, 1
    37  				}
    38  
    39  				err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: destOffset})
    40  				requireNoError(b, err)
    41  				err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: sourceOffset})
    42  				requireNoError(b, err)
    43  				err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: size})
    44  				requireNoError(b, err)
    45  				err = compiler.compileMemoryCopy()
    46  				requireNoError(b, err)
    47  				err = compiler.(compilerImpl).compileReturnFunction()
    48  				requireNoError(b, err)
    49  				code, _, err := compiler.compile()
    50  				requireNoError(b, err)
    51  
    52  				env.execBench(b, code)
    53  
    54  				for i := 0; i < b.N; i += 1 {
    55  					copy(testMem[destOffset:destOffset+size], testMem[sourceOffset:sourceOffset+size])
    56  				}
    57  
    58  				if !bytes.Equal(mem, testMem) {
    59  					b.FailNow()
    60  				}
    61  			})
    62  		}
    63  	}
    64  }
    65  
    66  func BenchmarkCompiler_compileMemoryFill(b *testing.B) {
    67  	sizes := []uint32{5, 17, 128, 10000, 64000}
    68  
    69  	for _, size := range sizes {
    70  		b.Run(fmt.Sprintf("%v", size), func(b *testing.B) {
    71  			env := newCompilerEnvironment()
    72  
    73  			mem := env.memory()
    74  			testMem := make([]byte, len(mem))
    75  			for i := 0; i < len(mem); i++ {
    76  				mem[i] = byte(i)
    77  				testMem[i] = byte(i)
    78  			}
    79  
    80  			compiler, _ := newCompiler(&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}}, false)
    81  			err := compiler.compilePreamble()
    82  			requireNoError(b, err)
    83  
    84  			var startOffset uint32 = 100
    85  			var value uint8 = 5
    86  
    87  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: startOffset})
    88  			requireNoError(b, err)
    89  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(value)})
    90  			requireNoError(b, err)
    91  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: size})
    92  			requireNoError(b, err)
    93  			err = compiler.compileMemoryFill()
    94  			requireNoError(b, err)
    95  			err = compiler.(compilerImpl).compileReturnFunction()
    96  			requireNoError(b, err)
    97  			code, _, err := compiler.compile()
    98  			requireNoError(b, err)
    99  
   100  			env.execBench(b, code)
   101  
   102  			for i := startOffset; i < startOffset+size; i++ {
   103  				testMem[i] = value
   104  			}
   105  			if !bytes.Equal(mem, testMem) {
   106  				b.FailNow()
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  func (j *compilerEnv) execBench(b *testing.B, codeSegment []byte) {
   113  	b.StartTimer()
   114  	for i := 0; i < b.N; i++ {
   115  		nativecall(
   116  			uintptr(unsafe.Pointer(&codeSegment[0])),
   117  			uintptr(unsafe.Pointer(j.ce)),
   118  			uintptr(unsafe.Pointer(j.moduleInstance)),
   119  		)
   120  	}
   121  	b.StopTimer()
   122  }
   123  
   124  func requireNoError(b *testing.B, err error) {
   125  	if err != nil {
   126  		b.Fatal(err)
   127  	}
   128  }