Benchmark libc.

This commit is contained in:
Nuno Cruces
2025-04-04 10:56:12 +01:00
parent 970eb6a2f9
commit e6c9f18934
13 changed files with 290 additions and 11 deletions

31
sqlite3/libc/build.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
cd -P -- "$(dirname -- "$0")"
ROOT=../../
BINARYEN="$ROOT/tools/binaryen/bin"
WASI_SDK="$ROOT/tools/wasi-sdk/bin"
trap 'rm -f libc.tmp' EXIT
"$WASI_SDK/clang" --target=wasm32-wasi -std=c23 -g0 -O2 \
-o libc.wasm ../strings.c \
-mexec-model=reactor \
-msimd128 -mmutable-globals -mmultivalue \
-mbulk-memory -mreference-types \
-mnontrapping-fptoint -msign-ext \
-fno-stack-protector -fno-stack-clash-protection \
-Wl,--initial-memory=16777216 \
-Wl,--export=memset \
-Wl,--export=memcpy \
-Wl,--export=memcmp
"$BINARYEN/wasm-ctor-eval" -g -c _initialize libc.wasm -o libc.tmp
"$BINARYEN/wasm-opt" -g --strip --strip-producers -c -O3 \
libc.tmp -o libc.wasm \
--enable-simd --enable-mutable-globals --enable-multivalue \
--enable-bulk-memory --enable-reference-types \
--enable-nontrapping-float-to-int --enable-sign-ext
"$BINARYEN/wasm-dis" -o libc.wat libc.wasm

BIN
sqlite3/libc/libc.wasm Executable file

Binary file not shown.

137
sqlite3/libc/libc.wat Normal file
View File

@@ -0,0 +1,137 @@
(module $libc.wasm
(type $0 (func (param i32 i32 i32) (result i32)))
(memory $0 256)
(data $0 (i32.const 1024) "\01")
(export "memory" (memory $0))
(export "memset" (func $memset))
(export "memcpy" (func $memcpy))
(export "memcmp" (func $memcmp))
(func $memset (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(memory.fill
(local.get $0)
(local.get $1)
(local.get $2)
)
(local.get $0)
)
(func $memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(memory.copy
(local.get $0)
(local.get $1)
(local.get $2)
)
(local.get $0)
)
(func $memcmp (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
(local $4 i32)
(block $block2
(block $block1
(block $block
(br_if $block
(i32.lt_u
(local.get $2)
(i32.const 8)
)
)
(br_if $block
(i32.and
(i32.or
(local.get $0)
(local.get $1)
)
(i32.const 7)
)
)
(loop $label
(br_if $block1
(i64.ne
(i64.load
(local.get $0)
)
(i64.load
(local.get $1)
)
)
)
(local.set $1
(i32.add
(local.get $1)
(i32.const 8)
)
)
(local.set $0
(i32.add
(local.get $0)
(i32.const 8)
)
)
(br_if $label
(i32.gt_u
(local.tee $2
(i32.sub
(local.get $2)
(i32.const 8)
)
)
(i32.const 7)
)
)
)
)
(br_if $block2
(i32.eqz
(local.get $2)
)
)
)
(loop $label1
(if
(i32.ne
(local.tee $3
(i32.load8_u
(local.get $0)
)
)
(local.tee $4
(i32.load8_u
(local.get $1)
)
)
)
(then
(return
(i32.sub
(local.get $3)
(local.get $4)
)
)
)
)
(local.set $1
(i32.add
(local.get $1)
(i32.const 1)
)
)
(local.set $0
(i32.add
(local.get $0)
(i32.const 1)
)
)
(br_if $label1
(local.tee $2
(i32.sub
(local.get $2)
(i32.const 1)
)
)
)
)
)
(i32.const 0)
)
;; features section: mutable-globals, nontrapping-float-to-int, simd, bulk-memory, sign-ext, reference-types, multivalue, bulk-memory-opt
)

96
sqlite3/libc/libc_test.go Normal file
View File

@@ -0,0 +1,96 @@
package libc
import (
"context"
_ "embed"
"os"
"testing"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
)
//go:embed libc.wasm
var binary []byte
const (
size = 1024 * 1024 * 4
ptr1 = 1024 * 1024
ptr2 = ptr1 + size
)
var (
memory []byte
module api.Module
memset api.Function
memcpy api.Function
memcmp api.Function
)
func call(fn api.Function, arg ...uint64) {
fn.CallWithStack(context.Background(), arg)
}
func TestMain(m *testing.M) {
ctx := context.Background()
runtime := wazero.NewRuntime(ctx)
mod, err := runtime.Instantiate(ctx, binary)
if err != nil {
panic(err)
}
module = mod
memset = mod.ExportedFunction("memset")
memcpy = mod.ExportedFunction("memcpy")
memcmp = mod.ExportedFunction("memcmp")
memory, _ = mod.Memory().Read(0, mod.Memory().Size())
os.Exit(m.Run())
}
func Benchmark_memset(b *testing.B) {
clear(memory)
b.ResetTimer()
for range b.N {
call(memset, ptr1, 3, size)
}
b.StopTimer()
for i, v := range memory[ptr1 : ptr1+size] {
if v != 3 {
b.Fatal(i, v)
}
}
}
func Benchmark_memcpy(b *testing.B) {
clear(memory)
call(memset, ptr2, 5, size)
b.ResetTimer()
for range b.N {
call(memcpy, ptr1, ptr2, size)
}
b.StopTimer()
for i, v := range memory[ptr1 : ptr1+size] {
if v != 5 {
b.Fatal(i, v)
}
}
}
func Benchmark_memcmp(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size)
call(memset, ptr2, 7, size)
call(memset, ptr2+size/2, 5, size)
b.ResetTimer()
for range b.N {
call(memcmp, ptr1, ptr2, size)
}
b.StopTimer()
}

View File

@@ -3,9 +3,19 @@
#include <stdint.h>
#if defined(__wasm_bulk_memory__)
#define memset __builtin_memset
#define memcpy __builtin_memcpy
#define memmove __builtin_memmove
void *memset(void *dest, int c, size_t n) {
return __builtin_memset(dest, c, n);
}
void *memcpy(void *restrict dest, const void *restrict src, size_t n) {
return __builtin_memcpy(dest, src, n);
}
void *memmove(void *dest, const void *src, size_t n) {
return __builtin_memmove(dest, src, n);
}
#endif
#define ONES (~(uintmax_t)(0) / UCHAR_MAX)