Table of Contents


Lua Compact Debug (LCD)

LCD (Lua Compact Debug) was developed by Terry Ellison as a patch to the Lua system to decrease the RAM usage of Lua scripts. This makes it possible to run larger Lua scripts on systems with limited RAM. Its use is most typically for eLua-type applications, and in this first version it targets the nodeMCU implementation for the ESP8266 chipsets.

This section gives a full description of LCD. If you are writing nodeMCU Lua modules, then this page will be of interest to you, as it shows how to use LCD in an easy to configure way.

Motivation

The main issue that led me to write this patch is the relatively high Lua memory consumption of its embedded debug information, as this typically results in a 60% memory increase for most Lua code. This information is generated when any Lua source is complied because the Lua parser uses this as meta information during the compilation process. It is then retained by default for use in generating debug information. The only standard method of removing this information is to use the “strip” option when precompiling source using a standard eLua luac.cross on the host, or (in the case of nodeMCU) using the node.compile() function on the target environment.

Most application developers that are new to embedded development simply live with this overhead, because either they aren't familiar with these advanced techniques, or they want to keep the source line information in error messages for debugging.

The compiler generates fixed 4 byte instructions which are interpreted by the Lua VM during execution. The debug information consists of a map from instruction count to source line number (4 bytes per instruction) and two tables keyed by the names of each local and upvalue. These tables contain metadata on these variables used in the function. This information can be accessed to enable symbolic debugging of Lua source (which isn't supported on nodeMCU platforms anyway), and the line number information is also used to generate error messages.

This overhead is sufficient large on limited RAM systems to replace this scheme by making two changes which optimize for space rather than time:

Building the firmware with the 0 option compiles to the pre-patch version. Options 1-3 generate the strip_debug() function, which allows this default value to be set at runtime.

Note that options 2 and 3 can also change the default behaviour of the loadstring() function in that any functions declared within the string cannot inherited any outer locals within the parent hierarchy as upvalues if these have been stripped of the locals and upvalues information.

Details

There are various API calls which compile and load Lua source code. During compilation each variable name is parsed, and is then resolved in the following order:

The variable meta information is stored in standard Lua tables which are allocated using the standard Lua doubling algorithm and hence they can contain a lot of unused space. The parser therefore calls close_func() once compilation of a function has been completed to trim these vectors to the final sizes.

The patch makes the following changes if LUAOPTIMIZEDEBUG > 0. (The existing functionality is preserved if this define is zero or undefined.)