Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds gojs for Go generated Wasm #621

Merged
merged 14 commits into from
Aug 26, 2022
Merged

Adds gojs for Go generated Wasm #621

merged 14 commits into from
Aug 26, 2022

Conversation

codefromthecrypt
Copy link
Contributor

@codefromthecrypt codefromthecrypt commented Jun 4, 2022

This adds an experimental package gojs which implements the host side of Wasm compiled by GOARCH=wasm GOOS=js go build -o X.wasm X.go

This includes heavy disclaimers, in part inherited by Go's comments https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L10-L11
Due to this many will still use TinyGo instead.

That said, this is frequently asked for and has interesting features including reflection and HTTP client support.

Ex.

// Grant the compiled wasm access to the default HTTP Transport.
ctx = gojs.WithRoundTripper(ctx, http.DefaultTransport)

// Execute the "run" function with the binary you compiled via
// `GOARCH=wasm GOOS=js go build -o X.wasm X.go`
err = gojs.Run(ctx, r, compiled, config)
if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() != 0 {
	log.Panicln(err)
} else if !ok {
	log.Panicln(err)
}

Fixes #432

internal/wasm/host.go Outdated Show resolved Hide resolved
@codefromthecrypt codefromthecrypt force-pushed the wasm_exec branch 2 times, most recently from 147d609 to aa2a48e Compare August 25, 2022 09:01
@codefromthecrypt codefromthecrypt changed the title Adds wasm_exec for Go generated Wasm Adds gojs for Go generated Wasm Aug 25, 2022
@tetratelabs tetratelabs deleted a comment from mathetake Aug 25, 2022
@codefromthecrypt codefromthecrypt marked this pull request as ready for review August 25, 2022 09:23
@codefromthecrypt
Copy link
Contributor Author

hmm the tests on CI take 40s which I assume is due to the amount of time it takes to compile. I might make a different approach where the tests use a single binary switched on arg. should reduce time and also flake

@codefromthecrypt
Copy link
Contributor Author

ok actually the execution speed of wasm is also a reason why it was slower. Regardless this is now compiling once for the package and re-using the same binary for parallel tests. Finishes in 1/4 the time on my laptop now.

@@ -0,0 +1,36 @@
package main
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mathetake fyi this might be a decent one to use for some perf curiosity tests as it makes 7.7MB of wasm that doesn't execute very fast due to so many host functions (and allocations within them)

@codefromthecrypt
Copy link
Contributor Author

Actually, the runtime performance is so bad I'm kindof wondering if we should just dump this.

Ex the below is literally returning a mock response

$ time go run stars.go 
wazero has 9999999 stars. Does that include you?

real    0m4.523s
user    0m8.657s
sys     0m0.563s

Also a fake main takes a second to execute:

func main() {
	fmt.Println("hello")
}

@prep @paralin do you have a working example on https://github.com/prep/wasmexec that can compare execution time across its 3 runtimes? I want to double-check there's not something wrong with the impl here.

iotw I was expecting slow, but not second+ slow, and I'm not sure what use cases can be met by that slow as even docker is faster.

@paralin
Copy link

paralin commented Aug 25, 2022

I would recommend removing the wasm startup time from the benchmark. Just measure how fast the calls are without parsing wasm

@codefromthecrypt
Copy link
Contributor Author

@paralin was thinking the same thing. I'll add a real benchmark which shows compile vs (instantiate/run). Instantiate and run are coupled as GOOS=js uses host state (host side values) coupled with wasm state (data segments etc).

@codefromthecrypt
Copy link
Contributor Author

ok @paralin's thoughts were right. Since @mathetake recently implemented compilation cache. Using GOARCH=wasm GOOS=js without it is incredibly slow due to the size and the complexity of the Wasm generated.

$ cd examples/gojs
$ go run .
2022/08/26 09:09:12 CompileModule took 4576ms with 36062KB cache
wazero has 9999999 stars. Does that include you?
2022/08/26 09:09:12 gojs.Run took 20ms

$ go run .
2022/08/26 09:09:15 CompileModule took 145ms with 36074KB cache
wazero has 9999999 stars. Does that include you?
2022/08/26 09:09:15 gojs.Run took 28ms

While still slow at runtime vs TinyGo, it isn't slow enough to endanger our CI anymore.

I think people building apps than embed wazero that runs GOARCH=wasm GOOS=js in docker...
They should use a cache dir, possibly doing a one-time run as a part of building the image, as otherwise people using the container will suffer and extraordinary first hit penalty every time.

@codefromthecrypt
Copy link
Contributor Author

@mathetake PTAL I think we are good. I'm not going to make a full on bench for gojs right now as already way over time budget and there is too much to review as it is. However, I think things are in good enough shape to review for merge.

Adrian Cole added 14 commits August 26, 2022 12:36
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Adrian Cole <adrian@tetrate.io>
@codefromthecrypt
Copy link
Contributor Author

codefromthecrypt commented Aug 26, 2022

One thing I noticed, but won't dig into at the moment, is this has no ability to collaborate with ad-hoc JavaScript at the moment (ex define ad-hoc functions in JS like spicedb cc @josephschorr)

This was out of scope for reasons of doing something like that needing a JavaScript engine which isn't a zero dependency thing in go, and makes the PR bigger also.

Currently, the only js functions supported are those Go defines in their own source code, so basically no dynamic javascript parsing. This makes sense because as wazero is for non-browser use, starting with only what go uses allows folks to at least use normal go. Many won't expect to inject dynamic functions into it.

@codefromthecrypt
Copy link
Contributor Author

The other thing left out is that Go allows via .s files the ability to import custom functions. This was left out as the calling convention Go uses is completely unlike the rest of WebAssembly and making something to implement that especially before people ask for it would be odd. https://wazero.io/languages/go/#user-defined-host-functions

@paralin
Copy link

paralin commented Aug 26, 2022

Looks cool, will test!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support GOOS=js GOARCH=wasm generated code
3 participants