1 package compiler
2
3 import (
4 "bytes"
5 "fmt"
6 "testing"
7 "unsafe"
8
9 "github.com/tetratelabs/wazero/internal/asm"
10 "github.com/tetratelabs/wazero/internal/testing/require"
11 "github.com/tetratelabs/wazero/internal/wasm"
12 "github.com/tetratelabs/wazero/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 }
138
View as plain text