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

misc/wasm: Go's WASM running slow in Node v19 #59748

Open
iamhopaul123 opened this issue Apr 20, 2023 · 3 comments
Open

misc/wasm: Go's WASM running slow in Node v19 #59748

iamhopaul123 opened this issue Apr 20, 2023 · 3 comments
Labels
arch-wasm WebAssembly issues NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance
Milestone

Comments

@iamhopaul123
Copy link

iamhopaul123 commented Apr 20, 2023

What version of Go are you using (go version)?

$ go version
go version go1.20.3 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/penghaoh/.cache/go-build"
GOENV="/Users/penghaoh/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/penghaoh/Workplace/my_go_workspace/pkg/mod"
GONOPROXY="*"
GONOSUMDB="*"
GOOS="darwin"
GOPATH="/Users/penghaoh/Workplace/my_go_workspace"
GOPRIVATE="*"
GOPROXY="direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.20.3"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/h0/6tx4n9fn59z1vj88py9mncmr00vbmk/T/go-build2636679718=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

  • Make a go program trying to reuse some logic in our project written in Go
main.go
var done chan bool

func init() {
	done = make(chan bool)
}

func main() {
	var hash js.Func
	hash = js.FuncOf(func(this js.Value, args []js.Value) any {
		h := crypto.SHA512.New()
		h.Write([]byte(args[0].String()))
		return hex.EncodeToString(h.Sum(nil))
	})
	js.Global().Set("wasmHash", hash)
	var close js.Func
	close = js.FuncOf(func(this js.Value, args []js.Value) any {
		defer close.Release()
		defer hash.Release()
		done <- true
		return nil
	})
	js.Global().Set("close", close)
	<-done
}

  • Build it with GOOS=js GOARCH=wasm go build -o wasm.wasm main.go and the binary size is 19.4 MB (i add some extra dependencies to simulate the real project for this prototype)
  • Compress the wasm file gzip -9 -v -c wasm.wasm > wasm.wasm.gz
  • Run it with node ./main.js
main.js
const pako = require("pako");
require("./wasm_exec");
fs = require("fs");

const wasmBuffer = new Uint8Array(pako.ungzip(fs.readFileSync("wasm.wasm.gz")));
const go = new Go();
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(wasmBuffer, go.importObject).then((wasmModule) => {
  go.run(wasmModule.instance);
  console.log(wasmHash("asdf"));
  close();
  process.on("exit", (code) => {
    // Node.js exits if no event handler is pending

    // commend the block avoid deadlock
    if (code === 0 && !go.exited) {
      // deadlock, make Go print error and stack traces
      go._pendingEvent = { id: 0 };
      go._resume();
    }
    process.exit();
  });
  return;
});

What did you expect to see?

The hashed result for asdf showing up instantly.

What did you see instead?

If the binary size is big, after seeing the result, it takes 5 seconds on my machine to exit. However, it is surprising to me that if I rewrite the js file in deno, it exits instantly after printing the result in my terminal.

deno.js
import * as _ from "./wasm_exec.js";
const go = new window.Go();
const f = await Deno.open("./wasm.wasm");
const buf = await Deno.readAll(f);
const inst = await WebAssembly.instantiate(buf, go.importObject);
go.run(inst.instance);
const result = wasmHash("asdf");
console.log(result);

@prattmic prattmic added Performance arch-wasm WebAssembly issues NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Apr 21, 2023
@prattmic
Copy link
Member

It sounds like this is more of an issue of Node.js being much slower than Deno, but maybe there is something we can do here?

cc @golang/wasm

@prattmic prattmic added this to the Backlog milestone Apr 21, 2023
@iamhopaul123
Copy link
Author

I don't feel like it is the performance difference because the actual result shows up quickly using Nodejs. There's just a weird hang after calling all the go func. It doesn't even work if I call process.exit(0) explicitly and the call stack is all empty.

@evanw
Copy link

evanw commented Jun 4, 2023

This is probably the following bug in node that they never fixed: nodejs/node#36616. There is a horrible hack that you can do to work around this if you really want to fix it: nodejs/node#36616 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-wasm WebAssembly issues NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance
Projects
None yet
Development

No branches or pull requests

3 participants