- Notifications
You must be signed in to change notification settings - Fork396
Experiment: AvoidJSArrayConstr
for Varargs to optimize the Wasm backend#5148
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Closed
Uh oh!
There was an error while loading.Please reload this page.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
… BackendCurrently in Scala.js, varargs call like `List(1, 2, 3)`, it is translated into the IR form `js.WrappedArray(JSArrayConstr(...))`. That requires JS interop for constructing the array and accessing its elements.Since Wasm-to-JS calls are expensive, this is undesirable for performance.This commit experiments avoiding `JSArrayConstr` for varargs.Instead, varargs are transformed into something like `new WrappedArray$ofInt(ArrayValue(1, 2, 3))` (or `new ArraySeq$ofInt(...)` on 2.13) to explore potential Wasm-specific optimizations.Note1: While reducing JS interop can improve performance on the Wasm backend, the same does not apply the JS backend.We'd need to re-optimize back to `JSArrayConstr`-based code during the Optimizer for the JS backend.Note 2: How about `WrappedArray.make` instead of directly instantiating specialized `WrappedArray`?I found that runtime type checks in `make` appear to be very slow, and in some micro-benchmarks, using `make` performed slightly worse than the original `JSArrayConstr`-based code.---Unfortunately, the performance improvements were negligible.For example, in the following code:```scaladef main(args: Array[String]): Unit = { val startTime = System.nanoTime() val xs = Seq(1, 2, ..., 20) xs.foreach(x => assert(x > 0)) val endTime = System.nanoTime() println(s"elapsed: ${endTime - startTime} ns")}```Both versions (with and without `JSArrayConstr`) reported similar timings of ~540000–580000 ns.Benchmarks run using [`sjrd/scalajs-benchmarks/wasm`](https://github.com/sjrd/scalajs-benchmarks/tree/wasm) also did not show any significant performance differences.| Benchmark | before | after | Ratio (after / before) ||-------------|--------------|--------------|----------------------|| sha512 | 12403.95816 | 12737.42497 | 1.0269 || sha512int | 12259.02363 | 13313.69655 | 1.0860 || queens | 2.954778067 | 2.920396237 | 0.9873 || list | 60.56316878 | 60.52163829 | 0.9993 || richards | 87.49714448 | 87.77807725 | 1.0032 || cd | 32866.35461 | 31672.2486 | 0.9637 || gcbench | 104672.8678 | 121351.2553 | 1.1588 || tracerFloat | 870.5680015 | 876.4962162 | 1.0068 || tracer | 784.3968099 | 783.2297365 | 0.9985 || sudoku | 3634.165046 | 3609.813857 | 0.9933 || nbody | 23722.03084 | 24192.39211 | 1.0198 || permute | 262.9023071 | 265.949228 | 1.0116 || deltaBlue | 525.4683864 | 511.8722724 | 0.9742 || kmeans | 206339.5187 | 202615.0022 | 0.9820 || brainfuck | 2352.518883 | 2357.064959 | 1.0019 || json | 288.1723513 | 280.1001847 | 0.9720 || bounce | 33.12443674 | 33.01821262 | 0.9978 |There may still be room for further optimization in the non-`JSArrayConstr` implementation.
JSArrayConstr
for Varargs to optimize the Wasm backendJSArrayConstr
for Varargs to optimize the Wasm backendJSArrayConstr
for Varargs to optimize the Wasm backendJSArrayConstr
for Varargs to optimize the Wasm backendSign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading.Please reload this page.
This is more like an experiment report for discuss based on the results of this change.
Currently in Scala.js, varargs call like
List(1, 2, 3)
, it is translated into the IR formjs.WrappedArray(JSArrayConstr(...))
. That requires JS interop for constructing the array and accessing its elements. Since Wasm-to-JS calls are expensive, this is undesirable for performance.This commit experiments avoiding
JSArrayConstr
for varargs. Instead, varargs are transformed into something likenew WrappedArray$ofInt(ArrayValue(1, 2, 3))
(ornew ArraySeq$ofInt(...)
on 2.13) to explore potential Wasm-specific optimizations.Note1: While reducing JS interop can improve performance on the Wasm backend, the same does not apply the JS backend. We'd need to re-optimize back to
JSArrayConstr
-based code during the Optimizer for the JS backend.Note 2: How about
WrappedArray.make
instead of directly instantiating specializedWrappedArray
? I found that runtime type checks inmake
appear to be very slow, and in some micro-benchmarks, usingmake
performed slightly worse than the originalJSArrayConstr
-based code.Unfortunately, the performance improvements were negligible.
For example, in the following code:
Both versions (with and without
JSArrayConstr
) reported similar timings of ~540000–580000 ns.Benchmarks run using
sjrd/scalajs-benchmarks/wasm
also did not show any significant performance differences.(It might be because there's not so much varargs in the benchmark)
There may still be room for further optimization in the non-
JSArrayConstr
implementation.