lua-users home
lua-l archive

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


On 14 Jan, 2015,at 12:31 PM, Roberto Ierusalimschy <roberto@inf.puc-rio.br> wrote:

[...] That said, a big +1 from me for removing those
additional 4 bytes (from TString.hnext) in Lua 5.3 :)

I think we can do that following Tom's idea of storing the length of
short strings in a byte. Long strings are not hashed, so they do not
need the 'hnext' field. The struct could look like this:

typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shtlen; /* length for short strings */
unsigned int hash;
union {
size_t len; /* length for long string */
struct TString *hnext; /* linked list for hash (only for short strings) */
} u;
} TString; 

That sounds like the best of both worlds. Gets my vote :)

I've just finished prototyping the external string support that I mentioned. Even though it won't work with 5.3, I used a very similar approach (involving the spare byte and making len a union) so I figure I might as well share the results anyway.

The idea was that for strings you know to be string literals or otherwise in constdata (ie declared with "static const") you don't copy the string data to the TString but just keep a pointer to it. In this way you save at least 8 bytes per string (due to most allocators rounding up to an 8-byte boundary). I tried this on 5.2 with the pointer in a union with TString.len, and using the spare byte to indicate the length if it was an external string, so I didn't increase the size of TString or introduce a new type. I should probably have called them constdata strings or literals or something, never mind. Where I say "external", this is what I mean.

I changed the reserved words, metaevents and anything passed to lua_pushliteral to be external and the results were:

Lua 5.2.3 unmodified (same numbers as before)
====================
lua_newstate: 2032 (1908)
luaL_openlibs: 6400 (6016)
Baseline mem usage: 10120

Lua 5.2.3 with reserved strings external
========================================
lua_newstate: 1672 (1668)
luaL_openlibs: 6376 (6117)
Baseline mem usage: 9736

Which saves a few hundred bytes from the baseline figure. (384 bytes is 3.8% which sounds rather better).

Next I made sure that all the built-in variable names registered with luaL_setfuncs were made external too (but without assuming all other callers of luaL_setfuncs would be, which would probably be an assumption too far).

Lua 5.2.3 with most built-in strings external
=============================================
lua_newstate: 1672 (1668)
luaL_openlibs: 5656 (5577)
Baseline mem usage: 9016

Which is a saving of 10%.

Finally, I exported the new luaL_setfuncsexternal function in the Lua API and used it in all my code (because like probably most people I always declare my luaL_Reg arrays as static const) which saved a bit more memory due to the additional runtime-specific tables included in the environment for my "Baseline mem usage" figure.

Lua 5.2.3 with all luaL_setfuncs external
=========================================
lua_newstate: 1672 (1668)
luaL_openlibs: 5624 (5550)
Baseline mem usage: 8760

Which brings the memory savings up to 13%, which is pretty nice. Unfortunately I realise that this 5.2-based prototype can't be applied on 5.3 due to the 'hnext' field being needed for short strings, which is a bit of a shame. The 5.2 diffs aren't that big and would be quite similar to Roberto's proposal, but if there isn't a spare 4 bytes in the TString then the savings would be negligable unless you had a lot of large literals (and you made the external stuff work for long strings, which I didnt bother doing). Ah well back to the drawing board for ways to eke out my RAM budget!

Cheers,

Tom