lua-users home
lua-l archive

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


Hi, list!

Thank you all for your answers. Since there were that many, I would
answer them in a single post, sorry. :-)

1. About module() trick (thanks, Javier, I haven't thought about this
one). I like to have table population code written by hand -- this
gives easy to read 'reference' to available functions in given object.
(A poor-mans documentation :-) .) Otherwise your approach seems to be
quite good.

2. Why no syntax sugar (var = function(self) vs. function self:var()).
I do not like this sugar because I want strong emphasis in my code on
that functions are the first-class objects in Lua. It helps when
switching from C++ to Lua frequently. (This is nothing more than a
personal preference of course.)

3. Why not to clone table. For performance considerations. I want my
object creation to be as fast as possible (see benchmark below).

4. Why not metatable approach. I have naively thought that 'plain'
table creation would be faster. I wrote a benchmark, and it appears
that I was wrong (thank you, Matthew!). I do not quite understand why
the difference is so great though.

Benchmark is attached. Usage:

KBENCH_SCRIPT=factorybench.lua ./kbench.sh

*_init is creation of factory function, *_call is call of that
function (that is, creation of object -- what I want to optimize).

Results:

$ time lua factorybench.lua clone_init 10000000
       47.66 real        46.99 user         0.20 sys

$ time lua factorybench.lua metatable_init 10000000
       47.69 real        46.88 user         0.20 sys

$ time lua factorybench.lua plain_init 10000000
       56.00 real        54.59 user         0.30 sys



$ time lua factorybench.lua metatable_call 10000000
        5.84 real         5.75 user         0.02 sys

$ time lua factorybench.lua plain_call 10000000
       18.69 real        18.43 user         0.06 sys

$ time lua factorybench.lua clone_call 10000000
       66.36 real        64.61 user         0.34 sys

Also I do not understand the reasons for significant slowdown of
plain_init. Is hash table constructor so heavy?

For reference, here is a LuaJIT timings (I see no big differences in
relative speeds):

$ time luajit -O factorybench.lua clone_init 10000000
       37.16 real        36.75 user         0.12 sys

$ time luajit -O factorybench.lua metatable_init 10000000
       37.18 real        36.69 user         0.13 sys

$ time luajit -O factorybench.lua plain_init 10000000
       48.67 real        48.00 user         0.18 sys


$ time luajit -O factorybench.lua metatable_call 10000000
        3.50 real         3.45 user         0.01 sys

$ time luajit -O factorybench.lua plain_call 10000000
       11.17 real        10.99 user         0.04 sys

$ time luajit -O factorybench.lua clone_call 10000000
       34.15 real        33.73 user         0.11 sys

Alexander.

P.S. BTW, I've actually (temporarily) solved my problem by a different
way: that class had a large number of copy-pasted getter functions
(doh), and I've replaced them with generated functions:

local simple_getter
do
  local cache = setmetatable({},{
    __index = function(t, k)
      local v = function(self) return self[k] end
      rawset(t, k, v)
      return v
    end
  })
  simple_getter = function(name)
    return cache[name]
  end
end

local factory
do
 local method1 = function(self)
   print("method1", tostring(self))
 end

 factory = function()
   return
   {
     method1 = method1;
     method2 = simple_getter("var1_");
     --...
     methodN = simple_getter("varN_");
     --
     var1_ = false;
     varN_ = true;
   }
 end
end

I understand that this does not solve any of performance problems
mentioned above -- but for this specific object performance is not
issue, and it is kind of first step to refactoring. :-)

Attachment: kbench.sh
Description: Bourne shell script

Attachment: factorybench.lua
Description: Binary data