Lua

Powerful, efficient, lightweight scripting language

Overview

Lua is a powerful, efficient, lightweight, embeddable scripting language. It is designed for extensibility, portability, and ease of use. Lua is widely used in game development, embedded systems, web applications, and high-performance computing environments.

Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. It is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with incremental garbage collection.

Available versions

To view available lua versions:

module avail lua

Build recipes and configuration details are maintained in our GitLab repository:

Command-line tools

Lua provides two main command-line tools:

lua - The Lua interpreter

The lua executable is the standalone Lua interpreter. It can be used to:

  • Run Lua scripts directly from the command line
  • Enter interactive mode (REPL) for interactive development
  • Execute Lua code from standard input
  • Process Lua scripts with command-line arguments

Example usage:

# Run a Lua script
lua script.lua

# Interactive mode (REPL)
lua

# Execute code from command line
lua -e "print('Hello, World!')"

# Process from standard input
echo "print(2+2)" | lua

luac - The Lua compiler

The luac executable is the Lua bytecode compiler. It compiles Lua source code into bytecode that can be:

  • Loaded faster than source code
  • Protected from casual inspection
  • Pre-compiled for distribution
  • Used for faster startup times

Example usage:

# Compile a Lua script to bytecode
luac script.lua

# Compile with output file
luac -o script.out script.lua

# Compile and strip debug information
luac -s script.lua

# List bytecode
luac -l script.lua

When to use each tool:

  • Use lua when: - Running scripts directly - Developing interactively (REPL) - Testing and debugging - Quick script execution
  • Use luac when: - Pre-compiling scripts for faster loading - Distributing bytecode instead of source - Reducing startup time for frequently-used scripts - Protecting source code (basic obfuscation)

Note

The bytecode produced by luac is portable across different platforms and Lua versions, but it is recommended to compile with the same Lua version that will be used to run the bytecode.

Build optimizations

Our Lua installations are optimised for maximum performance on Discoverer’s hardware. We use the recent LLVM Compiler Infrastructure compilers to build the Lua interpreter and compiler, which are the default compilers on Discoverer Petascale Supercomputer.

Compiler optimizations:

  • Link Time Optimization (LTO): Full LTO (-flto=full) is enabled for both compilation and linking, allowing cross-module optimizations that significantly improve performance.
  • CPU-Specific Optimizations: - -march=native: Optimises for the native CPU architecture, enabling all available instruction sets - -mtune=native: Tunes the generated code specifically for the target CPU - -mfma: Enables FMA (Fused Multiply-Add) instructions for improved floating-point performance
  • Position Independent Code: -fPIC is used to enable shared library support.
  • Debug Symbols: -g flag is included for BOLT optimisation compatibility and debugging support.

Linker optimizations:

  • LLD Linker: We use LLVM’s LLD linker for faster linking and better optimisation support.
  • LTO at Link Time: -flto=full -Wl,--lto-O3 enables full link-time optimisation with optimisation level 3, allowing the linker to perform whole-program optimisations.

Build configuration:

  • Release Build: All optimisations are enabled for production use.
  • Readline Support: Command-line history and editing enabled for the lua interpreter, providing a professional REPL experience with: - Arrow key navigation - Command history - Tab completion - Line editing capabilities
  • Static Library Build: The liblua.a static library is built and installed for linking into applications.
  • LLVM Toolchain: Complete LLVM toolchain (llvm-ar, llvm-ranlib, llvm-nm, llvm-strip) is used instead of GNU binutils for better LTO support.

BOLT Binary Optimisation

The lua interpreter is further optimised using BOLT (Binary Optimisation and Layout Tool), a post-link optimiser that improves application performance by optimising code layout based on execution profiles.

BOLT Optimisation Process:

  1. Profile Collection: During the build process, a representative Lua workload is executed and profiled using perf to collect execution patterns.
  2. Profile Conversion: The collected profile data is converted to BOLT format using perf2bolt.
  3. Binary Optimisation: The lua binary is optimised using llvm-bolt with: - Block reordering using Extended TSP algorithm for better cache utilisation - Function splitting to separate hot and cold code paths - Profile-guided layout optimisation

Benefits:

  • Performance: 5-10% improvement in Lua script execution speed
  • Cache Efficiency: Better instruction cache utilisation through code reordering
  • Branch Prediction: Improved branch prediction through hot/cold path separation

Note

BOLT optimisation is applied automatically during the build process. If BOLT tools are not available, the build continues with the standard optimised binary.

These optimisations ensure that our Lua installation provides the fastest possible script execution performance for CPU-based applications on Discoverer, while maintaining full compatibility with the standard Lua API.

Available libraries

Lua provides the liblua static library that is installed by default:

liblua.a - Lua interpreter library

This library implements the Lua interpreter and can be embedded into C/C++ applications.

  • Header files: lua.h, lualib.h, lauxlib.h
  • Link flag: -llua
  • Location: $LUA_ROOT/lib/liblua.a

Note

The library uses optimised implementations and can be embedded in both C and C++ applications. It is particularly effective for adding scripting capabilities to applications, configuration file processing, and rapid prototyping.

Linking your application

To link your C or C++ application against the Lua library, use the following approach:

module load lua/5/<version>

# Compile and link
clang -o myapp myapp.c \
    -I$LUA_ROOT/include \
    -L$LUA_ROOT/lib \
    -llua \
    $LDFLAGS

Or using the environment variables set by the module:

module load lua/5/<version>

# The module sets CFLAGS, LDFLAGS automatically
clang -o myapp myapp.c $CFLAGS $LDFLAGS -llua

Lua module search paths

The Lua module automatically configures LUA_PATH and LUA_CPATH environment variables to point to the installation’s Lua module directories:

  • LUA_PATH: Search path for Lua modules (.lua files)
  • LUA_CPATH: Search path for C modules (.so files)

These paths are automatically set when you load the Lua module, allowing you to use Lua modules installed with the Lua distribution.

Using Lua in SLURM Jobs

To load Lua in your SLURM batch scripts, use the following template:

#!/bin/bash
#
#SBATCH --partition=cn         # Name of the partition of nodes (as the support team)
#SBATCH --job-name=lua
#SBATCH --time=00:01:00        # The job completes for ~ 1 min

#SBATCH --nodes           1    # One node will be used
#SBATCH --ntasks-per-node 1    # Number processes per node
#SBATCH --ntasks-per-core 1    # Run only one process per CPU core

#SBATCH -o slurm.%j.out        # STDOUT
#SBATCH -e slurm.%j.err        # STDERR

ulimit -Hs unlimited
ulimit -Ss unlimited

module purge
module load lua/5/<version>

lua script.lua

Specify the parameters and resources required for successfully running and completing the job:

  • Slurm partition of compute nodes, based on your project resource reservation (--partition)
  • job name, under which the job will be seen in the queue (--job-name)
  • wall time for running the job (--time)
  • number of occupied compute nodes (--nodes)
  • number of processes per node (--ntasks-per-node)
  • version of Lua to run after module load (see Available versions)

Save the complete SLURM job description as a file, storing it inside the folder with the input configuration, for example /discofs/$USER/run_lua/run.batch, and submit it to the queue afterwards:

cd /discofs/$USER/run_lua/
sbatch run.batch

Upon successful submission, the standard output will be directed by SLURM into the file /discofs/$USER/run_lua/slurm.%j.out (where %j stands for the SLURM job ID), while the standard error output will be stored in /discofs/$USER/run_lua/slurm.%j.err.

Getting help

See Getting help