Live data from Hacker News

Building the fastest Lua interpreter automatically

sillycross.github.io

91–100 of 114 posts

Re: Building the fastest Lua interpreter automatically

#92
It is my understanding that benchmarks are run against LuaJIT interpreter (-j off), so here are some JIT numbers for reference, using the array3d.lua benchmark [1]

  time luajit -j off array3d.lua 
  
  real 0m1,968s
  user 0m1,915s
  sys 0m0,052s
  
  time luajit -j on array3d.lua 
  
  real 0m0,128s
  user 0m0,068s
  sys 0m0,060s

[1] https://github.com/luajit-remake/luajit-remake/blob/master/l...

Re: Building the fastest Lua interpreter automatically

#93

Earlier quoted context omitted.

> More recently I have been experimenting with a new calling convention that uses no callee-saved registers to work around this, but the results so far are inconclusive. The new calling convention would use all registers for arguments, but allocate registers in the opposite order of normal functions, to reduce the chance of overlap. I have been calling this calling convention "reverse_cc". As explained in the article…

I tried exposing the "cc 10" and "cc 11" calling conventions to Clang, but was unsuccessful. With "cc 10" I got crashes at runtime I could not explain. With "cc 11" I got a compile-time error: > fatal error: error in backend: Can't generate HiPE prologue without runtime parameters If "cc 10" would work from Clang I'd be happy to use that. Though I think reverse_cc could potentially still offer benefits by ordering ar…

If you didn't already, I'd recommend compiling llvm/clang in debug or release+assert mode when working on it. The codebase is quite heavy in debug-only assertions even for relatively trivial things (like missing implementation of some case, some combination of arguments being invalid, ...) which means that it's pretty easy to get into weird crashes down the line with assertions disabled.

Re: Building the fastest Lua interpreter automatically

#94

I work on a game, that mostly uses lua as logic code, saddling on a c/c++ engine. One of the engine developers implemented lua jit years ago and found that for the actual performance, the interpreter/jit was neglibable, the most expensive thing being the actual switch between luacode and c-code, which is with a large API a constant ugly background performance loss. The lua code by itself did not ran long enough to ac…

I believe LuaJIT also has a C FFI that should allow for faster function calls compared to the native Lua API.

Re: Building the fastest Lua interpreter automatically

#95

I work on a game, that mostly uses lua as logic code, saddling on a c/c++ engine. One of the engine developers implemented lua jit years ago and found that for the actual performance, the interpreter/jit was neglibable, the most expensive thing being the actual switch between luacode and c-code, which is with a large API a constant ugly background performance loss. The lua code by itself did not ran long enough to ac…

Sorry if my comment is naive or ignorant, but have you tried using LuaJIT FFI instead of traditional int (lua_State *) API? Or is that with FFI already?

I thought FFI promised almost seamless Lua->C calls. And can even pass Lua functions into C with native signatures (but this bridge is still claimed expensive).

Re: Building the fastest Lua interpreter automatically

#96
post #86

It would be interesting to see 1-1 comparison with LuaJIT interpreter _without corresponding runtime changes_. That would given a meaningful baseline for how much you potentially loose/gain using this approach. Current measurement presents comparison of two wildly different implementation strategies: LuaJIT Remake uses IC and hidden classes while LuaJIT proper does not. It's a well known fact that ICs+hidden classes…

I agree with your point, but I want to point out that Deegen also provided APIs to hide all the details of inline caching. The bytecode only specifies the body lambda and the effect lambdas, and Deegen lowers it to an efficient implementation automatically, including exotic optimizations that fuses the cached IC effect into the opcode so one indirect branch can be avoided.

If LuaJIT interpreter were to employ IC, it would have to undergo a major rewrite (due to its assembly nature) to have the equally efficient code as LJR (that we generate automatically). This is one advantage of our meta-compiler approach.

Finally, although no experiment is made, my subjective opinion is already in the article:

> LuaJIT’s hand-written assembly interpreter is highly optimized already. Our interpreter generated by Deegen is also highly optimized, and in many cases, slightly better-optimized than LuaJIT. However, the gain from those low-level optimizations are simply not enough to beat LuaJIT by a significant margin, especially on a modern CPU with very good instruction-level parallelism, where having a few more instructions, a few longer instructions, or even a few more L1-hitting loads have negligible impact on performance. The support of inline caching is one of the most important high-level optimizations we employed that contributes to our performance advantage over LuaJIT.

That is, if you compare the assembly between LJR and LuaJIT interpreter, I believe LJR's assembly is slightly better (though I would anticipate only marginal performance difference). But that's also because we employed a different boxing scheme (again...). If you force LJR to use LuaJIT's boxing scheme, I guess the assembly code would also be similar since LJR's hand-written assembly is already optimal or at least very close to optimal.

Re: Building the fastest Lua interpreter automatically

#97
post #13
post #9

>More importantly, it is the world’s fastest Lua interpreter to date, outperforming LuaJIT’s interpreter by 28% and the official Lua interpreter by 171% on average on a variety of benchmarks Wait what the hell

Faster than the LuaJIT's interpreter . People who focus on JIT often focus on the JIT and not the interpreter. Which is a shame because if you make the uncommon paths cheaper then you can tune your code for the hot paths a bit more aggressively. You get fewer situations where you are sacrificing Best Case for Average Case performance.

LuaJIT actually has a really fast and well-optimized interpreter though, and the article acknowledges this. The reason this interpreter has such great performance isn't directly because they automatically generate the assembly. The majority of the performance gain is because they implemented inline caching, an optimization that LuaJIT doesn't have:

> A lot of LJR’s speedup over LuaJIT interpreter comes from our support of inline caching. We have rewritten the Lua runtime from scratch. In LJR, table objects are not stored as a plain hash table with an array part. Instead, our table implementation employed hidden classes, using a design mostly mirroring the hidden class design in JavaScriptCore. > > Hidden class allows efficient inline caching, a technique that drastically speeds up table operations.

Re: Building the fastest Lua interpreter automatically

#99

I work on a game, that mostly uses lua as logic code, saddling on a c/c++ engine. One of the engine developers implemented lua jit years ago and found that for the actual performance, the interpreter/jit was neglibable, the most expensive thing being the actual switch between luacode and c-code, which is with a large API a constant ugly background performance loss. The lua code by itself did not ran long enough to ac…

I'm not really answering your question here but answering more in general regarding calls to functions bound from the lua c API.

There is trace stiching meant to help with code that does a lot of c calls. This was disabled in 2015 April 28 due to it being flawed but enabled again August 29 later that year with a working design.

Otherwise the recommendations are to reduce and maybe cache values on the lua side of things if you cannot use ffi.

Otherwise as mentioned in other comments if you can use ffi, use it. The performance benefit is significant.

The downside is that the ffi API is unsafe so in the context of a game development you'd have to be careful about third party scripts from modding or similar.

Another downside is if you cannot use jit (like on iOS) the performance hit can be worse than using the lua c api

Re: Building the fastest Lua interpreter automatically

#100

There's some prior art on DSLs for efficient interpreters, like Anton Ertl's vmgen. https://www.complang.tuwien.ac.at/anton/vmgen/

ah, I remembered this but could not find it again, thanks.

Many, many years ago there was even someone trying to write a ruby VM with it[1]. Wow, I'm old.

[1] https://savannah.nongnu.org/projects/carbone

Post reply on HN