lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> > This patch allows an alternative and much more efficient way of
> > defining these metamethods.
> 
> Have you measured the speed up in "real-like" code?

Yes, but not apart from the code that my binding generator creates.

My bindings use the __index metamethod to resolve fields and methods for my
custom types, so the most important performance test was simply to call
methods and to access fields from my custom types.

I benchmarked my binding against an up-to-date "Luna 5" style binding, which
uses a metatable and an __index metamethod pointing to a table with C
closures.

My binding uses an __index metamethod set to a C closure, which resolves the
method/field by name using my own hash function, and returns (pushes) the
correspondent Lua value (similarly to older versions of Luna).

Here's the test. I made 5.000.000 method calls invoking an empty C++ method.
GSL  iterative-calls    5000000         1.39    22KB
Luna iterative-calls    5000000         1.844   22KB
GSL  iterative-calls is 32.66% faster.

GSL is the name of my binding generator. My tests were not very rigorous,
but I made many performance improvements based on their results. If I were
to use the standard metatable route Luna would certainly beat GSL. Actually,
at the beginning, Luna *was* beating GSL. I must say you do have a pretty
fast hash table implementation :)

Here's another test. This one measure the time needed to instantiate a C++
class bound with GSL and Luna (tested with 2.000.000 instances).

GSL  instantiating      2000000         1.25    28KB
Luna instantiating      2000000         3.016   66KB
GSL  instantiating   is 141.28% faster.

The Luna implementation must fetch a metatable from the registry and
associate it to the userdata. The GSL implementation only needs to set the
fastTM field to point to some static memory structure created by the binding
generator.

But the most important performance improvement that resulted from my method
was faster garbage collections. If a game exports a HUGE amount of classes,
each with dozens or hundreds of methods and properties, the amount of
metatables and C closures created start to weight on the GC performance.

My bindings don't need metatables, and not even C closures. The code created
by the binding generator includes static C closure structs, which are linked
with the program and exist before the Lua states themselves. They are not
counted for garbage collection, and the Lua states end up using much less
memory.

This mechanism has yet another advantage: there's no need to actually "bind"
the C++ classes - that is, create their metatables and push the C closures -
the install/register/open stage. Since the closures are in static memory,
and metatables are not needed, all custom types are always available for all
Lua states, like any primitive Lua type.

Hope to have raised some interesting points about having alternative ways to
define metamethods for userdatas.

> > By the way, the addition of the fastTM field in the Udata structure
> > does not impose additional memory usage, since that structure had some
> > wasted space available (due to alignment/union issues).
> 
> Are you sure? In my machine, the original structure had 16 bytes, the
> new one has 20 (which would go to 24 with double alignment).

Sorry, it's evident that the structure will be larger. It has been 6 months
since I developed the patch/binding generator. The only type that didn't
grow in size was the GCObject union, but it doesn't make any difference
since it's never allocated.

-- Thiago