Can Lua be faster than JavaScript in a browser?

I have been working on getting Lua to run in a browser and was asked how much slower it is comparing to JavaScript. I put together two pages -- one for Lua and one for JavaScript -- to run the equivalent code to measure its performance and got a surprising result: Lua reliably outperformed JavaScript with the following code:

Lua

local canvas = document:getElementById("canvas")
canvas.width = canvas.width -- clear the canvas
local ctx = canvas:getContext("2d")

ctx.fillStyle = "rgb(200,0,0)"
ctx:fillRect(130, 130, 50, 50)
ctx.fillStyle = "rgba(0, 0, 200, 0.1)"

for i = 1, 100 do
  ctx:fillRect(math.random(0, 300), math.random(0, 300), 50, 50)
end

JavaScript

var canvas = document.getElementById("canvas");  
canvas.width = canvas.width
var ctx = canvas.getContext("2d");
  
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(130, 130, 50, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.1)";

for (i = 1; i<=100; i++) {
  ctx.fillRect(Math.random()*300, Math.random()*300, 50, 50);
}

This clearly wasn't something I expected as the Lua code compiles down to JavaScript, so it can be running with the same speed (in an ideal case), but clearly should not be running faster (I've averaged results over several runs, but you can see for yourself).

Even more puzzling was the fact that each individual part -- running a loop with ctx.fillRect(0, 0, 50, 50) or running the same loop with Math.random() call -- ran faster with the JavaScript code, but together they ran slower. It took a bit of experimenting, but in the end the mystery was solved: the difference was in Math.random()*300 in JavaScript versus math.random(0, 300) in Lua.

As some of you might have noticed already, math.random(0, 300) call in Lua returns an integer value, whereas Math.random()*300 call in JavaScript returns a float value. I was reading about canvas performance just a day earlier and there was a recommendation to avoid using floating point coordinates as it turns on anti-aliasing, which significantly slows the drawing. That was it; when I added Math.round() call the performance returned to normal.

So, while I was at it, I decided to compare performance of Lua vs. JavaScript on some other calls. The code above was running 50-80% slower in Lua than in JavaScript (with 1000 iterations). A simple loop with one function call -- for (i = 1; i<=10000; i++) { Math.abs(-10); } -- is 3-6 times faster in JavaScript. This is primarily because of table lookup that Lua version has to do. When I changed for i = 1, 10000 do math.abs(-10) end to abs = math.abs; for i = 1, 10000 do abs(-10) end it became only 2-3 times slower than the JavaScript code. Attribute assignment foo.bar had a similar performance: it was 3-6 times slower because of the table lookup and associated function calls in the Lua version.

Overall, I have been very satisfied with the difference in performance and will share the results when I get more complex code running.

You should get a copy of my slick ZeroBrane Studio IDE and follow me on twitter here.

Leave a comment

what will you say?
(required)
(required)

About

I am Paul Kulchenko.
I live in Kirkland, WA with my wife and three kids.
I do consulting as a software developer.
I study robotics and artificial intelligence.
I write books and open-source software.
I teach introductory computer science.
I develop a slick Lua IDE and debugger.

Recommended

Close