Local iterator functions slower than global?

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Local iterator functions slower than global?

Post by ivan »

Limey wrote: Fri Nov 10, 2017 8:27 pm I had no idea variable name mattered when localizing.
Like I said, there is no significant advantage to localizing pairs or ipairs (in fact it could be detrimental with LuaJIT).
On the other hand localizing functions like 'math.cos' is beneficial since you're not doing the 'math.' lookup every time.
like, 'math.cos' var name should be 'cos' or, 'love.graphics.draw' var name should be 'draw'?
No, it doesn't have to be.
User avatar
slime
Solid Snayke
Posts: 3163
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Local iterator functions slower than global?

Post by slime »

ivan wrote: Sat Nov 11, 2017 7:40 am(in fact it could be detrimental with LuaJIT).
I see people say this a lot but it's generally based on a misinterpretation of http://luajit.org/ext_ffi_tutorial.html#cache , which is specifically talking about localizing FFI-based C functions and nothing else. Mike Pall still recommends localizing Lua functions (including Lua's standard library APIs, most of which are something a bit different from FFI-based C APIs, traditional C Lua APIs, and Lua-defined functions).
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Local iterator functions slower than global?

Post by ivan »

slime, the tests confirm that using local L_next, L_pairs, L_ipairs = next, pairs, ipairs is slower with LuaJIT.
local next, pairs, ipairs = next, pairs, ipairs makes no significant difference to compared to simply using globals.
Localizing functions in modules (string.format, math.cos, etc) can be significantly faster though.
Attachments
tables.love
(666 Bytes) Downloaded 81 times
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Local iterator functions slower than global?

Post by bartbes »

But as was explained above, that's because the iterators specifically have special codepaths that are apparently sensitive to the function name. We have also seen that if you name the locals the same, it does have a (very small) positive effect.

Anyway, it seems like the moral of the story, as ever, is that when you're optimising you should measure.
User avatar
slime
Solid Snayke
Posts: 3163
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Local iterator functions slower than global?

Post by slime »

ivan wrote: Sun Nov 12, 2017 6:57 am slime, the tests confirm that using local L_next, L_pairs, L_ipairs = next, pairs, ipairs is slower with LuaJIT.
I restructured your test file a bit and that's not what I see.

Code:

Code: Select all

local clock = function() return love.timer.getTime()*1000 end
--local clock = function() return os.clock()*1000 end

function test(func, n)
  local t1 = clock()
  func(n)
  local t2 = clock()
  return t2 - t1
end

local tests = {}

function tests.G_pairs(t)
  for k,v in pairs(t) do end
end

function tests.G_ipairs(t)
  for k,v in ipairs(t) do end
end

function tests.G_next(t)
  for k,v in next,t do end
end

do
  local pairs = pairs
  function tests.L_pairs(t)
    for k,v in pairs(t) do end
  end
end

do
  local ipairs = ipairs
  function tests.L_ipairs(t)
    for k,v in ipairs(t) do end
  end
end

do
  local next = next
  function tests.L_next(t)
    for k,v in next,t do end
  end
end

function tests.numeric(t)
  for i = 1, #t do local v = t[i] end
end

local tbl1, tbl2 = { }, { }
for i = 1, 1000000 do
  tbl1["id:" .. i] = i
  tbl2[i] = i
end

local orderedtests = {
  "G_pairs",
  "L_pairs",
  "G_ipairs",
  "L_ipairs",
  "G_next",
  "L_next",
}

local runindex = 0

function run()
  runindex = runindex + 1
  print("Run " .. runindex)
  collectgarbage()
  print('  table')
  for k, v in ipairs(orderedtests) do
    local dt = test(tests[v], tbl1)
    local res = string.format("    %s  %f", v, dt)
    print(res)
  end

  print('  list')
  for k, v in ipairs(orderedtests) do
    local dt = test(tests[v], tbl2)
    local res = string.format("    %s  %f", v, dt)
    print(res)
  end
end

function love.keypressed( key )
  if key == "r" then
    run()
  elseif key == "escape" then
    love.event.quit()
  end
end
Results for 5 runs:

Code: Select all

Run 1
  table
    G_pairs  7.001184
    L_pairs  6.140291
    G_ipairs  0.000703
    L_ipairs  0.000241
    G_next  6.049011
    L_next  5.884710
  list
    G_pairs  4.139990
    L_pairs  4.099162
    G_ipairs  1.233163
    L_ipairs  1.238057
    G_next  4.137121
    L_next  4.103194
Run 2
  table
    G_pairs  7.419816
    L_pairs  6.398329
    G_ipairs  0.000797
    L_ipairs  0.000340
    G_next  6.009190
    L_next  6.012991
  list
    G_pairs  4.129244
    L_pairs  4.120332
    G_ipairs  1.181987
    L_ipairs  1.294385
    G_next  4.138757
    L_next  4.187949
Run 3
  table
    G_pairs  5.667696
    L_pairs  4.881093
    G_ipairs  0.000643
    L_ipairs  0.000227
    G_next  4.833117
    L_next  4.984283
  list
    G_pairs  3.356417
    L_pairs  3.433502
    G_ipairs  1.000181
    L_ipairs  0.925301
    G_next  3.380838
    L_next  3.437651
Run 4
  table
    G_pairs  5.487222
    L_pairs  5.373785
    G_ipairs  0.000764
    L_ipairs  0.000400
    G_next  5.328619
    L_next  5.360983
  list
    G_pairs  3.611831
    L_pairs  3.593776
    G_ipairs  1.105480
    L_ipairs  1.037402
    G_next  3.601530
    L_next  3.668182
Run 5
  table
    G_pairs  7.402496
    L_pairs  6.652951
    G_ipairs  0.000694
    L_ipairs  0.000368
    G_next  6.616921
    L_next  6.577384
  list
    G_pairs  4.345796
    L_pairs  4.371819
    G_ipairs  1.476764
    L_ipairs  1.392475
    G_next  4.106316
    L_next  4.103164
Results if I swap the order of the global and local tests:

Code: Select all

Run 1
  table
    L_pairs  6.791587
    G_pairs  6.089623
    L_ipairs  0.000967
    G_ipairs  0.000344
    L_next  6.018195
    G_next  5.899110
  list
    L_pairs  4.100567
    G_pairs  4.139295
    L_ipairs  1.240099
    G_ipairs  1.226358
    L_next  4.147724
    G_next  4.120191
Run 2
  table
    L_pairs  8.088988
    G_pairs  7.181398
    L_ipairs  0.000881
    G_ipairs  0.000450
    L_next  6.617171
    G_next  7.379357
  list
    L_pairs  4.767215
    G_pairs  4.204302
    L_ipairs  1.403988
    G_ipairs  1.248829
    L_next  4.137867
    G_next  4.382359
Run 3
  table
    L_pairs  8.070507
    G_pairs  7.158387
    L_ipairs  0.001047
    G_ipairs  0.000650
    L_next  6.187538
    G_next  6.027564
  list
    L_pairs  4.250479
    G_pairs  4.168065
    L_ipairs  1.328489
    G_ipairs  1.338998
    L_next  4.215130
    G_next  4.139268
Run 4
  table
    L_pairs  7.410009
    G_pairs  6.451298
    L_ipairs  0.000711
    G_ipairs  0.000480
    L_next  6.016515
    G_next  6.016951
  list
    L_pairs  4.099409
    G_pairs  4.145517
    L_ipairs  1.202127
    G_ipairs  1.277227
    L_next  4.125294
    G_next  4.141291
Run 5
  table
    L_pairs  7.360992
    G_pairs  6.380586
    L_ipairs  0.000707
    G_ipairs  0.000433
    L_next  6.026424
    G_next  5.992165
  list
    L_pairs  4.139334
    G_pairs  4.102957
    L_ipairs  1.200363
    G_ipairs  1.268221
    L_next  4.114833
    G_next  4.122798
ivan wrote: Sun Nov 12, 2017 6:57 amlocal next, pairs, ipairs = next, pairs, ipairs makes no significant difference to compared to simply using globals.
Indeed.
Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests