Remix.run Logo
Animats 3 days ago

Second Life is switching over from Linden Scripting Language to Luau. It's working out well. The existing system compiled to Mono, and with Mono being deprecated (abandoned?) something new was needed. Amusingly, not only is Luau being supported, the LSL compiler is now targeting the Luau execution engine, and that works. Performance has improved slightly.

Second Life runs on hundreds of thousands of tiny programs, all event driven and running on the servers. Managing that is tricky, since server side resources are limited. Yet it works well, even if user programs are compute-bound. Actually, the biggest problem is that each idle program uses about 1us per frame, which adds up.

ChocolateGod 2 days ago | parent | next [-]

When they had the Luau beta regions up and running I gave it a whirl and it seemed performance was greatly improved over the old Mono system. Clicking "Save" was near instant to execute, great improvement to clicking save and waiting 10 seconds to know whether or not there's an issue in your script.

The only desire I have is if they could adopt FiveM-style helper functions which help wrap coroutines, namely being CreateThread(fn) and Wait(ms) (wrapper around yield inside that "thread") and Await/Promises (seems like someone already made an implementation for Luau? https://github.com/evaera/roblox-lua-promise)

FiveM adopting these makes it easy to make better performing scripts without having to mangle coroutines, which is vital given the Lua VM has to finish its current task before the frame is allowed to render.

https://github.com/citizenfx/fivem/blob/master/data/shared/c...

HaroldCindy 2 days ago | parent [-]

I'm the contractor responsible for SL's Luau VM integration, appreciate the kind words about the Luau integration!

We're still in figuring out our async strategy for user-facing APIs to be honest, so these references are super helpful. We already have preemptive scheduling of execution, but it's most likely to be some kind of wrapper around `coroutine.create()` where an event loop is responsible for driving execution flow and internal `coroutine.yield()`s let you specify what you're `await`ing.

We'll likely have an RFC for how that will all work within the year, but several users have written their own bespoke `async` / `await` implementations for SL in Lua already.

ChocolateGod 2 days ago | parent [-]

> bespoke `async` / `await` implementations for SL in Lua already.

I did see these as well as some eventloop-like wrappers, but it's cool to have a built in implementation would be great so each script doesn't need to ship it.

How do you plan on migrating data from Mono's VM to Luau? Off the top of my head I can't think of any method that would be 100% reliable.

HaroldCindy a day ago | parent [-]

>How do you plan on migrating data from Mono's VM to Luau?

It helps a lot that you're only dealing with LSL that was compiled to .NET CIL by a single compiler and transformed into a state machine via an internal tool that predates `async` / `await` in .NET. Luckily you don't need a strategy that works for arbitrary .NET assemblies.

We can inspect those assemblies and the saved script state is stored in an LL-defined serialization format that includes everything on the stack / reachable via the heap. That could be converted to the script state serialization scheme we created for Luau.

The biggest complication would be that .NET CIL presents a stack-based bytecode whereas Lua(u) bytecode is register-based. There's prior art there, IIRC Android's Dalvik bytecode format is register-based and isn't generally compiled directly, you compile stack-based Java bytecode and the Android devkit has tools that convert it to stack-based Dalvik. We could use a similar scheme to convert the limited subset of CIL we need into Luau bytecode, possibly with some Dalvik-like extensions that allow use of "extended" registers for cases where we'd run into Luau's 255 register limit.

I'd like to eventually open-source SL's existing internal tooling for Mono so that people can get a better sense of the problem space and how that conversion would work. It really should have been public from the outset, and I believe the original author of SL's Mono integration wanted it to be.

Migrating existing Mono scripts onto Luau is a bit far out though, since we're still working on the core VM stuff.

ChocolateGod 16 hours ago | parent [-]

Speaking of script state serialisation, is there any improvement to the size of those when being stored/transferred.

IIRC one of the biggest fail points in region crossings is that the source simulator has to serialise and send the state of all scripts attached an agent to the target simulator, and if this fails the crossing fails and the user logs out (and in many cases the script will get marked as not running)

HaroldCindy 5 hours ago | parent [-]

> Speaking of script state serialisation, is there any improvement to the size of those when being stored/transferred.

They're about the same as before, they weren't terribly large to begin with though. From what I've seen the region crossing issues aren't caused by script state serialization, but hard to track down issues in edge cases in object handoff that're outside the scope of my contract.

HaroldCindy 2 days ago | parent | prev [-]

One thing that was immediately apparent upon switching VMs was that a lot of the existing overhead was in scheduling, context switching and the implementation of the actual library functions like `llDoWhatever()`.

We haven't even used Luau's JIT at all yet, but preemptive scheduling of what's typically trivial glue code is much cheaper and easier with a VM that supports it as a natural consequence of its design versus transforming everything into a state machine at the AST or bytecode level for a VM that doesn't.

> Actually, the biggest problem is that each idle program uses about 1us per frame, which adds up.

More scheduler overhead to resolve :)

Animats 2 days ago | parent [-]

(For those not familiar with Second Life, every object that does something has a little program in it. Every chair you can sit on, every door you can open, and every clothing item where you can change colors has a small program written by some users. Most of those programs are almost always idle. But there's a tiny amount of CPU time consumed on each frame for each idle program, about 1us to 2us in the Mono implementation. A region can have 10,000 little programs, each eating 1us on each simulation cycle, 45 times a second. This adds up.)

ChocolateGod 2 days ago | parent [-]

The amount of heavily custom scripted HUDs required to do things in Second Life seems pretty insane last time I checked it, one for a head, one for a body, one for animations etc. I'm surprised the viewer doesn't have a way to "dock HUDs" where they can be activated/deactivated with one click when not in use in viewer managed regions.