Lua: Get CPU Load on Linux

On May 2, 2011, in Code Monkey, by Tom

Here’s a Lua function that returns the percentage of CPU used on Linux. The load includes time in user space and system space. In case you’re curious, I used `top` to get the load for a couple reasons:

  1. It’s installed by default on most distros (as opposed to the sysstat tools).
  2. It gives the idle time in percentage normalized to 100% (as opposed to /proc/stat which requires knowledge of the jiffy’s interval, which can vary).
function cpu_load(interval)
   interval = interval or 1
   local f = io.popen('top -bp$$ -d ' .. interval .. ' -n 2')
   local s = f:read('*all')

   -- Find the idle times in the stdout output
   local tokens = s:gmatch(',%s*([%d%.]+)%%%s*id')

   -- We're interested in the 2nd 'top' idle time
   local ii = 1
   for idle in tokens do
      if ii == 2 then
         return 100.0 - tonumber(idle)
      end
      ii = ii + 1
   end
end

You can call it from the Lua shell as:

> load = cpu_load()
> print(load)
43.7

Tagged with:  

Lua Quick Reference Sheet

On September 27, 2010, in Code Monkey, by Tom

Here’s a nice 4 page reference for Lua 5.1. It was created by Thomas Lauer and can be downloaded from his website. I’ve reposted it here just-in-case… I’ve been bitten before.

Lua Reference Card (PDF)

Tagged with:  

C++ Enums in Lua

On September 13, 2010, in Code Monkey, by Tom

LuaI’ve been working lately on embedding Lua 5.1.4 into a C++ application. I’m really impressed with Lua, and most things are pretty straight-forward. However, when it comes to mapping typed enumerations into Lua, I just haven’t found an easy way to do it. For example, let’s say you want to expose a C++ function into Lua called create(), which takes an enumerated type as a parameter. In C++ this would look like:

typedef enum _TYPE {
    TYPE_FOO = 0,
    TYPE_BAR,
    TYPE_BAZ,
    TYPE_MAX
} TYPE;

bool create(const TYPE type);

To me, it makes the most sense to call create() from Lua with syntax like:

> create(type.foo)

Ideally, we’d also like the following:

  1. The enumeration is const, and can’t be altered from Lua code.
  2. The C++ implementation of create() could validate the type passed to it is the expected type.

Unfortunately, this isn’t as straight-forward as everything else I’ve done with Lua.

Solution (i.e. cut-to-the-chase and explain later)

Okay, I’m a practical guy… download lua_typed_enums.h and include it in your code. Then you can add the enums shown above to Lua by calling add_enum_to_lua():

add_enum_to_lua( L, "type",
    "foo", TYPE_FOO,
    "bar", TYPE_BAR,
    "baz", TYPE_BAZ,
    0 );

Your enums are now available in Lua as:

type.foo
type.bar
type.baz

Now, your C++ code that takes TYPE as an input and returns a boolean would be written as follows:

static int lua_create( lua_State *L )
{
    if( !check_enum_type( L, "type", -1 ) ) {
        /* error */
    }

    int value = get_enum_value( L, -1 );

    /* do something cool */

    lua_pushboolean( L, 1 );
    return (1);
}

You can now call your create() method from Lua how we wanted:

> create(type.bar)

Look at the comments in the header file if you want more info about using add_enum_to_lua(), check_enum_type(), and get_enum_value().

How it Works

There’s no direct way to map the expected behavior of C-enums into Lua (const-ness with typing). What I did was to create a read-only Lua table representing the enumerated type and then make each value in that table have a defined type.

Let’s deal with the first task: making a read-only table. This is pretty well documented on the web, but I’ve included a drawing below that would have helped me a lot in the beginning. Let’s assume we want to represent our enum as a Lua table. We could visualize it as follows:

We could still use the type.foo syntax with this table, but a user could assign a new value to the enum like:

> type.foo = 9

To prevent this, we need to deny write access to the table. The trick to doing this is to use a metatable and set the __index and __newindex values.

So how does this work? When the user reads a value from the table (i.e. by using type.foo), Lua fails to find “foo” in the table. So it looks in the metatable for the __index key. If that is set to point to a table, then it will try to lookup the value in that table. In the case above, it finds the “foo” value and returns it like normal. However, if the user attempts to assign to type.foo, Lua follows the __newindex path, which causes a function to get called that does nothing but print an error… effectively, the write is denied. Here’s what happens:

> type.foo = 9
[string "?"]:1: Attempt to modify read-only table

Okay, cool… we’ve made read-only enumerations, but what about typing. Glad you asked! We add one more layer of abstraction, of course <groaning>:

Basically, we make each value a table that includes the actual value and a type (“type” in our example above). The check_enum_type() function looks at the “type” field in the table to make sure the correct type was passed to your function. The get_enum_value() function gets the “value” field… which is equal to the actual C-enum type you’d expect. From the Lua side, you can inspect the enums like:

> print(type.foo.value)
0
> print(type.foo.type)
type

Explicitly, “type” is a read-only table with value “foo”. The value of “foo” is the table { value=0, type="type" }. I hope this explanation helps. Obviously, I’ve been geeking out on Lua a little too much lately :)

Tagged with: