8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
JSArrayConstr
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
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 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.
List(1, 2, 3)
js.WrappedArray(JSArrayConstr(...))
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.
new WrappedArray$ofInt(ArrayValue(1, 2, 3))
new ArraySeq$ofInt(...)
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.
WrappedArray.make
WrappedArray
make
Unfortunately, the performance improvements were negligible.
For example, in the following code:
def 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 also did not show any significant performance differences.
sjrd/scalajs-benchmarks/wasm
(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.
Sorry, something went wrong.
Experiment: Avoiding JSArrayConstr for Varargs to Optimize the Wasm…
a2c0441
… Backend Currently 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: ```scala def 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.
Successfully merging this pull request may close these issues.