Welcome Guest Search | Active Topics | Log In | Register

Performance on variable lookup
John Smith
#1 Posted : Friday, May 8, 2020 9:24:05 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 5/8/2020(UTC)
Posts: 1

Thanks: 0 times
Was thanked: 0 time(s) in 0 post(s)
Using 2.2.5 stable

test snippet

::func <- function() {
    return 251*139

::T1 <- {T2 = {T3 = {T4 = {func = ::func}}}}

local freefunc = ::func

T1.test <- function():(freefunc) {
    local start = clock()

    local f = ::func

    for (local i = 0; i < 10000000; i++){

    print(clock() - start)


I noticed that in some cases calling functions explicitly using :: is slower than not using it. I find this weird, as I imagine not using it would look through local -> constant -> environment -> root, but using it would skip all directly to root.

However, not calling a function but just looking up (removing '()') does indeed work as intended, with :: being faster in every case.

Using free variables are also slower than using local variables in every case. I thought using a free variable would lookup once, bind the value of the func to the function in compile, and use it as a local var (implicit param) - compared to using a local variable and looking up every time it is called (though I realize it is just once and should not make any difference).

Changing inside the loop, here are my consistent test results


f()                   : 1.070   : local var
freefunc()            : 1.170   : free var

func()                : 1.430   : global, no prefix
::func()              : 1.320   : global, with ::     faster

T1.T2.T3.T4.func()    : 2.080   : global, no prefix
::T1.T2.T3.T4.func()  : 2.280   : global, with ::     slower

Is this normal?

Also while I know such differences would not matter in most cases, under 2000 loops or whatever, wouldn't it make sense to assign global lookups to local variables every time?
#2 Posted : Tuesday, June 9, 2020 10:13:12 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 8/23/2014(UTC)
Posts: 144
Location: Northern Germany & Lincolnshire, U.K.

Thanks: 2 times
Was thanked: 10 time(s) in 10 post(s)
Hmmm, this behaviour is expected.

- Local variables are on the (linear) stack and can be accessed directly, hence are faster than table or class lookups (the latter involve hash table searches)
- Free variables are buried SOMEWHERE on the stack and their position on the stack needs to be evaluated first, hence it's a bit slower
- if you call "global" func() (not ::func) that is not global, but searching in the environment object (=parent object of the function) FIRST before it tries the root table as a fallback. Your example indicates that the environment object of "test" is T1, but as T1 does not contain "func" the lookup will fail and then failover to the root table - hence there are TWO table lookups for each call, hence slower than using ::func directly
- note :: indicates the root table, which is a normal table, like T1,T2,T3,T4
- T1.T2.T3.T4.func() will include 6 lookups (same problem - environment misses, then root table to finde T1 then iterating through T2,T3,T4 to pick the "func" reference.

So in the end, unless its local, every access has at least one indirection, and unless it comes to free variables, hash table lookups get involved.

However, in your example you do it right - look up the function reference, put it in a local variable and THEN iterate on that. Should not make any difference how you look it up in the first place. If you put the lookup into the loop, you will have impact as described above and like you observed
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Clean Slate theme by Jaben Cargman (Tiny Gecko)
Powered by YAF 1.9.4 | YAF © 2003-2010, Yet Another Forum.NET
This page was generated in 0.048 seconds.