This repository contains all code related to a 3-part tutorial published on Medium: Part 1, Part 2, and Part 3
- Ubuntu >= 18.04. (macOS naturally works fine, but I have not tested it yet)
- Go >= 1.15
- swift-wasm >= wasm-5.3.1-RELEASE
- To install swiftenv, follow instructions on: https://swiftenv.fuller.li/en/latest/installation.html
- Download the latest version of swiftwasm from the release page: https://github.com/swiftwasm/swift/releases
- Install dependencies for running Swift on Linux
$ apt update $ apt install binutils git gnupg2 libc6-dev libcurl4 libedit2 libgcc-9-dev libpython2.7 libsqlite3-0 libstdc++-9-dev libxml2 libz3-dev pkg-config tzdata zlib1g-dev curl lsb-release
- Install wasmer by following instructions on: https://wasmer.io/
-
Set the correct version of Swiftwasm
$ swiftenv global wasm-5.3.1-RELEASE
-
Build Swift project and generate wasm binary:
$ TOOLCHAIN_PATH=$(cd $(dirname "$(swiftenv which swiftc)") && cd ../share && pwd) $ swift build --triple wasm32-unknown-wasi -c release --toolchain $TOOLCHAIN_PATH -Xlinker --export=allocate -Xlinker --export=deallocate -Xlinker --export=hello -Xlinker --export=sum -Xlinker --export=concatenate -Xlinker --export=fetch -Xlinker --allow-undefined
-
Copy wasm to the project's directory
$ cp swiftwasm/.build/release/swiftwasm.wasm ../binary.wasm
- (optionally) Run tests
$ binary=swift go test ./... -v -race -count 1 -run _Swift
- Run the Go application
$ go run ./ > Hello World! > '_start' called, but returned void: true > 'save' exported function: 3 > 'concatenate' exported function with string parameters: World World! > 'fetch_code imported function input: 2' 4
With the first stable version of swiftwasm (wasm-5.3.1-RELEASE), a swift generated binary offers a larger binary with a significantly poor performance comparing to Rust. The project contains a Rust sample project for comparison purposes.
The following comparison shows the binary size for a same set of functions in Rust and Swift, 1.7M and 9.8M respectively. The Swift binary is about 5 times larger than the Rust one.
$ ls -lh rust | grep wasm
-rwxrwxr-x 1 hassan hassan 1.7M Oct 30 20:33 binary.wasm
$ ls -lh swiftwasm | grep wasm
-rwxrwxr-x 1 hassan hassan 9.8M Oct 26 17:08 binary.wasm
Larger binary size is not the only issue with Swift generated binaries. The more important issue is where wasmer is almost 32 times slower in running Swift binaries comparing to Rust binaries with identical functions. With the execution times are same for both Rust and Swift, the main issue with Swift binary seems to be wasmer compilation issue for large binaries.
$ binary=rust go test ./... -race -count 1 -run _Rust
ok github.com/hassan-shahbazi/swiftwasi/src 0.214s
$ binary=swift go test ./... -race -count 1 -run _Swift
ok github.com/hassan-shahbazi/swiftwasi/src 6.899s
Discussed in #2135, using wasm-opt -0s
can significantly improve binary size from 9.8M to 4.4M which results in a the performance improvement from 6.899s to 3.547s.
$ ~/binaryen/bin/wasm-opt swiftwasm/binary.wasm -o swiftwasm/binary.wasm -Os
$ ls -lh swiftwasm | grep wasm
-rwxrwxr-x 1 hassan hassan 4.4M Nov 30 16:12 binary.wasm
$ binary=swift go test ./... -race -count 1 run _Swift
ok github.com/hassan-shahbazi/swiftwasi/src 3.547s