Memory Allocation Hooks

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Memory Allocation Hooks

William Ahern
Having never written a single line of Lua code I briefly took a look at the
interpreter source to see if it's possible to add malloc()/free() hooks. It
doesn't seem like the functionality is there, though maybe not too difficult
to add. Did I miss anything?

What I'm looking for is the ability to allocate a Lua state from my own
memory arena and disable Lua's garbage collection so that I can free the
entire Lua execution context in one go. Each Lua context will be running a
handful of extremely short scripts per instantiation. My priority is
extremely fast startup and shutdown.

Lua Newbie,

Bill

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

Spencer Schumann-2
> Having never written a single line of Lua code I briefly took a look at the
> interpreter source to see if it's possible to add malloc()/free() hooks.

Look at lmem.h and lmem.c; all allocations eventually go through
luaM_realloc, which is defined within these files.  But I doubt that's
what you really want.

> What I'm looking for is the ability to allocate a Lua state from my own
> memory arena and disable Lua's garbage collection so that I can free the
> entire Lua execution context in one go. Each Lua context will be running a
> handful of extremely short scripts per instantiation. 

I think you'll find that garbage collection takes surprisingly little
time.  For executing small scripts, each with its own Lua state,
creation and deletion of the Lua state will probably dominate
processing time.  If you do want to disable garbage collection, you
can call "collectgarbage(1000000)".  I tried just such a thing early
in my Lua career, thinking that it would help to stop collecting
during CPU intensive operations.  However, in my case, disabling
garbage collection actually slowed things down.  With the caching and
virtual memory systems in modern computers, keeping a small memory
footprint is important.

> My priority is extremely fast startup and shutdown.

With this as your priority, you may want to use a single Lua state to
run all your scripts.  If you use setfenv, you can give each script
its own global environment to avoid problems with variables leaking
between scripts.

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

skaller
In reply to this post by William Ahern
On Wed, 2005-01-12 at 15:46, William Ahern wrote:
> Having never written a single line of Lua code I briefly took a look at the
> interpreter source to see if it's possible to add malloc()/free() hooks. It
> doesn't seem like the functionality is there, though maybe not too difficult
> to add. Did I miss anything?


Hope i have this right being a Lua newbie too:

In lmem.c, in 5.0.2:

/*
** definition for realloc function. It must assure that l_realloc(NULL,
** 0, x) allocates a new block (ANSI C assures that). (`os' is the old
** block size; some allocators may use that.)
*/
#ifndef l_realloc
#define l_realloc(b,os,s)       realloc(b,s)
#endif

/*
** definition for free function. (`os' is the old block size; some
** allocators may use that.)
*/
#ifndef l_free
#define l_free(b,os)    free(b)
#endif

However, lua 5.1 (still work in progress) does this with
a runtime hook:

void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t
nsize) {
  global_State *g = G(L);
  lua_assert((osize == 0) == (block == NULL));
  block = (*g->realloc)(g->ud, block, osize, nsize);
----------*************


[BTW: those codes are spagetti .. :]


-- 
John Skaller, [hidden email]
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net




Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

Jay Carlson
However, lua 5.1 (still work in progress) does this with
a runtime hook:

void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t
nsize) {
  global_State *g = G(L);
  lua_assert((osize == 0) == (block == NULL));
  block = (*g->realloc)(g->ud, block, osize, nsize);
----------*************


[BTW: those codes are spagetti .. :]

*g->realloc is win32's fault.  You now know where to send your mailbombs.

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

William Ahern
On Wed, Jan 12, 2005 at 12:15:37AM -0500, Jay Carlson wrote:
> >However, lua 5.1 (still work in progress) does this with
> >a runtime hook:
> >
> >void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t
> >nsize) {
> >  global_State *g = G(L);
> >  lua_assert((osize == 0) == (block == NULL));
> >  block = (*g->realloc)(g->ud, block, osize, nsize);
> >----------*************
> >
> >
> >[BTW: those codes are spagetti .. :]
> 
> *g->realloc is win32's fault.  You now know where to send your mailbombs.

hahahahah

Actually, the arena library I've written requires the old size as well, so
it maps perfectly. Of course, I don't even try freeing anything but the last
block except when destroying the arena. Going by my experience using
Windows, I suspect Win32 might do the same ;)

Thanks.


Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

William Ahern
In reply to this post by Spencer Schumann-2
On Tue, Jan 11, 2005 at 10:11:16PM -0700, Spencer Schumann wrote:
> > My priority is extremely fast startup and shutdown.
> 
> With this as your priority, you may want to use a single Lua state to
> run all your scripts.  If you use setfenv, you can give each script
> its own global environment to avoid problems with variables leaking
> between scripts.

This brings me to the second thing I was hoping to do. My application in
which I wish to embed Lua is a single-threaded server. However, all of its
I/O operations are non-blocking so as to be able to handle multiple clients.
Using Lua and coroutines I'm hoping to implement concurrent execution of
user scripts.

However, to do this I need to be able to fall out of Lua during any I/O
processing and install event callbacks. And when the I/O request is
finished, restart execution. For instance, if Lua calls something like
lookup()--for a DNS lookup--I need execution to yield and return back to the
C function which started/resumed the execution. What I *don't* want is for
lookup() to recurse back into my application, growing the C stack each time.

Would this be better accomplished using multiple states or does it not
matter? I'm still fuzzy on how I could accomplish this with Lua, or if it's
even possible.

- Bill

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

William Ahern
In reply to this post by Spencer Schumann-2
On Tue, Jan 11, 2005 at 10:11:16PM -0700, Spencer Schumann wrote:
> > What I'm looking for is the ability to allocate a Lua state from my own
> > memory arena and disable Lua's garbage collection so that I can free the
> > entire Lua execution context in one go. Each Lua context will be running a
> > handful of extremely short scripts per instantiation. 
> 
> I think you'll find that garbage collection takes surprisingly little
> time.  For executing small scripts, each with its own Lua state,
> creation and deletion of the Lua state will probably dominate
> processing time.

I wouldn't mind the garbage collection. It's just that in the average case
each client context for the server will probably take up similar amounts of
memory, and I have an inkling I _might_ get better performance by keeping
memory pools around which I can free instantly and reuse, rather than
shuttling smaller buffers back and forth from the heap with malloc(3) and
free(3).

Of course, this is all conjecture and using malloc(3) and free(3) directly
will probably suffice. It's just an option for the small chance performance
might benefit.

And, if I keep a single Lua state like you suggested then it wouldn't
matter. I'll never know till I test, though.



Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

skaller
On Wed, 2005-01-12 at 16:46, William Ahern wrote:

> 
> Of course, this is all conjecture and using malloc(3) and free(3) directly
> will probably suffice.

They're probably be more efficient than anything 
you design. I too have been tempted to write suballocators,
but I suspect that other than very special cases,
the system allocators are very good these days.

In addition GC may recycle blocks already, on top
of raw allocations, so adding yet another layer seems
likely to cost more than it saves (not to mention
the programming effort).

Hmm .. is there an option to just 'junk' the whole
of memory for a Lua state without bothering with
finalisation? In that case no collection is needed,
just delete everything on the free list without a sweep.

This could save considerable time on termination.
[Especially for small scripts that happily spew garbage
without ever doing a collection, and then terminate]

-- 
John Skaller, [hidden email]
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net




Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

Spencer Schumann-2
> Hmm .. is there an option to just 'junk' the whole
> of memory for a Lua state without bothering with
> finalisation? In that case no collection is needed,
> just delete everything on the free list without a sweep.

Take a look at close_state in lstate.c.  This function is called by
lua_close, and does just what you are asking about - it deletes
everything on the free list without bothering with a mark phase.

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

Wim Couwenberg-2
In reply to this post by Jay Carlson

Jay Carlson wrote:

*g->realloc is win32's fault.  You now know where to send your mailbombs.

Care to explain?

--
Wim

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

Jay Carlson
Wim Couwenberg wrote:

Jay Carlson wrote:

*g->realloc is win32's fault.  You now know where to send your mailbombs.


Care to explain?

Already wrote this in private mail; less certain now:

On reflection, I'm not all that certain that it's win32. But on ELF systems, it's easy to substitute a new malloc for the entire application (just define realloc). It's also easy to compile Lua to use its own custom allocator, using #define.

The three cases for the runtime hook (as opposed to a compile-time hook) are:

1) You want different allocators for different states

2) You want to have a single "standard" DLL or .so file to reduce the number of versions floating around.

3) Your program and its shared libraries can't agree which allocator to use. This is the Win32 problem I was mudslinging at.

Jay

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

skaller
On Thu, 2005-01-13 at 06:47, Jay Carlson wrote:

> The three cases for the runtime hook (as opposed to a compile-time hook) 
> are:
> 
> 1) You want different allocators for different states
> 
> 2) You want to have a single "standard" DLL or .so file to reduce the 
> number of versions floating around.
> 
> 3) Your program and its shared libraries can't agree which allocator to 
> use.  This is the Win32 problem I was mudslinging at.

also possibly

(4) testing and measuring allocations

since a hook allows you to, for example, log data
about a running program, possibly without changing
the program.

-- 
John Skaller, [hidden email]
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net




Reply | Threaded
Open this post in threaded view
|

RE: Memory Allocation Hooks

Cory Bloyd
In reply to this post by William Ahern
In order to use the runtime hook to have different allocators for
different states, would you need to have a different C function
explicitly defined to call the different allocators?

I ask because our system does not use global allocation functions.
Instead it has allocator objects that get passed around.  In order to
allow different Lua states to use different allocator objects without
modifying the distributed code, I had to resort to a rather evil hack in
my override of the Lua allocation macros.

The override looks something like this

#define l_realloc(b,os,s) poLuaRealloc(L, b, os, s)

Where L happens to be the name of the Lua state that happens to always
be present when l_realloc() is called.

For the future, I respectfully request that a pointer to the Lua state
be made an official parameter to l_realloc() and related macros.  Or at
least, please don't screw up my hack :)  The OO-in-C design of the Lua
interpreter is wonderful.  It's a shame that it stops short of the
memory handling routines.

Our goal is to allow different subsystems to run independent Lua
interpreters in different threads.  Adding the OO-extension to the
memory macros allows us to do so without necessitating any thread
synchronization within the Lua system.  It lets us control and verify
the memory allocated to the interpreters independently.  It also allows
us to segregate memory fragmentation of the interpreters from each other
and the rest of the system.  For such a tiny change, it has been
extremely valuable to us and I think it would benefit others as well. 


-----Original Message-----
From: Jay Carlson [[hidden email]] 

The three cases for the runtime hook (as opposed to a compile-time hook)

are:

1) You want different allocators for different states

...




Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

Roberto Ierusalimschy
> For the future, I respectfully request that a pointer to the Lua state
> be made an official parameter to l_realloc() and related macros.

The new system allows you to specify both the allocator function *and*
a related user data. The allocator function always gets that user data
when called:

typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
                             ^^^^^^^^

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Memory Allocation Hooks

skaller
On Fri, 2005-01-14 at 06:09, Roberto Ierusalimschy wrote:

> The new system allows you to specify both the allocator function *and*
> a related user data. The allocator function always gets that user data
> when called:
> 
> typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);

This is the traditional workaround for brain dead languages
like C that do not provide closures.

FYI: my flxcc program is a wrapper generator that wraps
C functions so they can be called from my language Felix,
it actually recognises this feature automatically
in most cases (it would be confused by lua_Alloc because
it has two void *, ud and ptr, and can't guess which
one is the client data pointer)

The failure of the Win32 to provide this facility
indicates just how stupid Microsoft really are.
X Windows always provided it, there was no excuse
at all for this misdesign. The cost was absolutely
enormous -- whole systems (such as Borland's OWL
and MFC) existed just to work around it.

-- 
John Skaller, [hidden email]
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net