-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
cmd/compile: wasm code causes out of memory error on Chrome and Firefox for Android #27462
Comments
Since the code is same for all desktop, iOS and Android devices, I doubt there is much we can do here. @neelance has some optimizations in mind for 1.12. But unless you have some specific suggestions, this just falls in the category of general optimizations which will happen anyways. |
Given the market share of Android devices, this would be a major drawback ... |
can you try this?
|
btw @termonio - You should also build with |
@thesyncim: @agnivade: Your hint has a similar effect. The payload is reduced to 2.3MB, but can't be run on Android. For someone who wants to reproduce this issue: iOS devices need a polyfill (omitted in my minimal code example above).
|
you can try other optimization levels like -O2 or -O4 for binary size consider using -Os or -Oz |
I did try other optimization levels but got core dumps (not further investigated yet). |
@termonio try to run with -d (debug option) (in my case running with -d avoid core dumps, also -O4 requires a lot of memory) |
@thesyncim: running with |
@thesyncim : Yes indeed. I tried all 12 combinations (with and without |
I looked into the |
The solution most likely depends on https://github.com/WebAssembly/design/blob/master/FutureFeatures.md#finer-grained-control-over-memory. However, even currently it is not necessary for the WebAssembly host and operating system to physically allocate the full amount of memory, since most of it is not used. For example on Chrome on OS X, the operating system reports a much lower memory usage than the 1GB that WebAssembly requests. |
Why does WebAssembly allocate this 1GB of (mostly unused) memory in the first place? Is there a way to limit the amount of memory it can request? ( |
The initial 1 GB memory is control by this line: https://go.googlesource.com/go/+/go1.11/src/cmd/link/internal/wasm/asm.go#310 I don't think we will change this setting in Go 1.11. But you can modify the source and rebuild the toolchain. |
@neelance - I see a TODO there to use lower initial memory size. I believe the challenge to set the correct initial memory size is to somehow analyze the code being compiled and come up with the base minimum memory the code would need ? Is it possible to hoist this from being hardcoded in the binary to being set from the importObject ? So that the user has control over the value. Or do we not want to expose more knobs ? |
I wrote a small tool that can patch the memory section of a |
This is not nearly as efficient as a native build of the transform binary, due to bugs such as http://crbug.com/853685 and golang/go#27462, but serves as a starting point for further investigation. There have been a few optimizations already: - Keeping one long-lived process open to amortize the bootstrapping cost across requests. - Batching the "requests" to the wasm code via Promise.all. (This can be seen by adding a log statement just before the call to exports.run in wasm_exec.js.) Another potential problem to investigate the cost of is the lack of cross-heap GC.
This is not nearly as efficient as a native build of the transform binary, due to bugs such as http://crbug.com/853685 and golang/go#27462, but serves as a starting point for further investigation. There have been a few optimizations already: - Keeping one long-lived process open to amortize the bootstrapping cost across requests. - Batching the "requests" to the wasm code via Promise.all. (This can be seen by adding a log statement just before the call to exports.run in wasm_exec.js.) Another potential problem to investigate the cost of is the lack of cross-heap GC.
I also ran into this problem. My Go/WebAssembly app may be helpful for analysis or testing bug fixes in the wasm compiler: https://github.com/Yaoir/VideoPoker-Go-WebAssembly I tried the wams tool, and found it seemed to alter reliability, but if reliability increased in one browser, it decreased or entirely broke the app in another browser or on another device. Overall, nothing was solved. I worked with the JavaScript glue code that's in the HTML file to load sequentially rather than using the streaming JavaScript calls. I still got "out of memory" errors. I also put console.log() statements between calls to fetch, compile, and load to see where things went wrong. I did not find any solutions, but learned that the "out of memory" error occurs during the linking phase of the fetch/compile/load sequence. I noticed that if the app isn't entirely broken on a combination of browser and device, it sometimes it can be made to work by clearing the browser cache, restarting the browser app, and loading the WebAssembly app fresh, into a browser that has not loaded any other pages already. But reloading the page one or more times may bring up the error, and reloading after getting an error may actually work! For a while, I had Firefox for Android running the app successfully every other time the page was reloaded. |
I hacked on the runtime library to reduce the initial allocation to ~80MB: master...twifkak:small A couple of notes:
Update: It seems this is bad for processes that create a lot of flyweight objects. |
It works. Thank you! @twifkak |
I updated my fork to implement a free list, so that Go can reclaim freed memory in wasm. Using this, combined with Update: With |
It works! Thank you so much @twifkak. I'm writing article/opinion/tutorial where my goal is to create a simple game that can be run on mobile because I need touch interaction. You saved me so much time! ❤️ I'll share the publication once its done! |
Hi @olso! IME that error happens when you use the wasm_exec.js from Go 1.11. Grab a copy from the Go 1.12 release. (Tip will probably work too.) Thanks for sharing! I look forward to the article.
|
Hi all, I would love to clean up my fork so it could be merged into golang proper and this bug fixed. The one thing preventing me from doing so is that it depends on Can anybody help?
@neelance Any ideas what I'm doing wrong? Or who to contact for help? |
I think this is no "actual" race in the current Wasm implementation -- it is single threaded, no preemption, and atomic operations are just plain load/stores. I don't think the race detector could help anything.
I guess you mean |
@cherrymui Thanks for the response! Yes, I meant to say Please take a look at the fork for races. It definitely has non-atomic behavior. I was assuming that there will never be two instances of |
Oops, I realize I didn't post the errors I'm seeing. First:
Second:
|
As the program is single threaded, there wouldn't be two things running at same time. Or you mean |
Here is the article - https://medium.com/@martinolsansky/webassembly-with-golang-is-fun-b243c0e34f02 And my Thank you again! 😻 |
Hi all! I looked into the bug @twifkak had encountered, and it looked like a race condition between calls to sysReserve and sysFree (this occurs when gc and malloc race, I believe). I implemented mutexes (similar to mem_plan9.go) to prevent this race condition, and it seems to work correctly. I'd love for other folks to give this branch a try, though, and let @twifkak or me know if they've run into problems: https://github.com/golang/go/compare/master...gabbifish:gabbi-small?expand=1#diff-7e39049a2de75c1412aac58accc6a92f |
The branch code of @twifkak works well. It's just that the value of "writeUleb128'(ctxt. Out, 1024*1)" to initialization memory is still higher on my phone, which leads to slow loading. But this Page setting is too low and can easily overflow when running on my browser (Firefox on HTC 10, Safari on iPhone 6 plus). This needs to be set according to the actual needs of the project memory to achieve better results. I actually used @termonio's wams tool to set up wasm's runtime memory. The combination of the two works very well. Here's the shell of my building project.
And with @twifkak modifications, go-wasm really works well on my Andoird and iPhone. Now I have other problem is whether the binary compiled by go-wasm is somewhat large. I can only use syscall/js to call the api of js, instead of using the standard library of go to keep the binary size of 4M. When I imported go's standard libraries (strings, json, base64, http), the binary package was almost 7~8M. This size reloaded twice on the web on my iPhone 6 plus it reported wasm compiler error of memory overflow. Maybe the wasm implemented by mobile browser is too weak. |
I'm seeing OOM on win7 latest firefox, and also android7 latest firefox, so actually it only works on my macos 10.12.4 firefox63 currently :( |
Using some of the optimization flags mentioned here, I got my .wasm file down to ~2.6MB but still seeing OOM errors on everything but my mac :( I haven't tried the fork mentioned above (I'm very new to Go) but I did try using 'bytecoder' with some Java for comparison... That generates a 15KB file (also interacting with Javascript / canvas 2D) and runs great on Android g-tab2, and even an old Nexus 5 Android 6 device! and obviously the load times are vastly improved. Although still no success on my iOS devices, but that might be because I keep them on older iOS versions for development testing. I know that wasm support is still experimental, but could this issue possibly be upgraded from 'Performance' ? Since currently this makes Go WASM unusable in many situations, and this probably needs fixing before WASI hits mainstream. Thanks. |
Change https://golang.org/cl/170950 mentions this issue: |
- go 1.12 optimizes memory allocation for wasm - see golang/go#27462. This was causing the demo to OOM on memory restricted devices (e.g. phones). - js namespace changed so we need to adapt to that
- go 1.12 optimizes memory allocation for wasm - see golang/go#27462. This was causing the demo to OOM on memory restricted devices (e.g. phones). - js namespace changed so we need to adapt to that
- go 1.12 optimizes memory allocation for wasm - see golang/go#27462. This was causing the demo to OOM on memory restricted devices (e.g. phones). - js namespace changed so we need to adapt to that
Seems like the situation is better at first loading but out of memory still occurs when reloading a page that uses go wasm on mobile. Using safari on iPhone. Edit: |
Yes, it hangs up with a few more refreshes on the safari of the iphone, and you need to reopen the page at this time. I debugged on PC, and other browsers did not release memory in time after refreshing, so did WASM compiled by rust and C. I think this has nothing to do with the compiler language, but with the WASM performance of the browser implementation. |
I am very excited that Go ships now with Webassembly support. I ran wasm code generated by Go 1.11 on Chrome and Firefox on desktops (MacOS and Linux) and on Chrome, Firefox and Safari on iOS devices. Running Go generated wasm code on Android devices failed though.
Minimal example
GOOS=js GOARCH=wasm go build -o test.wasm wasm.go
index.html
wasm_exec.js
fromgo/misc/wasm
mime.types
Expected behavior
Actual behavior
The text was updated successfully, but these errors were encountered: