Favicon
Gravatar

Re: Task scheduling in Lua

Hi, Alexander
Have you seen Rings?
It has an interesting solution for inter-state communication. Maybe taking a closer look might help.
http://www.keplerproject.org/rings/

On Mon, Mar 31, 2008 at 7:08 PM, Alexander Gladysh <agladysh <at> gmail.com> wrote:
Hi, list!

I'm writing a generic task server. Each task is a Lua coroutine.
Server runs several system threads, each thread with separate Lua
state. Each state may contain many tasks. New tasks are added to the
least loaded thread. Preliminary analysis suggest that performance
would benefit from some more fine-grained load balancing on the server
-- make each task thread-independent, to allow next available thread
to update next available task.

This is not easy thing to do though.

Simplest solution would be to keep a separate Lua state for each task
(possibly with cache of states). This would require almost no
modifications to existing code. However, I'm afraid (haven't tested
yet) that this solution is too heavy as I have too many script files
to read, compile and execute on state creation (okay, no compile step
with precompiled code; also can keep all sources cached in memory...
but still feels like too much). I thought about loading single Lua
state and then cloning it with lper. However this is Linux-only
solution. Furthermore, LPSM seems to be abandoned long ago. Have any
one used it in production environment?

Then there is an option to keep single state per thread and to copy
task data between them. This looks even less viable. My tasks are
sometimes data-heavy (up to few megabytes), and I expect serialization
and deserialization on each tick to take too much time. Also, this
imposes restrictions on what may be serialized -- I'd like to avoid
using low-level patches/libraries like Pluto. What-to-serialize
problems are not too much complex to workaround, but would require
some painful code changes -- again, hard to expect serialization
performance to be good enough.

I have never looked close enough, but looks like existing solutions
like Copas and Helper Threads Toolkit are not exactly fit to my
problem. Perhaps there is something else that I've missed? Any recent
advances in the field? Any advice?

Perhaps there is some way to implement some performance-effective
cross-state Lua table? Looks like such thing (albeit filled with
native Lua data only, and no coroutines/functions with upvalues etc.)
would benefit implementing second solution by eliminating the need of
serialization. But then, I guess, even *if* it would be possible, it
would involve some nasty core source patching. :-)

Alexander.



--
Luís Eduardo Jason Santos
Jérôme Vuarand | 1 Apr 01:52
Picon
Gravatar

Re: Userdata environment

2008/3/31, Shmuel Zeigerman <shmuz <at> actcom.co.il>:
> Is there some reason behind enforcing userdata environment to be a table?

I'm very surprised by the question, and the rest of the thread. In
some of my modules I use full userdata as the environment to other
full userdata, I never ran into an error specifying that the
environment has to be a table.

More specifically, my userdata A is a pointer to a C structure, and
when I __index one of its field, it returns a userdata B pointing to
the field directly. To avoid the A structure to be collected while I
have a pointer to its field (B), I make A the environment of B. It
seems to work perfectly fine.

How should the restriction manifest itself ? Is that something
specific to the Lua version of setfenv (as opposed to the C function
lua_setfenv) ? Is that something from Lua 5.0 (I'm using 5.1) ?

Mike Pall | 1 Apr 02:16
Picon

Re: Userdata environment

Jérôme Vuarand wrote:
> I'm very surprised by the question, and the rest of the thread. In
> some of my modules I use full userdata as the environment to other
> full userdata, I never ran into an error specifying that the
> environment has to be a table.

If you had turned on assertions with LUA_USE_APICHECK, the
  api_check(L, ttistable(L->top - 1));
in lua_setfenv() would have caught it.

> More specifically, my userdata A is a pointer to a C structure, and
> when I __index one of its field, it returns a userdata B pointing to
> the field directly. To avoid the A structure to be collected while I
> have a pointer to its field (B), I make A the environment of B. It
> seems to work perfectly fine.

The GC doesn't care which kind of object is referenced from the
u->env pointer (as long as it's a collectable object). You were
just lucky. But lua_getfenv() will gladly push any environment
object on the stack and tag it as a table (ouch).

> How should the restriction manifest itself ? Is that something
> specific to the Lua version of setfenv (as opposed to the C function
> lua_setfenv) ? Is that something from Lua 5.0 (I'm using 5.1) ?

Nope, it's been there since Lua 5.1 was released. Userdatas had no
environment in Lua 5.0.

--Mike

Jérôme Vuarand | 1 Apr 04:34
Picon
Gravatar

Re: Userdata environment

2008/3/31, Mike Pall <mikelu-0804 <at> mike.de>:
> Jérôme Vuarand wrote:
>  > I'm very surprised by the question, and the rest of the thread. In
>  > some of my modules I use full userdata as the environment to other
>  > full userdata, I never ran into an error specifying that the
>  > environment has to be a table.
>
>
> If you had turned on assertions with LUA_USE_APICHECK, the
>
>   api_check(L, ttistable(L->top - 1));
>
> in lua_setfenv() would have caught it.

Indeed, it does assert.

>  > More specifically, my userdata A is a pointer to a C structure, and
>  > when I __index one of its field, it returns a userdata B pointing to
>  > the field directly. To avoid the A structure to be collected while I
>  > have a pointer to its field (B), I make A the environment of B. It
>  > seems to work perfectly fine.
>
> The GC doesn't care which kind of object is referenced from the
>  u->env pointer (as long as it's a collectable object). You were
>  just lucky. But lua_getfenv() will gladly push any environment
>  object on the stack and tag it as a table (ouch).

So this means that having a userdata as environment works (as a
collection prevention as in my example above), as long as you don't
try to access it once set ?

It would be nice to have lua_setfenv check the type in a future
version. Alternatively (and I'd favor that alternative), it would be
nice to allow userdata as environment of other userdata. In the
meantime I'll try other methods to store my owner<->owned
relationship.
Alexander Gladysh | 1 Apr 07:47
Picon
Gravatar

Re: Task scheduling in Lua

On Tue, Apr 1, 2008 at 3:01 AM, Luís Eduardo Jason Santos
<jasonsantos <at> quantumsatis.net> wrote:

> Have you seen Rings?
> It has an interesting solution for inter-state communication. Maybe taking a
> closer look might help.
> http://www.keplerproject.org/rings/

I have seen it (may be not close enough), but I was under impression
that it does not allow direct data communication -- that is, if one
needs to pass something like table, he have to serialize it.

Alexander.

Goran Adrinek | 1 Apr 08:30
Picon

Re: Task scheduling in Lua

If you need serialization, Pluto library 
(http://luaforge.net/projects/pluto/) is the right way to go. I've been 
using it a lot and its stable. You can serialize practically anything 
with it.

Goran.

On 01-04-08 7:47, Alexander Gladysh wrote:
> On Tue, Apr 1, 2008 at 3:01 AM, Luís Eduardo Jason Santos
> <jasonsantos <at> quantumsatis.net> wrote:
>
>   
>> Have you seen Rings?
>> It has an interesting solution for inter-state communication. Maybe taking a
>> closer look might help.
>> http://www.keplerproject.org/rings/
>>     
>
> I have seen it (may be not close enough), but I was under impression
> that it does not allow direct data communication -- that is, if one
> needs to pass something like table, he have to serialize it.
>
> Alexander.
>
>   

Shmuel Zeigerman | 1 Apr 10:17
Picon
Picon

Re: Userdata environment

David Given wrote:
> That sounds very much like a reference leak in your code rather than 
> anything in the Lua core --- tables are used *so* much that any GC bug 
> that keeps references to deleted items would have shown up elsewhere by 
> now. The GC is pretty solid.

As Mike Pall said elsewhere in this thread, it is a known issue, already 
discussed a few times on this list. (I didn't intend to discuss it once 
again: see the starting message of this thread).

--

-- 
Shmuel

Alexander Gladysh | 1 Apr 09:48
Picon
Gravatar

Re: Task scheduling in Lua

> If you need serialization, Pluto library
>  (http://luaforge.net/projects/pluto/) is the right way to go. I've been
>  using it a lot and its stable. You can serialize practically anything
>  with it.

Is it fast? If I have to do serialization, I have to do it on each
task switch... Say, 512 tasks with 8 threads, with single update per
second -- that's 64 save/load operations per second if I'm not
mistaken. Looks like too much -- especially considering that some my
tasks are data-heavy.

Alexander.

Alex Davies | 1 Apr 09:52
Picon
Picon
Favicon

Re: Userdata environment

From: "Shmuel Zeigerman"
> This is not a leak but that doesn't help. The memory is not freed and as 
> application continues to run, it can eventually consume all the available 
> memory.

I'm afraid I still can't imagine a scenario where that's possible. I mean, 
it doesn't keep dead keys around forever. Just until it needs to grow the 
table, and then it can remove them all.. and in doing so discover that it 
never needed to grow the table in the first place. The only way it could 
consume all available memory would be if at some point you had enough live 
keys in the table to do that.

Either that or I don't understand the problem, which is also quite likely. 
=)

Sorry that there doesn't seem to be an elegant solution though.

- Alex 

Shmuel Zeigerman | 1 Apr 11:59
Picon
Picon

Re: Userdata environment

Alex Davies wrote:
> I'm afraid I still can't imagine a scenario where that's possible. I 
> mean, it doesn't keep dead keys around forever. Just until it needs to 
> grow the table, and then it can remove them all.. and in doing so 
> discover that it never needed to grow the table in the first place. The 
> only way it could consume all available memory would be if at some point 
> you had enough live keys in the table to do that.

Here is a pure-Lua test case that is very close to what my application 
is doing. (Change N if needed).
   local N = 6
   local tb = setmetatable ({}, { __mode="k" })
   print(collectgarbage"count")
   for n=1,N do
     for k=1,1e6 do tb[{}] = true end
     print(collectgarbage"count")
   end

--

-- 
Shmuel


Gmane