Lua-RTOS: a real-time operating system for ESP32
github.com
github.com
Is the goal of this project to allow people to run realtime software? if so, isn't using lua a problem because of it's memory management causing GC stalls?
It doesn't appear to be addressed in the README of the github. One other explanation is that I'm missing the point, and it's just using RTOS as a small embeddable OS on which to run lua, is that the case?
https://researcher.watson.ibm.com/researcher/view_page.php?i...
https://www.ptc.com/en/blogs/plm/ptc-perc-virtual-machine-te...
https://www.militaryaerospace.com/defense-executive/article/...
I thought we were talking about real time GC, besides only the first example is a naval ship.
Hard realtime C++ does as well.
Can you entirely turn off lua's GC?
collectgarbage("stop")
See https://www.lua.org/manual/5.4/manual.html#pdf-collectgarbag...For such a dynamic language Lua is quite good about avoiding hidden dynamic allocation. Creating a new closure (or plain Lua function), coroutine, string, or table will, of course, allocate a new object. But all of those are either explicit or fairly obvious. Lua's iterator construct is careful to avoid dynamic allocation--I believe it's one reason why iterators take two explicit state arguments. And Lua has a special type for C functions (as opposed to Lua functions), allowing you to push, pass, and call C functions without dynamic allocation. Likewise for lightuserdata (just a void pointer), and of course numbers (floats and integers) and booleans--no dynamic allocation.
Nested function calls could result in a (Lua VM) stack reallocation. But Lua guarantees tail call optimization. And the default stack size is a compile-time constant.
Finally, Lua is very rigorous about catching allocation failure while maintaining consistent state. Well-written applications can execute data processing code from behind a protected call or coroutines resume (which is implicitly protected) and still keep chugging along in the event of allocation failure anywhere in the VM. The core of the application, such as the event loop and critical event handlers, can be written to avoid dynamic allocation after initialization.
Depending on where you are on the need for control different technologies can work for you.
edit: updated to reflect that I meant "upper bound"
edit2: completely reworded to be more clear.
On the RTOS I was the lead for, some constraints were measured in 100s of ns.
Edit to address the edit: our upper bound in that case was single digit microseconds.
Might I suggest wording such as "upper bound constraints exceeding 100ms aren't typically addressed with real time methods".
Now, some parent comment mentioned RTOS. Maybe for a real time OS there would be a practical hard upper bound. But for real time systems in general this upper bound would be totally domain specific.
Perhaps even more important is the increased memory use due to Lua. Some devices have very little memory to begin with.
Yet MS-DOS had plenty of programming languages to chose from, when we weren't coding games or demoscene stuff.
That is, one can start it, stop it, run it to completion, run a 'step', tune the size of the step and the aggressiveness of collection, all from within Lua.
It's true that you can't get hard realtime guarantees while using Lua naively, you do have to be aware of what you're doing. If you need to be 'cycle perfect', probably use something else.
But there are an enormous number of applications where what Lua offers is just fine, and there's no reason a Lua program should have GC 'stalls', if that means unexpected and lengthy pauses in execution.
This is a really cool project imho.
I find that if I completely abduct a high-priority thread and never yield back to the OS, things on the critical execution path run incredibly smoothly. I am able to execute a custom high precision timer in one of these loops while experiencing less than a microsecond of jitter. Granted, it will light up an entire core to 100% the whole time the app is running. But, in today's world of 256+ core 1U servers, I think this is a fantastic price to pay for the performance you get as a result. Not yielding keeps your cache very toasty.
Avoiding any allocation is also super important. In .NET, anything touching gen2 or LOH is death sentence. You probably don't even want stuff making it into gen1. Structs and streams are your friends for this adventure.
This is a non-realtime application running on top of a scheduler that is capable of supporting realtime applications.
Just placing an application on top of an RTOS does not make it realtime.
There's a few caveats, though, in that this will not be called if you've called into C code. That is, you will only yield while executing code in the Lua interpreter.
Why does an IDE for microcontrollers requires a Google Account? Guess I'll never know.
I wonder if the performance can significantly be improved if this is ported to Terra language, a system programming language meta-programmed in Lua [2]. It's going to stable 1.0 version real soon.