I have two almost identical pieces of code. One is running Scala on JVM, second is running Javascript. Both perform lots of atan and asin calls (this is extracted from the real application performing quaternion to Euler angles conversion). The Javascript implementations runs an order of magnitude faster.
The JS version takes about 1 000 ms on my machine. The Scala code takes about 10 000 ms when running on JVM, but when compiled using Scala.js it is again running for about 1000 ms (see ScalaFiddle).
What is the reason for such huge performance difference? What changes would I have to implement for the JVM code run this fast?
var size = 100000;
var input = new Array(size);
function fromQuaternion(a, b, c) {
return Math.asin(a) + Math.atan2(a, b) + Math.atan2(b, c);
}
function convert() {
var sum = 0;
for (var i = 0; i < size * 3; i += 3) {
sum += fromQuaternion(input[i], input[i+1], input[i+2]);
}
return sum;
}
for (var i = 0; i < size * 3; i += 3) {
input[i + 0] = Math.random();
input[i + 1] = Math.random();
input[i + 2] = Math.random();
}
var total = 0;
for (var i = 0; i < 10; i++) total += convert();
var start = Date.now();
for (var i = 0; i < 100; i++) total += convert();
var end = Date.now();
console.log("Duration " + (end - start));
console.log("Result " + total);
document.write("Duration " + (end - start));
val input = Array.fill(100000) {
val x = util.Random.nextDouble()
val y = util.Random.nextDouble()
val z = util.Random.nextDouble()
(x, y, z)
}
def fromQuaternion(a: Double, b: Double, c: Double): Double = {
Math.asin(a) + Math.atan2(a, b) + Math.atan2(b, c)
}
def convert = {
input.foldLeft(0.0) { (sum, q) =>
sum + fromQuaternion(q._1, q._2, q._3)
}
}
// warmup
var sum = 0.0
for (_ <- 0 until 10) sum += convert
val start = System.currentTimeMillis()
for (_ <- 0 until 100) sum += convert
val end = System.currentTimeMillis()
println(s"Duration ${end - start} ms")
println(f"Sum $sum%f")
When I measure asin and atan2 separately (with fromQuaternion containing only a single asin or a single atan2), I get following results:
- JS
atan2: 453 ms JS
asin230 msJava Math
atan21000 msJava Math
asin3800 msApache FastMath
atan21020 ms- Apache FastMath
asin1400 ms
I have tested Apache FastMath as well. While its asin is a bit faster, its performance is still way behind the one seen in the browser.
My measurements are done with Oracle Java 8 SDK 1.8.0.161 (JVM) and Chrome 78.0.3904.108 (Browser), both running on x64 Windows 10 running Intel Core i7 @ 3.2 GHz with 12 GB RAM.