Caching last used table index

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Caching last used table index

Soni "They/Them" L.
I often write code like:

local foo = t.foo
if not foo then foo = whatever t.foo = foo end
-- use foo here

but ideally I'd like to write it like:

if not t.foo then t.foo = whatever end
local foo = t.foo

and still have the same performance (or better).

does lua do any optimizations related to this?

Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

Sam Pagenkopf
have you benchmarked it?

also note that "if not x then x = y" can be written as "x = x or y"

On Sat, May 4, 2019 at 10:05 PM Soni "They/Them" L. <[hidden email]> wrote:
I often write code like:

local foo = t.foo
if not foo then foo = whatever t.foo = foo end
-- use foo here

but ideally I'd like to write it like:

if not t.foo then t.foo = whatever end
local foo = t.foo

and still have the same performance (or better).

does lua do any optimizations related to this?

Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

Philippe Verdy
I'd write:
local foo = t.foo; if not foo then foo = whatever; t.foo = foo end // Lua
(i.e. first assign the local, to reassign this local to the t field).

If you don't need to assign t.foo itself, you can of course write:
  local foo = t.foo or whatever; // Lua

In C, I'd use chained assignements:
  /*auto or register*/ Object *foo = t.foo = t.foo || whatever; // C

Stricter variant Javascript/Java/C#/C++ (if the || operator is overloaded or only returns a boolean):
  /*local or var*/ foo = t.foo = (t.foo == null ) && t.foo || whatever; // Javascript
  Object foo = t.foo = (t.foo == null ) && t.foo || whatever; // Java
   /*auto or register*/  Object *foo = t.foo = (t.foo == null ) && t.foo || whatever; // C++

But Lua still does not like chained assignments in expressions (only supports assignments as separate instructions).


Le dim. 5 mai 2019 à 06:50, Sam Pagenkopf <[hidden email]> a écrit :
have you benchmarked it?

also note that "if not x then x = y" can be written as "x = x or y"

On Sat, May 4, 2019 at 10:05 PM Soni "They/Them" L. <[hidden email]> wrote:
I often write code like:

local foo = t.foo
if not foo then foo = whatever t.foo = foo end
-- use foo here

but ideally I'd like to write it like:

if not t.foo then t.foo = whatever end
local foo = t.foo

and still have the same performance (or better).

does lua do any optimizations related to this?

Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

Tim Hill
In reply to this post by Soni "They/Them" L.


> On May 4, 2019, at 8:04 PM, Soni They/Them L. <[hidden email]> wrote:
>
> I often write code like:
>
> local foo = t.foo
> if not foo then foo = whatever t.foo = foo end
> -- use foo here
>
> but ideally I'd like to write it like:
>
> if not t.foo then t.foo = whatever end
> local foo = t.foo
>
> and still have the same performance (or better).
>
> does lua do any optimizations related to this?
>

Do you REALLY mean “if not foo…” ? Dont you actually want “if foo == nil …” ?

—Tim


Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

云风 Cloud Wu
In reply to this post by Soni "They/Them" L.
Soni "They/Them" L. <[hidden email]> 于2019年5月5日周日 上午11:05写道:

>
> I often write code like:
>
> local foo = t.foo
> if not foo then foo = whatever t.foo = foo end
> -- use foo here
>
> but ideally I'd like to write it like:
>
> if not t.foo then t.foo = whatever end
> local foo = t.foo
>
> and still have the same performance (or better).
>
> does lua do any optimizations related to this?
>
I have had tried to do this optimization many years ago (2012), See
the attachment for the patch, it's based on lua 5.2.1 .

I cached the last index of table hash part in Proto struct , so that
it can use it directly on next access ( for OP_GETTABUP, OP_GETTABLE,
OP_SELF) .

But I haven't seen the better performance. I guess lua's hash table is
good enough for short string keys, > 70% short string keys are on the
main index according to my experience.


--
http://blog.codingnow.com

patch (20K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

Francisco Olarte
In reply to this post by Philippe Verdy
Philippe:

On Sun, May 5, 2019 at 6:40 PM Philippe Verdy <[hidden email]> wrote:
> In C, I'd use chained assignements:
>   /*auto or register*/ Object *foo = t.foo = t.foo || whatever; // C

1.- IIRC in C || yields int ( classic, new standars maybe yeed bool ).

2.- If it is an int, I think you can do "int foo = t.foo ||= whatever"
( may need pares ).

FOS

Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

Soni "They/Them" L.
In reply to this post by 云风 Cloud Wu


On 2019-05-05 11:03 p.m., 云风 Cloud Wu wrote:

> Soni "They/Them" L. <[hidden email]> 于2019年5月5日周日 上午11:05写道:
>> I often write code like:
>>
>> local foo = t.foo
>> if not foo then foo = whatever t.foo = foo end
>> -- use foo here
>>
>> but ideally I'd like to write it like:
>>
>> if not t.foo then t.foo = whatever end
>> local foo = t.foo
>>
>> and still have the same performance (or better).
>>
>> does lua do any optimizations related to this?
>>
> I have had tried to do this optimization many years ago (2012), See
> the attachment for the patch, it's based on lua 5.2.1 .
>
> I cached the last index of table hash part in Proto struct , so that
> it can use it directly on next access ( for OP_GETTABUP, OP_GETTABLE,
> OP_SELF) .
>
> But I haven't seen the better performance. I guess lua's hash table is
> good enough for short string keys, > 70% short string keys are on the
> main index according to my experience.
>
>

Sorry, I don't understand. Is this patch meant to turn a hash operation
(or hash retrieval operation in the case of Lua objects) and a
comparison into just a comparison?

Ideally, I want the code:

if not t.foo then t.foo = whatever end
local foo = t.foo

to act like the following C pseudocode (including some of the
unnecessary checks and branches that would be executed by the Lua VM):

void *foo;
Entry *entry = get_entry(t, "foo");
if (entry->value == NULL) {
     void *whatever;
     if (entry->key == "foo") entry->value = whatever;
     else get_entry(t, "foo")->value = whatever;
}
if (entry->key == "foo") foo = entry->value;
else foo = get_entry(t, "foo")->value;

but your code seems to use a whole other table?

Another idea would be, for short n (table hash length, 1 or 2 hash
entries), it might be faster to do a linear scan of the whole hash table
before trying to hash the key. But this has other issues.

Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

云风 Cloud Wu


Soni "They/Them" L. <[hidden email]>于2019年5月7日 周二02:17写道:


On 2019-05-05 11:03 p.m., 云风 Cloud Wu wrote:
> Soni "They/Them" L. <[hidden email]> 于2019年5月5日周日 上午11:05写道:
>> I often write code like:
>>
>> local foo = t.foo
>> if not foo then foo = whatever t.foo = foo end
>> -- use foo here
>>
>> but ideally I'd like to write it like:
>>
>> if not t.foo then t.foo = whatever end
>> local foo = t.foo

But your codes are not equivalence because it may trigger metamethods.



--
Reply | Threaded
Open this post in threaded view
|

Re: Caching last used table index

云风 Cloud Wu
In reply to this post by Soni "They/Them" L.
Soni "They/Them" L. <[hidden email]> 于2019年5月7日周二 上午2:17写道:

>
> but your code seems to use a whole other table?

It cache the index in the Proto , not another table.  It suggest the
place of entry in a hash table when the VM execute bytecode at the
same place.


>
> Another idea would be, for short n (table hash length, 1 or 2 hash
> entries), it might be faster to do a linear scan of the whole hash table
> before trying to hash the key. But this has other issues.
>

If a table has only one hash entry, it must be in main position. I
don't think it can be faster.

--
http://blog.codingnow.com