├── .gitignore ├── Makefile ├── README.md ├── build.sh ├── main.c ├── main.cpp ├── main.d ├── main.go ├── main.rs └── main.zig /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.wasm 3 | setenv.sh 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NUMBER=42 2 | 3 | WASI_SDK?=$(HOME)/wasi-sdk-22.0 4 | 5 | .PHONY: benchmark clean c-version cpp-version go-version tinygo-version d-version rust-version zig-fast-version zig-small-version 6 | 7 | all : benchmark 8 | 9 | benchmark: go.wasm zig-small.wasm zig-fast.wasm rust.wasm d.wasm c.wasm tinygo.wasm cpp.wasm 10 | @./build.sh ${NUMBER} | tee README.md 11 | 12 | go.wasm: main.go 13 | @GOOS=wasip1 GOARCH=wasm go build -ldflags="-s -w" -o $@ $< 14 | 15 | go-version: 16 | -@go version 17 | 18 | tinygo.wasm: main.go 19 | @tinygo build -target=wasi -no-debug -o $@ $< 20 | 21 | tinygo-version: 22 | -@tinygo version | sed 's/ (.*//' 23 | 24 | zig-fast.wasm: main.zig 25 | @zig build-exe -target wasm32-wasi-musl -O ReleaseFast -fstrip $< -femit-bin=$@ 26 | 27 | zig-fast-version: 28 | -@echo -n 'zig ' && zig version 29 | 30 | zig-small.wasm: main.zig 31 | @zig build-exe -target wasm32-wasi-musl -O ReleaseSmall $< -femit-bin=$@ 32 | 33 | zig-small-version: 34 | -@echo -n 'zig ' && zig version 35 | 36 | rust.wasm: main.rs 37 | @rustc $< -O -C lto=true -C codegen-units=1 -C strip=symbols --target wasm32-wasi -o $@ 38 | 39 | rust-version: 40 | -@rustc -V 41 | 42 | d.wasm: main.d 43 | @ldc2 \ 44 | --mtriple=wasm32-unknown-wasi \ 45 | -Oz \ 46 | --betterC \ 47 | --fvisibility=hidden \ 48 | -L$(WASI_SDK)/lib/clang/18/lib/wasi/libclang_rt.builtins-wasm32.a \ 49 | -L$(WASI_SDK)/share/wasi-sysroot/lib/wasm32-wasi/crt1.o \ 50 | -L$(WASI_SDK)/share/wasi-sysroot/lib/wasm32-wasi/libc.a \ 51 | -L--gc-sections \ 52 | -L--strip-all \ 53 | -of=$@ \ 54 | $< 55 | 56 | d-version: 57 | -@ldc2 --version | head -n 1 | sed 's/://' 58 | 59 | c.wasm: main.c 60 | @$(WASI_SDK)/bin/clang -O2 -mbulk-memory -s -o $@ $< 61 | 62 | c-version: 63 | @$(WASI_SDK)/bin/clang --version | grep 'clang version' 64 | 65 | cpp.wasm: main.cpp 66 | @$(WASI_SDK)/bin/clang++ -O2 -mbulk-memory -std=c++23 -s -fno-exceptions -o $@ $< 67 | 68 | cpp-version: 69 | -@$(WASI_SDK)/bin/clang++ --version | grep 'clang version' 70 | 71 | clean: 72 | -rm *.o *.wasm 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasi-benchmark 2 | 3 | Benchmark of WASI in several languages. This benchmark uses fibonacci number 42. 4 | 5 | ## Result 6 | 7 | |Name|Version|Size|Time| 8 | |-|-|-:|-| 9 | |c.wasm|clang version 18.1.2 (https://github.com/llvm/llvm-project 26a1d6601d727a96f4301d0d8647b5a42760ae0c)|23639|1.21| 10 | |cpp.wasm|clang version 18.1.2 (https://github.com/llvm/llvm-project 26a1d6601d727a96f4301d0d8647b5a42760ae0c)|187184|1.48| 11 | |d.wasm|LDC - the LLVM D compiler (1.37.0)|29961|1.24| 12 | |go.wasm|go version go1.22.2 linux/amd64|1638162|5.06| 13 | |rust.wasm|rustc 1.77.1 (7cf61ebde 2024-03-27)|59660|1.13| 14 | |tinygo.wasm|tinygo version 0.31.2 linux/amd64|28798|1.60| 15 | |zig-fast.wasm|zig 0.11.0|6556|1.38| 16 | |zig-small.wasm|zig 0.11.0|5061|1.74| 17 | 18 | ## License 19 | 20 | MIT 21 | 22 | ## Author 23 | 24 | Yasuhiro Matsumoto (a.k.a. mattn) 25 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | NUMBER=${1:-40} 6 | 7 | cat < /dev/null) 21 | SIZE=$(stat --printf="%s" $WASM) 22 | OUTPUT=$(/usr/bin/time --format=%e sh -c "wasmtime $WASM $NUMBER > /dev/null 2>&1" 2>&1) 23 | echo "|$WASM|$VERSION|$SIZE|$OUTPUT|" 24 | done 25 | 26 | cat < 2 | #include 3 | 4 | int 5 | fib(int n) { 6 | if (n <= 1) return n; 7 | return fib(n - 1) + fib(n -2); 8 | } 9 | 10 | int 11 | main(int argc, char* argv[]) { 12 | printf("%d\n", fib(atoi(argv[1]))); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | fib(int n) { 5 | if (n <= 1) return n; 6 | return fib(n - 1) + fib(n -2); 7 | } 8 | 9 | int 10 | main(int argc, char* argv[]) { 11 | if (argc != 2) { 12 | std::cerr << "Usage: " << argv[0] << " " << std::endl; 13 | return 1; 14 | } 15 | int n = std::stoi(argv[1]); 16 | if (n < 0) { 17 | std::cerr << "Number should be non-negative." << std::endl; 18 | return 1; 19 | } 20 | std::cout << fib(n) << std::endl; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /main.d: -------------------------------------------------------------------------------- 1 | extern (C): 2 | nothrow: 3 | @nogc: 4 | 5 | enum EX_SOFTWARE = 70; 6 | 7 | extern int errno; 8 | void _Exit(int status) @trusted; 9 | void perror(const char* s) @trusted; 10 | pragma(printf) int printf(const(char)* format, ...) @trusted; 11 | uint strtoul(const char* str, char** str_end, int base) @trusted; 12 | 13 | uint fib(uint n) 14 | { 15 | if (n < 2) return n; 16 | else return fib(n - 2) + fib(n - 1); 17 | } 18 | 19 | // https://github.com/WebAssembly/wasi-libc/commit/d9066a87c04748e7381695eaf01cc5c9a9c3003b 20 | int __main_argc_argv(int argc, char** argv) 21 | { 22 | if (argc != 2) 23 | { 24 | perror("error: argument not given"); 25 | _Exit(EX_SOFTWARE); 26 | } 27 | char* end = null; 28 | uint n = strtoul(argv[1], &end, 10); 29 | if (errno != 0) 30 | { 31 | perror("error: argument not a integer"); 32 | _Exit(EX_SOFTWARE); 33 | } 34 | printf("%lu\n", fib(n)); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "strconv" 6 | ) 7 | 8 | func fib(num uint32) uint32 { 9 | if num <= 1 { 10 | return num 11 | } 12 | return fib(num-2) + fib(num-1) 13 | } 14 | 15 | func main() { 16 | num, err := strconv.ParseUint(os.Args[1], 10, 32) 17 | if err != nil { 18 | panic(err) 19 | } 20 | println(fib(uint32(num))) 21 | } 22 | -------------------------------------------------------------------------------- /main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn fib(n: u32) -> u32 { 4 | return match n { 5 | 0 => 0, 6 | 1 => 1, 7 | _ => fib(n - 2) + fib(n - 1), 8 | }; 9 | } 10 | 11 | fn main() { 12 | let args: Vec = env::args().collect(); 13 | 14 | let number: u32 = match args.len() { 15 | 2 => match args[1].parse() { 16 | Ok(n) => n, 17 | Err(_) => { 18 | eprintln!("error: argument not an integer"); 19 | return; 20 | } 21 | }, 22 | _ => { 23 | eprintln!("error: argument not given"); 24 | return; 25 | } 26 | }; 27 | println!("{}", fib(number)); 28 | } 29 | -------------------------------------------------------------------------------- /main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | fn fib(n: u32) u32 { 4 | if (n == 0 or n == 1) return n; 5 | return fib(n - 1) + fib(n - 2); 6 | } 7 | 8 | pub fn main() anyerror!void { 9 | const allocator = std.heap.page_allocator; 10 | var args = try std.process.argsWithAllocator(allocator); 11 | _ = args.skip(); 12 | const str_num = args.next().?; 13 | const num = try std.fmt.parseInt(u32, str_num, 10); 14 | std.debug.print("{}\n", .{fib(num)}); 15 | } 16 | --------------------------------------------------------------------------------