Skip to content

Optimize and improve lualib#1128

Closed
GlassBricks wants to merge 53 commits intoTypeScriptToLua:masterfrom
GlassBricks:optimize-array-operations
Closed

Optimize and improve lualib#1128
GlassBricks wants to merge 53 commits intoTypeScriptToLua:masterfrom
GlassBricks:optimize-array-operations

Conversation

@GlassBricks
Copy link
Copy Markdown
Contributor

@GlassBricks GlassBricks commented Sep 8, 2021

Significantly optimizes array builtin function calls. EDIT: and other lualib impovements

This depends on both runtime-benchmark and preceding-statements pull requests. If and when those get merged I'll rebase.

Implementation notes:

  • For some cases this might break with preceding statements, will fix whenever preceding statements gets more finalized
  • Optimizations have the most effect on lua5.3, minimal effect on luaJIT (as can be expected).
  • Introduced NodeFlags concept (which absorbs existing FunctionExpressionFlags)
  • Added lualib dependency exactness test, and fix detected bugs
EDIT: no longer relevant:
For optimizing array.push with one element, when the return is not used, `#array` is not generated, and there needs to be a way to signal "no expression" (the statement is added as a preceding statement). `FunctionVisitor` does not allow to return `undefined` for a `CallExpression`; and returning `undefined` already means something else for `transformBuiltinCallExpression`. The best way I could come up with was to create a new lua AST node called `NotEmittedExpression`, than when `transformExpressionStatement` receives, it outputs no statement. Nodes of this type should not end up in the final lua AST. If you can think of a better solution, please comment.

General optimization methods:

  • Append to array instead of array = array.concat(...)
  • Use items[] instead of ...items[]. This allows optimizing cases such as array.push(...anotherArray), and also is slightly faster than vararg anyways (based on my local benchmarks). This does however create backwards incompatibilities
  • #array is actually a O(lgN) operation; so length is stored/computed where possible
  • all array indexes are replaced with lua indexes (used as arr[i-1], which gets translated to lua as arr[i]), avoiding an addition on every indexing. Based on my benchmarks, even if this happens only once in a simple loop, this gives a ~10% speedup
  • All for loops (numeric and array iteration) are replaced with for(const i of $range(...)). This both helps in "storing" #array so it isn't recomputed, seems to be friendlier to the compiler (measurable speedup in some cases), and is faster than ipairs. I assume the potential behavior change (due to metatables) isn't an issue because lualib already wasn't consistent in using ipairs or numeric indexes
  • Avoid Math.min/Math.max -- global variable access

Some particular methods:

  • array.push(oneElement) is optimized to something like array[#array+1] = oneElement (+ changes for execution order). This is the most significant optimization
  • array.join() is replaced with essentially an array.map + table.concat call -- lua string manipulation is very slow, and one table.concat call is much faster than many concats
  • array.shift() is inlined (since array.pop() already is?)

Other:

  • Normalized naming of variables
  • Found and fixed a few corner-case bugs

Benchmarks running on my local machine, for lua5.3 (Note: I changed the benchmarks to run x5 times for more stable results):

runtime

name master (s) commit (s) change (s) change (%)
./runtime_benchmarks/array_concat_array.lua 0.3594 0.2454 -0.1140 -31.73
./runtime_benchmarks/array_concat_spread.lua 0.4924 0.3262 -0.1662 -33.75
./runtime_benchmarks/array_every.lua 0.4613 0.3444 -0.1169 -25.35
./runtime_benchmarks/array_filter.lua 0.4877 0.3835 -0.1041 -21.35
./runtime_benchmarks/array_find.lua 0.8240 0.6976 -0.1263 -15.33
./runtime_benchmarks/array_findIndex.lua 0.7934 0.6771 -0.1163 -14.66
./runtime_benchmarks/array_flat.lua 1.1143 0.4668 -0.6475 -58.11
./runtime_benchmarks/array_flatMap.lua 1.4170 0.5521 -0.8648 -61.03
./runtime_benchmarks/array_foreach.lua 0.4511 0.3249 -0.1262 -27.97
./runtime_benchmarks/array_includes.lua 0.3914 0.3530 -0.0384 -9.81
./runtime_benchmarks/array_indexOf.lua 0.4625 0.3597 -0.1028 -22.23
./runtime_benchmarks/array_join.lua 2.8024 0.9221 -1.8803 -67.10
./runtime_benchmarks/array_map.lua 0.4588 0.3736 -0.0852 -18.57
./runtime_benchmarks/array_push_array.lua 0.5226 0.1527 -0.3699 -70.78
./runtime_benchmarks/array_push_multiple.lua 0.3632 0.1985 -0.1647 -45.35
./runtime_benchmarks/array_push_single.lua 0.6837 0.1884 -0.4954 -72.45
./runtime_benchmarks/array_reduce.lua 0.4811 0.4259 -0.0552 -11.47
./runtime_benchmarks/array_reduceRight.lua 0.4892 0.4298 -0.0594 -12.14
./runtime_benchmarks/array_reverse.lua 0.6198 0.4796 -0.1402 -22.62
./runtime_benchmarks/array_slice.lua 0.5619 0.4497 -0.1122 -19.96
./runtime_benchmarks/array_some.lua 0.4633 0.3456 -0.1178 -25.42
./runtime_benchmarks/array_splice.lua 0.5837 0.4816 -0.1021 -17.49
./runtime_benchmarks/array_unshift.lua 0.6866 0.4277 -0.2590 -37.72
sum 15.9709 9.6059 -6.3650 -39.85

@GlassBricks
Copy link
Copy Markdown
Contributor Author

GlassBricks commented Sep 8, 2021

The above commit addresses #1130.
maybe could separate into different PR/branch

@GlassBricks
Copy link
Copy Markdown
Contributor Author

I'll eventually rebase to cleanup the commit tree

…p-base

# Conflicts:
#	src/transformation/visitors/literal.ts
String manipulation is slow in lua, and one table.concat operation is much faster than many string concatenations
@GlassBricks GlassBricks force-pushed the optimize-array-operations branch from 11a9e40 to db04b77 Compare September 9, 2021 23:29
@GlassBricks GlassBricks changed the title Optimize array operations Optimize and improve lualib Sep 10, 2021
@Zamiell
Copy link
Copy Markdown
Contributor

Zamiell commented Nov 18, 2021

fantastic work!

@GlassBricks GlassBricks closed this Jan 2, 2022
@GlassBricks
Copy link
Copy Markdown
Contributor Author

Will wait until (possible) lualib refactor before finishing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants