Why is Lua so slow?

It’s checked just every Friday, so will have to wait for an week :rage:

1 Like

Like @buildthomas said, this is primarily because Lua isn’t JIT compiled. You can compare with LuaJIT as a benchmark, though that might be harder to do because it doesn’t natively have a time function that’s precise to milliseconds like Roblox does and as far as I know there’s no pre-built executable for it on Windows.

The new Lua VM is quite a bit faster than vanilla Lua, but it also isn’t JIT compiled, so Javascript will probably still be faster. The reason the new VM isn’t JIT is because certain platforms don’t allow it.

As an aside, the name of the language is Lua, not LUA. It’s not an acronym – simply Portugese for Moon.

7 Likes

Running this benchmark in the chrome console I get 11.2 ms in javascript, and running in LuaJIT in ZeroBrane, I get 374ms when I run 100 times as many iterations. luajit runs about 30x as fast as javascript. In Roblox Studio the 16m iterations takes 762ms in the new VM, and 7 seconds when I put it in a script and press play in the old VM. javascript runs about 68x as fast as the new Lua VM.

2 Likes

For fair comparison try using node —jitless command line for JS (and -joff for LuaJit)

4 Likes

A smart compiler won’t even run the benchmark because it has no side effects? The Lua simplifier I made would just delete the for loop.

1 Like

Yeah I wanted to note this as well - thanks! I’m not sure what the JS semantics here are, in Lua getfenv prevents us from realizing that math.sqrt / math.pow can be evaluated as constants, and the loop body can be dropped. I’d suggest rewriting the benchmark so that on each loop iteration a unique value is computed and then is used (e.g. sum = sum + smth) outside of the loop.

3 Likes

JavaScript is used in many more places than Lua. The general rule is that the average JS implementation will be much faster than most Lua implementations due to the sheer number of stakeholders. All major browsers have VERY fast JS implementations (all chromium based browsers are using the V8 JS engine, SpiderMonkey for Firefox, Rhino Java’s JavaScript interpreter, JavaScriptCore for Safari, Chakra for non-chromium Edge). There are MANY implementations for JS which have tested various ideas to improve performance for different types of applications and environments.

Regardless of the immense funding and effort put into JS implementations, there is an exception to this rule. Mike Pall is an absolute tracing JIT compiler genius and LuaJIT still out performs every other scripting language and even in some trivial cases outperforms C (see ycombinator for one reason why this is, although similar cases exist in which JIT can outperform AOT compilation).

Unfortunately, Roblox has chosen not to use LuaJIT. The reasons why are explained by @zeuxcg in a gist. To summarize, there are security, flexibility, maintainability, and use case issues.

So, the answer to your question: Why is Lua so slow? Because Roblox development has limited resources and their hands are tied by other issues than sheer performance. There are technical hurdles and LuaJIT shows they can be overcome.

5 Likes

Worth noting is that we (well, I) don’t believe in tracing JITs. NYI and trace aborts aren’t for the faint of heart. When (if?) we implement a JIT it will not use tracing.

I agree with you on this, stack traces are very confusing. I was extremely confused by a lot of the error stacks I was getting when I learned java.

There are many reasons. I cannot list all of them.
Before you read my post. I suggest you look up these. (I’m quite bad with explanations, and you might be even more confused)

  • CPU Instruction Set
  • Interpreted Language

CPUs run on things called on Instructions. A program made of CPU instructions that can be readily be run by the CPU is called ‘Native’.
Program languages such as C++ are compiled into “native”, thus fast.
One of the obvious is that Lua is made to be an interpreted language.
Lua is quite different. The language is compiled into “Bytecode”, which is like CPU’s instructions, but CPU’s cannot run this from the get-go. It has to be translated into CPU Instructions first, then run.
There are bytecodes either run on “during runtime”, or an intermediate bytecode that is compiled into CPU instructions before the application runs(Prime example are C#,VB .NET, F#'s CLR).

The later is fastest, but Lua uses the first one.

There’s also anther reason that ROBLOX’s lua is slow. Your Javascript example uses a JIT(Which others have pointed out.) A JIT is like turning the bytecode into CPU instructions(which is fast) while the program is running. JIT makes interpreted languages such as Lua and Javascript to be fast.
ROBLOX does not. (A teaser in their new lua VM video says that JIT is being considered.)

There are other reasons, such as the design of Lua itself. Such as having no arrays. Tables are associative arrays. Integers and floating point numbers are 64 bit, etc (wait does ROBLOX use 64 bit integers or 32???)

Lua is just; simple to embed to other programs, ‘Portable’(Or interpreted languages in general), which means the same code can run on mobile and PC, etc. That’s why ROBLOX uses it

This is true. I remember reading that it was chosen as it is semantically closer to English, if rather than

if (num > 2){
   console.log('Ahhhh')
}

we have

if num > 2 then 
   print('ahhhh')
end

This makes it easier to pick up and code is more intuitive to read

1 Like

Personally I think roblox lua is one of the easiest programming languages to learn for an English speaker. It’s about as simplified as you can get without losing practicality for none OOP programming. Most notably the total lack of any limitations on tables makes a lot of things easier.

1 Like

Correct! Lua was written to be picked up by people who didn’t know much programming, if any, as part of a deal with a company in Brazil. As a result, it’s got a simplistic syntax and very simple rules (this is why there aren’t any pointers and up until Lua 5.3 there was only one type of number).

1 Like

Certain data types are implicitly assigned by reference though, so pointers do exist in Lua from a practical point-of-view. If Roblox’s language were a statically typed one, making a deep copy during assignment would be possible and more intuitive for beginners.

Dare I say that, instantiation time notwithstanding, it might also be more performant as well, as you’d probably have fewer cache misses when iterating over better-formed data that doesn’t chop up the CPU stack.

Speaking of structuring data to avoid cache misses (which I would consider relevant to OP), does anyone know if implementing ECS (Entity Component System) instead of OOP (Object Oriented Programming) in Roblox brings a measurable performance benefit? It could be possible since the Roblox engine is at least partially built in C++. That’s the direction Unity is moving, and once they got the compiler to behave, the increased performance is now massive.