lua-users home
lua-l archive

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


Dear All,

i am trying to implement a Copas equivalent using libev (and maybe later also libuv to perform some benchmarks).

For a first prototype, i used [lua-ev](https://github.com/brimworks/lua-ev). It works quite well, but does not seem to be maintained anymore.

Then, i came acroos [evffi.lua](https://github.com/AlloSphere-Research-Group/alive/blob/master/master/ev.lua) a LuaJIT FFI binding to libev. It is quite similar to lua-ev.

Maybe i understood wrong, but it seemed to me that the FFI binding would be more efficient that the C module when used with LuaJIT. So, i ran a simple benchmark [source code](https://gist.github.com/saucisson/deb9048863386905e121#file-evffi-lua-L315). This gist also contains the code for the FFI binding.

    local ev     = require "ev" -- or "evffi"
    print (ev.version ()) -- 4.15 in both cases
    collectgarbage "stop" -- only for "evffi"
    local max   = 10000000
    local count = 0
    local loop = ev.Loop.default
    ev.Idle.new (function (loop, idle)
        count = count+1
        if count == max then
          idle:stop   (loop)
          loop:unloop ()
        end
    end):start (loop)
    local socket = require "socket"
    local start  = socket.gettime ()
    loop:loop ()
    local finish = socket.gettime ()
    print (math.floor (max / (finish - start)), "idles / second")

Question 1: why do i get a "segmentation fault" when running luajit with ev FFI on the example without `collectgarbage "stop"`? The code for Idle handler is as below (the same applies to the modified version shown after):

    ev.Idle = {}
    function ev.Idle.new (on_idle_fn)
      assert (on_idle_fn, "on_idle_fn cannot be nil")
      local ev_idle = ev_idle_t ()
      ev_idle.active = 0
      ev_idle.pending = 0
      ev_idle.priority = 0
      ev_idle.cb = on_idle_fn
      return ev_idle
    end


Question 2: when i run the benchmarks; the FFI version is faster (3.212.945 idles/second vs 2.242.525 for lua-ev). But when using sockets, i get the "too many callbacks" error from LuaJIT. So, i had to update the code as below (shown for idle, but useless in the example):

    ev.Idle.callbacks = {}
    ev.Idle.on_idle = ffi.cast ("idle_cb", function (loop, idle, revents)
      local address = tostring (idle):match "(0x%x+)$"
      ev.Idle.callbacks [address] (loop, idle, revents)
    end)
    function ev.Idle.new (on_idle_fn)
      assert (on_idle_fn, "on_idle_fn cannot be nil")
      local ev_idle = ev_idle_t ()
      local address = tostring (ev_idle):match "(0x%x+)$"
      ...
      ev_idle.cb = ev.Idle.on_idle
      ev.Idle.callbacks [address] = on_idle_fn
      return ev_idle
    end

It creates only one callback for each event type (idle, io, ...) and does the dispatch in this callback. And with this, the performance drops to 795.885 idles/second. Awful! And there is still the segmantation fault when garbage collection is enabled.

So, i suspect i am doing something wrong... but what?

Best regards,
Alban Linard