github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/compiler/compiler_bench_test.go (about)

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