Skip to content

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

Open
@iamhopaul123

Description

@iamhopaul123

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);

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performancearch-wasmWebAssembly issues

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions