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
syscall/js: remove Wrapper type to avoid extreme allocations and improve performance #44006
Comments
I support this proposal. The Wrapper type was only added for convenience and performance trumps convenience for such a low-level package as The author of the Wrapper type also supports the removal: #39740 (comment) @rsc Please consider this proposal for the proposal process. |
The existence of the Wrapper interface causes unavoidable heap allocations in syscall/js.ValueOf. See the linked issue for a full explanation. Fixes golang#44006.
I have a program which animates an LED matrix, and transfers frames @ 60fps, to a JS IDE for rendering. Receiving binary frames over a WebSocket, the IDE starts to stutter around 9000 - 10,000 pixels. Receiving binary frames from embedded Go to JS, the server both rendering the animation and copying the bytes to a JS buffer within the context of a requestAnimationFrame, the IDE can handle 10,000 pixels like butter.. without breaking a sweat! Reading this proposal, and hearing of performance improvements in 1.17, gives hope that even better performance is possible! Exciting times for the web platform and Go both. |
Any chance to get this into the proposal process this cycle? 🙂 |
Do we have any numbers about how often Wrapper is used today? Did I miss them above? |
This proposal has been added to the active column of the proposals project |
You didn't miss anything; the original proposal didn't make an effort to enumerate usage of Anyway, searching https://github.com/search?q=%22js.Wrapper%22+language%3AGo&type=Code returns 375 code results.
Here is a (potentially incomplete) list of projects that would (at least temporarily) break (they reference the
It would be interesting to get the perspectives of the maintainers of these projects. Finally, since it's been 8 months since this proposal began, I have more context on my particular use cases: Development of the Go version of my online game has stopped, and development on a Rust port has started (but stalled). I also started developing a new online Game based on Rust wasm. Rust seems to be a better fit for performance critical wasm. While I would not personally benefit from this proposal any more, I think it would help close the Go<->Rust wasm gap by eliminating the major performance cliff. |
https://github.com/search?q=%22syscall%2Fjs%22+%22js.Wrapper%22+language%3AGo&type=Code I searched this with As this is an interface, we should find the code that defines a method |
It sounds like we need more data about the potential impact here. |
I would still feel better with more data, but because this is in syscall and in wasm, which is not heavily used, and because literally no one has objected to doing this, it seems okay to do it and see if anyone comes forward. |
Based on the discussion above, this proposal seems like a likely accept. |
This is not really about removing Wrapper type, which I have no objection. But I don't really understand the escaping part. What exactly escapes, and can be avoided if Wrapper is removed? And if a value is passed to JavaScript how do we know it is safe to not escape? I.e. be sure that JavaScript doesn't hold the value or use it in some asynchronous way? Thanks. |
From Go's perspective, the parameter
As outlined in my original proposal, the
It is Disclaimer: This is all just my understanding, gathered by optimizing Go and |
Thanks. Yeah, I think it makes sense and is safe for ValueOf not escape the interface data at least in some cases (e.g. numbers). |
No change in consensus, so accepted. 🎉 |
Change https://golang.org/cl/356430 mentions this issue: |
Great! Don't forget to apply the other optimizations (e.g. noescape; none of which are breaking changes; see my patch) so the performance gain will apply 😉 |
Updated the milestone to Go 1.18 since that's the version this proposal was implemented. This change is significant enough to warrant being mentioned in the 1.18 release notes. |
Introduction
It is truly remarkable what can be accomplished by compiling Go to WebAssembly (
wasm
), but virtually all such applications are being held back by the combination of two factors:As the title of this proposal suggests, the performance problems can be solved if the
js.Wrapper
type is removed. Removal of existing features from the standard library should not be taken lightly, but this particular removal is both allowable (syscall/js
is exempt from Go's compatibility promise) and necessary given the data.Why
Wrapper
mattersAt the core of every call to JS,
syscall/js
uses itsValueOf
function to convert Go arguments to their JS equivalents. This conversion is implemented as a switch statement:One of the cases is the
Wrapper
interface. This was intended to allow any type implementing theJSValue
method to be easily passed as an argument to a JS method. However, asJSValue
may consist of an arbitrary pointer receiver, the compiler must assume the worst:This means that the argument to
ValueOf
, which includes any argument passed to any JS function, is guaranteed to escape to the heap.Data
Data is reported as number of heap allocations per unit of work.
[]byte
copy to JSstring
manipulation//go:noescape
makeArgs
slices on stack (See #39740)Wrapper.JSValue()
Wrapper
type*on the order of the number of allocations that happen unrelated to
syscall/js
Data collection method
syscall/js/js.go
: js.go.patchContext
Preliminary discussion of this proposal has has already taken place in #39740. The consensus there was that removing
Wrapper
is the only way to sustainably call JS functions in a performance-critical setting. Given thatsyscall/js
is a low level package, it make sense to prioritize performance over the ease of use afforded byWrapper
.More context on my actual use case
Go
, compiled toWebAssembly
, usesWebGL 2.0
APIs, and is intended to run at 60 frames per second.The text was updated successfully, but these errors were encountered: