<p>LTR (Lua Tiny RAM) is a Lua patch (written specifically for <b>eLua</b> by Bogdan Marinescu) that significantly decreases the RAM usage of Lua scripts,
thus making it possible to run large Lua programs on systems with limited RAM. This section gives a full description of LTR. If you're writing <b>eLua</b>
modules, this page will certainly be of interest to you, as it shows how to interact with LTR in a portable and easy to configure way.</p>
<h2>Motivation</h2>
<p>The main thing that drove me to write this patch is the relatively high Lua memory consumption at startup (obtained by running
<i>lua -e "print(collectgarbage'count')"</i>). It's about 17k for regular Lua 5.1.4, and more than 25k for some of eLua's platforms. These figures are
mainly a result of registering many different modules to Lua. Each time you register a module (via luaL_register) you create a new table and populate
it with the module's methods. But a table is a read/write datatype, so luaL_register is quite inefficient if you don't plan to do any write operations
on that table later (adding new elements or manipulating existing ones). I found that I almost never have to do any such operations on a module's
table after it was created, I just query it for its elements. So, from the perspective of someone worried about memory usage, I'd rather have a
different type of table in this case, one that wouldn't need any RAM at all, since it would be read only, so it could reside entirely in ROM.</p>
<p>There's one more thing related to this context: Lua's functions. While Lua does have the concept of C functions, they still require data structures
that need to be allocated (see lua_pushcclosure in lapi.c for details), as they can have upvalues or environments. Once again, this isn't something I
use often with eLua. Most of the times my functions (especially the ones exported by a C module) are very simple, and they don't need upvalues or
environments at all. In conclusion, having a "simpler" function type would improve memory usage.
</p>
<h2>Details</h2>
<p>The patch adds two new data types to Lua. Both or them are based on the lightuserdata type already found in Lua, and they share the same basic
attributes: they don't need to be dynamically allocated (as they're just pointers on steroids) and they're compared in the same way lightuserdatas
<p>The table below summarizes the RAM usage in KBytes (as obtained by running <i>lua -e "print(collectgarbage'count')"</i> from the <b>eLua</b> shell).
<b>OPT=0</b> is LTR's "compatibility mode" (basically this means that the patch is disabled, so you're running plain Lua) and <b>OPT=2</b> is the
<p>As you can see, the differences are significant, and (more important) it doesn't matter how many modules you load in <b>eLua</b>, the RAM consumption
doesn't modify.</p>
<p>Currently, there aren't any performane measurements related to LTR. It's clear from the implementation that the patch slows down the virtual machine,
<ahref="building.html">here</a>. You don't even to specify this explicitly, as LTR is enabled by default for all <b>eLua</b> targets.</p>
<p>When <b>optram</b> is 0, LTR is not active. In this mode the patch just tries to keep the modified version as close as possible to the unpatched version
in terms of speed and functionality. You might want to use this if you want full Lua compatibility (although this is rarely an issue in practice),
or need to overcome the read-only limitations of rotables (but check <ahref="faq.html#rotables">this</a> first). If your program behaves weird and you
suspect that LTR might be the cause of your problems, recompiling with <b>optram=0</b> is a quick way to eliminate or confirm your suspicions.</p>
<p>When <b>optram</b> is 1 (default), all the LTR optimizations are enabled. The implementation of the Lua standard libraries is modified to take advantage
of the new datatypes. In particular, the IO library is modified to use the registry instead of environments, thus making it more resource-friendly,
the side effect being that this mode doesn't support pipes in the <b>io</b> module (which isn't an issue for <b>eLua</b>).
It also leaves the <b>_G</b> (globals) table with a single method (<i>__index</i>) and sets it as its own metatable, so all accesses to globals are
now sligthly slower because of the <i>__index</i> metamethod call.</p>
<h2>Writing LTR-compatible modules</h2>
<p>The LTR patch introduces a specific method for writing modules in such a way that they're fully compatible with both <b>optram=0</b> and <b>optram=1</b>.
If you're writing a new <b>eLua</b> module you should use this method, as it keeps code coherency. </p>
<p>We'll show this method using a simple example. Let's assume that you want to register a simple module called "mod" that has a single function named "f".
For regular Lua, you'd do something like this:</p>
<li>all the "global" rotables in the system (the ones that must be visible from <b>_G</b>, like the rotables of all the modules exported to Lua) must be
included in a special array, called <b>lua_rotable</b> (defined in <i>linit.c</i>). Simply including the rotable's definition array (mod_map in this case)
in the lua_rotable array makes it visible globally, thus you don't need to call any kind of register function. This is why <b>luaopen_mod</b> now returns
<p>The two forms above (for regular tables and for rotables) are clearly different, but we want to keep them both to be able to work at both <b>optram=0</b>
and <b>optram=2</b>. You can use #ifdefs to differentiate between the two cases in different optimization levels, but this becomes really annoying after
a (short) while. This is why I added another file called <b>lrodefs.h</b> (<i>src/lua</i>) that can be used to give an "universal" definition to our map
arrays. Here's how our example looks after rewriting it to take advantage of <b>lrodefs.h</b>:</p>
<p>If you want to register a module using a regular Lua table, but use lightfunctions instead of regular functions, use <i>luaL_register_light</i> instead
<li>currently, <b>MIN_OPT_LEVEL</b> should be always set to 2</li>
<li>you need a C99-compatible compiler to use LTR (because of the compile-time explicit union initialization that's needed to declare const rotables).
Fortunately this isn't a issue right now, as all current eLua targets use GCC and GCC knows how to handle this.</li>
<li>your linker command file should export two symbols: <b>stext</b> and <b>etext</b>. They should be declared before and after the .rodata* section
placement (generally you'd declare stext at the beginning of .text definition and etext and the end of .text definition, see for example
<i>src/lua/at91sam7x256/flash256.lds</i>). These are needed by the patch to differentiate between a regular table and a rotable (although this is likely
<p>With unpatched Lua, you can specify what modules to be part of the Lua image by modifying <i>src/lua/linit.c</i>. In the particular case of <b>eLua</b>
one had to declare a list of the modules that must be compiled in <i>src/platform/<name>/platform_conf.h</i> like this:</p>
<p>(<b>IMPORTANT NOTE</b>: the fact that there are no commas between two different _ROM declarations (as seen above) is NOT an error;
on the contrary, this is very much intended. Try using commas and you'll get in trouble very soon :) ).</p>
<p>Note the 3rd parameter of the <b>_ROM</b> macro, which is the name of the definition array for the (ro)table. That's it. The code in linit.c will take
care of everything else, including initializing the list of modules in LUA_PLATFORM_LIBS_ROM with regular tables instead of rotables at <b>optram=0</b>