-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Speed up passing ASCII-only strings to WASM #1470
Conversation
Thanks for this! I was wondering though if we could perhaps be more strict about changes here to head off regressions like cc @fitzgen |
I think this would make sense, yeah, although for now I've been focusing on finishing serde-wasm-bindgen (which has own benchmarks presented above and relies on optimisations). So yes, I think it's a great idea given the risks, but I'm not 100% sure when I'll get around to adding all these generic tests and benchmarks. How about leaving this open for now and maybe someone else would want to add these string tests in the meanwhile? |
Although wait, in terms of tests - I think you said we have coverage now that newer Firefox runs on Azure? |
We should run tests in both Node.js and Firefox on Azure right now, and I think our test suite on strings is pretty light so it'd be nice to test just a wide variety of strings which mix non-ascii, lengths, etc. That'd be good for building confidence at least! The numbers here sound great but I'd just want to make sure they were reproducible as well as ideally having helpful benchmarks to run in the future. We probably can't have a super nice framework of benchmarks just yet, but having at least the start I think would be a good way to begin. |
Regarding benchmarks: I know you also had a micro benchmark for various into/from wasm ABI stuff, Alex. I think it would be useful to collect these in a single place where anyone can run them and we make sure that they build in our CI. How about a |
Ah that's right, I did! After some digging I also apparently even published the benchmark. I actually think it'd be pretty cool if we published the benchmark for our own internal usage from CI, and that way we could always redirect folks to take a look and compare numbers themselves. I can try to whip something up and make a PR |
@alexcrichton Did you have any time / luck with benchmarks so far? |
Sorry no I haven't had enough time to work through this and try to get something set up. In the meantime could you share how you were benchmarking this? Additionally have you had a chance to write some more tests for ascii/unicode/etc? |
Alright, I've created isolated benchmark set for passing strings into WASM here, instructions included in README: https://github.com/RReverser/wasm-bindgen-string-benches I've ran them myself in latest Firefox and Chrome to provide some reference numbers. As expected, because these are isolated string benchmarks and not whole-app improvements like above, the difference is even bigger, especially for small ASCII strings, which are particularly common and where C++ overhead is particularly noticeable.
|
As for more tests - no, I didn't have time to work on that. |
9798cc5
to
46ccb35
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the benchmark! I can indeed reproduce some similar performance gains on Firefox myself.
I think we'll want to have more tests for ascii/unicode/etc before this lands to ensure it doesn't accidentally regress anything and we don't accidentally regress it in the future.
ptr = wasm.__wbindgen_realloc(ptr, size, size += arg.length * 3); | ||
const view = getUint8Memory().subarray(ptr + offset, ptr + size); | ||
offset += cachedTextEncoder.encodeInto(arg, view).written; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could a debug assert of some form be included after this to ensure that it wrote everything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't exactly use debug_assert
in the JS code, but I guess I could add something if debug_assertions
is on...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a --debug
flag to wasm-bindgen
itself which can control whether the assertion is emitted or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not sure what to check here. I mean, I'm passing all that's left of arg
to encodeInto
, so it has to be written fully - what condition would I check to prove it?
Some speed up numbers from my string-heavy WASM benchmarks: - Firefox + encodeInto: +45% - Chrome + encodeInto: +80% - Firefox + encode: +29% - Chrome + encode: +62% Note that this helps specifically with case of lots of small ASCII strings, in case of large strings there is no measurable difference in either direction.
46ccb35
to
0c681ee
Compare
Hmm, I just found out that I left few mistakes in the benchmark code - did you manage to run the same benchmarks when you wrote that? Anyway, should be fixed now. |
@@ -1499,12 +1499,19 @@ impl<'a> Context<'a> { | |||
arg = arg.slice(offset); | |||
ptr = wasm.__wbindgen_realloc(ptr, size, size = offset + arg.length * 3); | |||
const view = getUint8Memory().subarray(ptr + offset, ptr + size); | |||
const ret = cachedTextEncoder.encodeInto(arg, view); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexcrichton I see you already merged it, but this change... doesn't seem right. Why is it encoding same view twice now?
I asked that question but didn't get any response. @alexcrichton can we revert this change (given the bug above) and land it with a proper fix and review instead please? |
This was a regression introduced in the last commit of rustwasm#1470, which might make Unicode strings 2x slower to pass.
Yes that was a mistake in my merge. I ran the benchmarks locally and had them fixed so they ran correctly and showed improvements. Why do you want to revert this and back it out? |
@alexcrichton Mainly due to 2x regression for Unicode strings, but in the meanwhile I've submitted a PR to fix just that, and I see you already merged it. I don't want to cause problems, but I think that it would be helpful to ask one more pair of eyes to look at the new changes before merging to make sure there are no similar regressions in the future. Also hoped to clean up the code a bit further - to avoid duplicate JS in the output - when I have time to get back to this, but I guess I can leave that for a separate PR. Either way, thanks for merging both PRs and getting back to me! |
Ok just wanted to make sure. It would also be helpful to write requested tests ahead of time for PRs! This isn't a massive project where some breakage on master destroy's everyone's workflow. I'm simply extremely busy yesterday and today and it took a bit to merge a fix. No sweat if things are broken temporarily. |
Fair enough, maybe I'm stressing over breakages more than I should. |
Some speed up numbers from my string-heavy WASM benchmarks mentioned in the previous PRs:
Note that this helps specifically with case of lots of small ASCII strings, in case of large strings there is no measurable difference in either direction.
Related issue: #1313
r? @alexcrichton