LuaLS / lua-language-server

A language server that offers Lua language support - programmed in Lua
https://luals.github.io
MIT License
3.38k stars 320 forks source link

[Experimental] Luals rust-based luajit port #2879

Open CppCXY opened 2 months ago

CppCXY commented 2 months ago

The current LuaJIT porting is complete. jit.on is not enabled because jit.off performs better. Feel free to try it if you're interested.

see: https://github.com/LuaLS/lua-language-server-rust

tomlau10 commented 1 month ago

Here are some old issues which suggested porting to luajit, maybe participants inside will be interested to test this out

lewis6991 commented 1 month ago

How did you test with LuaJIT? Did you remove all <close> variables?

CppCXY commented 1 month ago

How did you test with LuaJIT? Did you remove all <close> variables?

I replace close to defer : image

tomlau10 commented 1 month ago

I just did a preliminary benchmark here: https://github.com/LuaLS/lua-language-server/issues/2482#issuecomment-2385017356

CppCXY commented 1 month ago

I just did a preliminary benchmark here: #2482 (comment)

  • The compile time of a large lua file (~8K lines) is 40% faster 🚀
  • But the textDocument/documentSymbol of that file is 100% slower 🐌 ... and currently I have no idea why 😕

I have already fixed many issues related to the APIs. Please check the problems again

tomlau10 commented 1 month ago

I have already fixed many issues related to the APIs. Please check the problems again

I checked out the latest commit https://github.com/LuaLS/lua-language-server-rust/commit/6c7bab8189cc6d9e18062e403d862cebbe05b1e2 and rebuilt the luals-rust, now textDocument/documentSymbol is much faster than before 👍

[18:17:04.943][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [1.401]sec. {
[18:17:05.041][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.684]sec. {
[18:17:27.900][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.801]sec. {
[18:17:28.008][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.903]sec. {
[18:17:28.149][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.906]sec. {
[18:17:44.449][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.643]sec. {
[18:17:44.617][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.762]sec. {
[18:17:45.654][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.844]sec. {
[18:17:55.249][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.662]sec. {
[18:17:55.695][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.569]sec. {
[18:18:03.385][warn] [#0:resources/override_script/proto\proto.lua:189]: Method [textDocument/documentSymbol] takes [0.593]sec. {
CppCXY commented 1 month ago
  • but it's just on par with regular luals 0.71s 🤔 (a little bit slower to be exact)

Is there any comprehensive performance report, such as a comparison of memory usage and startup time for large codebases?

tomlau10 commented 1 month ago

Is there any comprehensive performance report, such as a comparison of memory usage and startup time for large codebases?

I don't have that currently, I only tested it on a large file (the large_file.lua generated by the python script mentioned in the above comment). Because with the compile time benchmark of a large file, we may directly see the performance gain (if any) by switching to luajit.

I might try to do a more comprehensive performance comparison on some of my team's projects later 🤔

CppCXY commented 1 month ago
By conducting startup tests on the luals project itself, the manually measured results are roughly as follows. It seems to be getting slower and slower, possibly due to my own limited skills. I look forward to others' tests. I will go back to working on my own language server. language server memory start time
luals 300mb 10s
luals-rust-lua5.4 315mb 10s
luals-rust-luajit 330mb 13.86s
tomlau10 commented 1 month ago

By conducting startup tests on the luals project itself

May I ask how did you conduct the start time test? By checking the timestamp in the log file? 😕


Doing 5 runs on each server setup:

Start up time (in second)

server 1 2 3 4 5 avg
luals-3.11 2.422 2.62 3.13 3.134 2.691 2.7994
luals-rust-luajit 3.856 3.749 3.367 3.542 3.852 3.6732
luals-rust-luajit-jitoff 2.3 2.456 2.95 2.114 2.404 2.4448

Memory usage (in MB)

server 1 2 3 4 5 avg
luals-3.11 152 152 156 155 142 151.4
luals-rust-luajit 175 173 179 179 185 178.2
luals-rust-luajit-jitoff 129 127 127 131 128 128.4

jit.off() jit.flush()


- ‼️ surprisingly it runs **FASTER** when `jit.off()` 🤔 maybe the startup logic of luals is not jit-friendly...
- ref for **turning off `jit` may improve performance**: https://www.cnblogs.com/zhaolaosan/p/16185249.html 
CppCXY commented 1 month ago

amazing test result, I also got the same speed test results on luals-3.11: image on luajit jit-off: image

The speed improvement is about 40%. It might be faster if we can identify what is causing the JIT fail

CppCXY commented 1 month ago

The porting to LuaJIT has been completed, and the luajit branch has been merged into the main trunk. You can download it from the release, and I have already migrated to LuaLS version 3.11.

tomlau10 commented 1 month ago

I just learnt that luajit has parameters for tuning:

Maybe we can try fiddle them around and test the difference 🤔

tomlau10 commented 1 month ago

Another test by performing full workspace diagnostic on luals project (for clarity I mean the lua-language-server, but not lua-language-server-rust). The measurement is just the time taken reported in this log:

[09:03:32.727][info] [#0:resources/override_script/provider\diagnostic.lua:566]: Diagnostics scope [file:///c%3A/Users/TomLau/lua-language-server], files count:[403]
...
[09:03:42.224][info] [#0:resources/override_script/provider\diagnostic.lua:583]: Diagnostics scope [file:///c%3A/Users/TomLau/lua-language-server] finished, takes [9.497] sec.

diagnostic time (in seconds)

server 1 2 3 4 5 avg
luals-3.11 12.87 12.668 11.613 11.572 11.687 12.082
luajit-jitoff 9.497 8.598 8.153 8.112 7.975 8.467
luajit-jiton 21.27 18.919 19.036 19.036 19.025 19.4572
luajit-jiton-tune 14.527 12.945 12.941 13.045 13.001 13.2918
C3pa commented 1 month ago

It would be interesting to know the OS & CPU architecture you both run those benchmarks on. This may be a case of: https://github.com/LuaJIT/LuaJIT/issues/285

tomlau10 commented 1 month ago

my system spec:

CppCXY commented 1 month ago

Maybe we can use the jit.dump module to see the reasons for jit failure and then consider targeted optimizations. I see many traces about inspect and luadoc.

sumneko commented 1 month ago

Try this version: https://github.com/openresty/luajit2

lewis6991 commented 1 month ago

Just to note that calls into C code cannot be JIT compiled, so if LuaLS calls into C a lot (into bee.lua), then it's likely the JIT isn't able to do much.

CppCXY commented 1 month ago

Just to note that calls into C code cannot be JIT compiled, so if LuaLS calls into C a lot (into bee.lua), then it's likely the JIT isn't able to do much.

The current situation is that JIT has caused a significant performance drop. By analyzing the results of the JIT dump, I obtained this chart: image

Frityet commented 1 month ago

Just to note that calls into C code cannot be JIT compiled, so if LuaLS calls into C a lot (into bee.lua), then it's likely the JIT isn't able to do much.

Are you sure about this? I am pretty sure that it can be JIT compiled, the C calls become inlined

CppCXY commented 1 month ago

here are the simple:

File: luadoc.lua, Line: 939, Error: NYI: bytecode FNEW  , Count: 405
File: compile.lua, Line: 604, Error: inner loop in root trace, Count: 280
File: guide.lua, Line: 748, Error: NYI: bytecode UCLO  , Count: 233
File: compile.lua, Line: 409, Error: NYI: bytecode FNEW  , Count: 182
File: variable.lua, Line: 55, Error: NYI: bytecode UCLO  , Count: 141
File: scope.lua, Line: 214, Error: inner loop in root trace, Count: 107
File: compile.lua, Line: 604, Error: loop unroll limit reached, Count: 88
File: luadoc.lua, Line: 1822, Error: NYI: bytecode FNEW  , Count: 78
File: compile.lua, Line: 606, Error: leaving loop in root trace, Count: 55
File: compile.lua, Line: 2759, Error: leaving loop in root trace, Count: 37
File: await.lua, Line: 65, Error: leaving loop in root trace, Count: 33
File: global.lua, Line: 167, Error: NYI: bytecode FNEW  , Count: 33
File: files.lua, Line: 981, Error: NYI: bytecode FNEW  , Count: 32
File: luadoc.lua, Line: 824, Error: inner loop in root trace, Count: 29
File: luadoc.lua, Line: 1832, Error: NYI: bytecode UCLO  , Count: 28
File: luadoc.lua, Line: 955, Error: NYI: bytecode UCLO  , Count: 27
File: luadoc.lua, Line: 870, Error: inner loop in root trace, Count: 26
File: guide.lua, Line: 746, Error: NYI: bytecode FNEW  , Count: 26
File: luadoc.lua, Line: 1854, Error: inner loop in root trace, Count: 25
File: luadoc.lua, Line: 830, Error: leaving loop in root trace, Count: 25
File: luadoc.lua, Line: 2091, Error: leaving loop in root trace, Count: 25
File: guide.lua, Line: 683, Error: loop unroll limit reached, Count: 25
File: guide.lua, Line: 779, Error: loop unroll limit reached, Count: 25
File: luadoc.lua, Line: 837, Error: leaving loop in root trace, Count: 23
File: compile.lua, Line: 2090, Error: leaving loop in root trace, Count: 23
File: luadoc.lua, Line: 568, Error: NYI: bytecode FNEW  , Count: 22
File: loading.lua, Line: 39, Error: NYI: bytecode UCLO  , Count: 22
File: luadoc.lua, Line: 1946, Error: leaving loop in root trace, Count: 22
File: compile.lua, Line: 1790, Error: inner loop in root trace, Count: 21
File: luadoc.lua, Line: 824, Error: loop unroll limit reached, Count: 20
File: luadoc.lua, Line: 2003, Error: leaving loop in root trace, Count: 20
File: 0x01d10bece3a0, Line: 4, Error: leaving loop in root trace, Count: 19
File: guide.lua, Line: 768, Error: leaving loop in root trace, Count: 18
File: compile.lua, Line: 1488, Error: inner loop in root trace, Count: 18
File: utility.lua, Line: 229, Error: NYI: bytecode FNEW  , Count: 17
File: compile.lua, Line: 2161, Error: inner loop in root trace, Count: 17
File: log.lua, Line: 61, Error: leaving loop in root trace, Count: 16
File: luadoc.lua, Line: 2078, Error: leaving loop in root trace, Count: 16
File: luadoc.lua, Line: 1829, Error: NYI: bytecode FNEW  , Count: 15
File: guide.lua, Line: 796, Error: inner loop in root trace, Count: 14
File: compile.lua, Line: 1993, Error: leaving loop in root trace, Count: 14
File: luadoc.lua, Line: 2016, Error: leaving loop in root trace, Count: 13
File: guide.lua, Line: 456, Error: inner loop in root trace, Count: 13
File: compile.lua, Line: 2727, Error: inner loop in root trace, Count: 13
File: diagnostic.lua, Line: 433, Error: NYI: bytecode UCLO  , Count: 12
File: luadoc.lua, Line: 1832, Error: leaving loop in root trace, Count: 12
File: 0x01d1086d96a0, Line: 5, Error: leaving loop in root trace, Count: 12
File: guide.lua, Line: 808, Error: loop unroll limit reached, Count: 11
File: inspect.lua, Line: 296, Error: down-recursion, restarting, Count: 10
File: workspace.lua, Line: 92, Error: NYI: bytecode UCLO  , Count: 10
File: compile.lua, Line: 2759, Error: down-recursion, restarting, Count: 10
File: guide.lua, Line: 796, Error: loop unroll limit reached, Count: 10
File: inspect.lua, Line: 148, Error: persistent type instability, Count: 9
File: library.lua, Line: 135, Error: leaving loop in root trace, Count: 9
File: diagnostic.lua, Line: 456, Error: NYI: bytecode UCLO  , Count: 9
File: luadoc.lua, Line: 1152, Error: NYI: bytecode FNEW  , Count: 9
File: 0x01d17ec3ab60, Line: 9, Error: leaving loop in root trace, Count: 9
File: compile.lua, Line: 978, Error: inner loop in root trace, Count: 9
File: compile.lua, Line: 2080, Error: inner loop in root trace, Count: 9
File: inspect.lua, Line: 148, Error: loop unroll limit reached, Count: 8
File: inspect.lua, Line: 255, Error: inner loop in root trace, Count: 8
File: net.lua, Line: 282, Error: leaving loop in root trace, Count: 8
File: utility.lua, Line: 652, Error: NYI: bytecode FNEW  , Count: 8
File: 0x01d1090ab5a0, Line: 4, Error: leaving loop in root trace, Count: 8
File: luadoc.lua, Line: 2008, Error: leaving loop in root trace, Count: 8
File: compile.lua, Line: 3655, Error: leaving loop in root trace, Count: 8
File: luadoc.lua, Line: 2030, Error: inner loop in root trace, Count: 7
File: json.lua, Line: 180, Error: inner loop in root trace, Count: 7
File: 0x01d1090b85a0, Line: 4, Error: leaving loop in root trace, Count: 7
File: compile.lua, Line: 2279, Error: leaving loop in root trace, Count: 7
File: compile.lua, Line: 2185, Error: leaving loop in root trace, Count: 7
File: 0x01d10c8a9aa0, Line: 5, Error: leaving loop in root trace, Count: 7
File: pub.lua, Line: 193, Error: leaving loop in root trace, Count: 7
File: compile.lua, Line: 2161, Error: loop unroll limit reached, Count: 7
File: files.lua, Line: 939, Error: NYI: bytecode FNEW  , Count: 7
File: inspect.lua, Line: 141, Error: call unroll limit reached, Count: 6
File: files.lua, Line: 983, Error: leaving loop in root trace, Count: 6
File: scope.lua, Line: 218, Error: leaving loop in root trace, Count: 6
File: json.lua, Line: 200, Error: leaving loop in root trace, Count: 6
File: global.lua, Line: 707, Error: NYI: bytecode FNEW  , Count: 6
File: luadoc.lua, Line: 1972, Error: leaving loop in root trace, Count: 6
File: 0x01d10bed0010, Line: 4, Error: leaving loop in root trace, Count: 6
File: luadoc.lua, Line: 1853, Error: leaving loop in root trace, Count: 6
File: compile.lua, Line: 2011, Error: down-recursion, restarting, Count: 6
File: compile.lua, Line: 3471, Error: inner loop in root trace, Count: 6
File: inspect.lua, Line: 148, Error: inner loop in root trace, Count: 5
File: inspect.lua, Line: 137, Error: leaving loop in root trace, Count: 5
File: scope.lua, Line: 74, Error: inner loop in root trace, Count: 5
File: luadoc.lua, Line: 1095, Error: inner loop in root trace, Count: 5
File: compile.lua, Line: 1546, Error: leaving loop in root trace, Count: 5
File: 0x01d1090b8dc0, Line: 3, Error: loop unroll limit reached, Count: 5
File: compile.lua, Line: 3498, Error: leaving loop in root trace, Count: 5
File: compile.lua, Line: 3471, Error: loop unroll limit reached, Count: 5
File: compile.lua, Line: 2199, Error: loop unroll limit reached, Count: 5
File: provider.lua, Line: 80, Error: NYI: bytecode FNEW  , Count: 4
File: inspect.lua, Line: 151, Error: leaving loop in root trace, Count: 4
File: scope.lua, Line: 232, Error: leaving loop in root trace, Count: 4
File: luadoc.lua, Line: 2023, Error: leaving loop in root trace, Count: 4
File: scope.lua, Line: 75, Error: inner loop in root trace, Count: 4
File: luadoc.lua, Line: 2009, Error: inner loop in root trace, Count: 4
File: compile.lua, Line: 2075, Error: inner loop in root trace, Count: 4
File: guide.lua, Line: 532, Error: loop unroll limit reached, Count: 4
File: compile.lua, Line: 721, Error: leaving loop in root trace, Count: 4
File: compile.lua, Line: 2080, Error: persistent type instability, Count: 4
File: 0x01d1090b9100, Line: 4, Error: leaving loop in root trace, Count: 4
File: guide.lua, Line: 337, Error: inner loop in root trace, Count: 4
File: 0x01d1086daf00, Line: 3, Error: loop unroll limit reached, Count: 4
File: variable.lua, Line: 392, Error: leaving loop in root trace, Count: 4
File: variable.lua, Line: 71, Error: leaving loop in root trace, Count: 4
File: compile.lua, Line: 1144, Error: leaving loop in root trace, Count: 4
File: compile.lua, Line: 3908, Error: loop unroll limit reached, Count: 4
File: compile.lua, Line: 3505, Error: down-recursion, restarting, Count: 4
File: guide.lua, Line: 532, Error: persistent type instability, Count: 4
File: compile.lua, Line: 1481, Error: leaving loop in root trace, Count: 4
File: compile.lua, Line: 1593, Error: inner loop in root trace, Count: 4
File: luadoc.lua, Line: 1911, Error: inner loop in root trace, Count: 4
File: guide.lua, Line: 783, Error: leaving loop in root trace, Count: 4
File: 0x01d1086d96a0, Line: 4, Error: loop unroll limit reached, Count: 4
File: luadoc.lua, Line: 1795, Error: inner loop in root trace, Count: 4
File: compile.lua, Line: 302, Error: loop unroll limit reached, Count: 4
File: luadoc.lua, Line: 2132, Error: NYI: bytecode FNEW  , Count: 4
File: gitignore.lua, Line: 76, Error: leaving loop in root trace, Count: 3
File: workspace.lua, Line: 103, Error: NYI: bytecode FNEW  , Count: 3
File: files.lua, Line: 979, Error: inner loop in root trace, Count: 3
File: json.lua, Line: 185, Error: leaving loop in root trace, Count: 3
File: json.lua, Line: 113, Error: leaving loop in root trace, Count: 3
File: compile.lua, Line: 2727, Error: loop unroll limit reached, Count: 3
File: compile.lua, Line: 978, Error: loop unroll limit reached, Count: 3
File: 0x01d10becdec0, Line: 4, Error: leaving loop in root trace, Count: 3
File: compile.lua, Line: 2095, Error: leaving loop in root trace, Count: 3
File: luadoc.lua, Line: 2089, Error: inner loop in root trace, Count: 3
File: global.lua, Line: 184, Error: inner loop in root trace, Count: 3
File: luadoc.lua, Line: 2163, Error: NYI: bytecode UCLO  , Count: 3
File: 0x01d1086daf00, Line: 6, Error: leaving loop in root trace, Count: 3
File: compile.lua, Line: 658, Error: inner loop in root trace, Count: 3
File: compile.lua, Line: 3184, Error: leaving loop in root trace, Count: 3
File: 0x01d10b89bc90, Line: 8, Error: leaving loop in root trace, Count: 3
File: compile.lua, Line: 3920, Error: loop unroll limit reached, Count: 3
File: 0x01d10c8a98c0, Line: 5, Error: leaving loop in root trace, Count: 3
File: compile.lua, Line: 577, Error: leaving loop in root trace, Count: 3
File: compile.lua, Line: 414, Error: inner loop in root trace, Count: 3
File: inspect.lua, Line: 132, Error: inner loop in root trace, Count: 2
File: progress.lua, Line: 149, Error: leaving loop in root trace, Count: 2
File: files.lua, Line: 908, Error: leaving loop in root trace, Count: 2
File: language.lua, Line: 68, Error: NYI: bytecode FNEW  , Count: 2
File: await.lua, Line: 185, Error: NYI: bytecode FNEW  , Count: 2
File: 0x01d108c59670, Line: 7, Error: leaving loop in root trace, Count: 2
File: luadoc.lua, Line: 582, Error: NYI: bytecode UCLO  , Count: 2
File: files.lua, Line: 169, Error: leaving loop in root trace, Count: 2
File: global.lua, Line: 735, Error: leaving loop in root trace, Count: 2
File: compile.lua, Line: 4084, Error: NYI: bytecode FNEW  , Count: 2
File: luadoc.lua, Line: 583, Error: NYI: bytecode UCLO  , Count: 2
File: luadoc.lua, Line: 590, Error: NYI: bytecode UCLO  , Count: 2
File: guide.lua, Line: 775, Error: leaving loop in root trace, Count: 2
File: loading.lua, Line: 114, Error: NYI: bytecode FNEW  , Count: 2
File: gitignore.lua, Line: 95, Error: error thrown or hook called during recording, Count: 2
File: compile.lua, Line: 3902, Error: loop unroll limit reached, Count: 2
File: variable.lua, Line: 220, Error: leaving loop in root trace, Count: 2
File: luadoc.lua, Line: 2011, Error: inner loop in root trace, Count: 2
File: guide.lua, Line: 523, Error: NYI: bytecode FNEW  , Count: 2
File: utility.lua, Line: 727, Error: NYI: bytecode UCLO  , Count: 2
File: compile.lua, Line: 3632, Error: leaving loop in root trace, Count: 2
File: luadoc.lua, Line: 1854, Error: loop unroll limit reached, Count: 2
File: compile.lua, Line: 2764, Error: inner loop in root trace, Count: 2
File: 0x01d1082d30b0, Line: 8, Error: leaving loop in root trace, Count: 2
File: 0x01d108f354e0, Line: 9, Error: leaving loop in root trace, Count: 2
File: 0x01d109b0b9d0, Line: 4, Error: leaving loop in root trace, Count: 2
File: luadoc.lua, Line: 2135, Error: NYI: bytecode FNEW  , Count: 2
File: guide.lua, Line: 541, Error: NYI: bytecode UCLO  , Count: 2
File: guide.lua, Line: 540, Error: leaving loop in root trace, Count: 2
File: await.lua, Line: 152, Error: NYI: bytecode VARG  , Count: 2
File: 0x01d10bece3a0, Line: 3, Error: inner loop in root trace, Count: 2
File: compile.lua, Line: 2199, Error: inner loop in root trace, Count: 2
File: plugin.lua, Line: 51, Error: leaving loop in root trace, Count: 2
File: global.lua, Line: 710, Error: NYI: bytecode FNEW  , Count: 2
File: 0x01d1090b8dc0, Line: 3, Error: inner loop in root trace, Count: 2
File: luadoc.lua, Line: 2251, Error: leaving loop in root trace, Count: 2
File: 0x01d1086d96a0, Line: 4, Error: inner loop in root trace, Count: 2
File: 0x01d108f351b0, Line: 6, Error: leaving loop in root trace, Count: 2
File: luadoc.lua, Line: 2186, Error: NYI: bytecode FNEW  , Count: 2
File: capability.lua, Line: 18, Error: inner loop in root trace, Count: 1
File: capability.lua, Line: 42, Error: error thrown or hook called during recording, Count: 1
File: capability.lua, Line: 46, Error: leaving loop in root trace, Count: 1
File: inspect.lua, Line: 274, Error: inner loop in root trace, Count: 1
File: config.lua, Line: 209, Error: inner loop in root trace, Count: 1
File: template.lua, Line: 179, Error: inner loop in root trace, Count: 1
File: workspace.lua, Line: 34, Error: leaving loop in root trace, Count: 1
File: log.lua, Line: 59, Error: inner loop in root trace, Count: 1
File: compile.lua, Line: 3195, Error: leaving loop in root trace, Count: 1
File: luadoc.lua, Line: 2021, Error: inner loop in root trace, Count: 1
File: 0x01d108503440, Line: 16, Error: leaving loop in root trace, Count: 1
File: guide.lua, Line: 813, Error: leaving loop in root trace, Count: 1
File: guide.lua, Line: 807, Error: leaving loop in root trace, Count: 1
File: utility.lua, Line: 848, Error: NYI: bytecode FNEW  , Count: 1
File: node.lua, Line: 67, Error: inner loop in root trace, Count: 1
File: luadoc.lua, Line: 1795, Error: loop unroll limit reached, Count: 1
File: guide.lua, Line: 204, Error: inner loop in root trace, Count: 1
File: timer.lua, Line: 96, Error: leaving loop in root trace, Count: 1
File: pub.lua, Line: 203, Error: error thrown or hook called during recording, Count: 1
File: loading.lua, Line: 31, Error: error thrown or hook called during recording, Count: 1
File: config.lua, Line: 189, Error: error thrown or hook called during recording, Count: 1
File: config.lua, Line: 161, Error: error thrown or hook called during recording, Count: 1
File: gitignore.lua, Line: 176, Error: error thrown or hook called during recording, Count: 1
File: service.lua, Line: 158, Error: error thrown or hook called during recording, Count: 1
File: workspace.lua, Line: 91, Error: error thrown or hook called during recording, Count: 1
File: files.lua, Line: 819, Error: error thrown or hook called during recording, Count: 1
File: loading.lua, Line: 70, Error: error thrown or hook called during recording, Count: 1
File: timer.lua, Line: 228, Error: error thrown or hook called during recording, Count: 1
File: config.lua, Line: 34, Error: error thrown or hook called during recording, Count: 1
File: workspace.lua, Line: 345, Error: error thrown or hook called during recording, Count: 1
File: guide.lua, Line: 776, Error: loop unroll limit reached, Count: 1
File: json.lua, Line: 179, Error: inner loop in root trace, Count: 1
File: utility.lua, Line: 220, Error: leaving loop in root trace, Count: 1
File: 0x01d1090b85a0, Line: 3, Error: loop unroll limit reached, Count: 1
File: progress.lua, Line: 143, Error: inner loop in root trace, Count: 1
File: 0x01d17e87c390, Line: 8, Error: leaving loop in root trace, Count: 1
File: luadoc.lua, Line: 1956, Error: inner loop in root trace, Count: 1
File: luadoc.lua, Line: 870, Error: loop unroll limit reached, Count: 1
File: compile.lua, Line: 2080, Error: loop unroll limit reached, Count: 1
File: 0x01d10bece3a0, Line: 3, Error: loop unroll limit reached, Count: 1
File: compile.lua, Line: 2568, Error: loop unroll limit reached, Count: 1
File: utility.lua, Line: 215, Error: leaving loop in root trace, Count: 1
File: compile.lua, Line: 2075, Error: loop unroll limit reached, Count: 1
File: 0x01d1090ab5a0, Line: 3, Error: inner loop in root trace, Count: 1
File: guide.lua, Line: 337, Error: loop unroll limit reached, Count: 1
File: compile.lua, Line: 4122, Error: leaving loop in root trace, Count: 1
File: scope.lua, Line: 87, Error: leaving loop in root trace, Count: 1
File: guide.lua, Line: 779, Error: inner loop in root trace, Count: 1
File: variable.lua, Line: 227, Error: leaving loop in root trace, Count: 1
File: 0x01d1086daf00, Line: 3, Error: inner loop in root trace, Count: 1
File: global.lua, Line: 187, Error: leaving loop in root trace, Count: 1
File: luadoc.lua, Line: 1656, Error: error thrown or hook called during recording, Count: 1
File: gitignore.lua, Line: 149, Error: leaving loop in root trace, Count: 1
File: 0x01d10becdec0, Line: 3, Error: loop unroll limit reached, Count: 1
File: compile.lua, Line: 1722, Error: down-recursion, restarting, Count: 1
File: compile.lua, Line: 2577, Error: loop unroll limit reached, Count: 1
File: compile.lua, Line: 1394, Error: error thrown or hook called during recording, Count: 1
File: compile.lua, Line: 571, Error: loop unroll limit reached, Count: 1
File: pub.lua, Line: 138, Error: NYI: bytecode FNEW  , Count: 1
File: files.lua, Line: 722, Error: NYI: bytecode FNEW  , Count: 1
File: luadoc.lua, Line: 1975, Error: loop unroll limit reached, Count: 1
File: compile.lua, Line: 4020, Error: inner loop in root trace, Count: 1
File: guide.lua, Line: 572, Error: inner loop in root trace, Count: 1
File: luadoc.lua, Line: 2138, Error: loop unroll limit reached, Count: 1
File: pub.lua, Line: 203, Error: inner loop in root trace, Count: 1
lewis6991 commented 1 month ago

Just to note that calls into C code cannot be JIT compiled, so if LuaLS calls into C a lot (into bee.lua), then it's likely the JIT isn't able to do much.

Are you sure about this? I am pretty sure that it can be JIT compiled, the C calls become inlined

Pretty sure. Calls into C can't be JIT compiled, but calls into C via the FFI can.

Read the top of: https://luajit.org/ext_ffi.html

The FFI library is tightly integrated into LuaJIT (it's not available as a separate module). The code generated by the JIT-compiler for accesses to C data structures from Lua code is on par with the code a C compiler would generate. Calls to C functions can be inlined in JIT-compiled code, unlike calls to functions bound via the classic Lua/C API.

bee.lua uses the "classic Lua/C API".

CppCXY commented 1 month ago

bee.lua uses the "classic Lua/C API".

a bit mistaken; the luajit porting work was done on my rust version, not bee.lua. The entire bee API was implemented by me using rust. However, the conclusion remains unchanged: it is indeed a C API call. From the jit trace data, it appears that the significant performance degradation is due to too many jit failures, rather than an issue with the C API itself.

C3pa commented 1 month ago

Ok, there is some space to rearrange the code a bit to work around the NYI (not yet implemented) bytecodes. The FNEW stands for closure construction. Maybe the most offending closures can be made free functions instead? Particularly https://github.com/LuaLS/lua-language-server/blob/f6dcbcc08d8d07e4a4bb61dfd3c9b367078818f1/script/parser/luadoc.lua#L896C20-L896C30`pushResume`

Resource: https://chrisfls.github.io/luajit-wiki/NYI/

tmillr commented 1 month ago

Resource: https://chrisfls.github.io/luajit-wiki/NYI/

Is this up-to-date?

tmillr commented 1 month ago

Just to note that calls into C code cannot be JIT compiled, so if LuaLS calls into C a lot (into bee.lua), then it's likely the JIT isn't able to do much.

Are you sure about this? I am pretty sure that it can be JIT compiled, the C calls become inlined

From http://luajit.org/ext_ffi.html:

The FFI library allows calling external C functions and using C data structures from pure Lua code.

The FFI library largely obviates the need to write tedious manual Lua/C bindings in C. No need to learn a separate binding language — it parses plain C declarations! These can be cut-n-pasted from C header files or reference manuals. It's up to the task of binding large libraries without the need for dealing with fragile binding generators.

The FFI library is tightly integrated into LuaJIT (it's not available as a separate module). The code generated by the JIT-compiler for accesses to C data structures from Lua code is on par with the code a C compiler would generate. Calls to C functions can be inlined in JIT-compiled code, unlike calls to functions bound via the classic Lua/C API.

So it appears that to achieve best performance, you need to use the FFI to call non-Lua/pre-compiled functions. In that case, when the Lua is jit-compiled, the external calls to pre-compiled code will often be inlined and it will all get compiled as one binary/native (function).

Idk the finer details, but if I'm not mistaken, with the usual/classic Lua C api you are forced to use the Lua calling convention and Lua stack (for passing args, returns, etc.)? But with the FFI, you simply call regular C functions directly (which are not written to use the Lua stack at all), which forgoes the Lua stack entirely and uses the native calling convention/stack? So (for jit-compiled code) you not only get inlined calls, but you get to avoid the Lua stack completely (which is probably implemented in the heap) including all of the code which manages it. But the hard part (probably?) is taking advantage of all this and getting the jit settings just right, etc., in order to maximize your application's performance and offset the overhead of dynamic/runtime jit-compilation. Maybe some data structures need to be converted over to use native structs and arrays as well? (which may be managed/used/handled directly in Lua via luajit's builtin FFI)

My understanding is that C calls are inlined in jit-compiled Lua if calling C functions via the FFI. For best performance however, I believe you need to write "native" C functions (i.e. written without Lua in mind, written without using Lua's stack/calling convention, and written using native data types/structures) as much as possible. So perhaps taking full advantage of all of this would require a decent amount of the codebase to be rewritten? OTOH, I thought that simply switching to luajit runtime alone would have been enough to improve performance, but maybe I'm wrong.

C3pa commented 1 month ago

Resource: https://chrisfls.github.io/luajit-wiki/NYI/

Is this up-to-date?

That's someone's backup of the last time this page was on LuaJIT's wiki, which the uploader got from archive.org. That's as up-to-date as it can be. LuaJIT's master branch has recently had some development, but IIRC none pertaining to implementing any remaining NYI bytecodes.

Frityet commented 1 month ago

bee.lua uses the "classic Lua/C API".

whoops i thought you meant using FFI

OTOH, I thought that simply switching to luajit runtime alone would have been enough to improve performance, but maybe I'm wrong.

Same, I think its due to the frequency of the C api calls, and if its inlined with FFI (or fully rewritten to only use FFI) it could be truly unleashed

tomlau10 commented 1 month ago

OTOH, I thought that simply switching to luajit runtime alone would have been enough to improve performance, but maybe I'm wrong.

Same, I think its due to the frequency of the C api calls, and if its inlined with FFI (or fully rewritten to only use FFI) it could be truly unleashed

From my benchmark above: https://github.com/LuaLS/lua-language-server/issues/2879#issuecomment-2385026553

CppCXY commented 1 month ago

I think continuing to work on this doesn't seem promising. I plan to completely rewrite a language server in Rust, but it won't be LuaLS. If necessary, we can integrate the parser part into the luals_rust project later and see the results.

CppCXY commented 1 month ago

I just created this repository. If you're interested, please follow it: https://github.com/CppCXY/emmylua-analyzer-rust

ofseed commented 1 month ago

Would you implement it in a way that supports LuaCATS? Although I am not a big fan of this annotation system, I think a unified annotation system (even if it comes from the community) would benefit the ecosystem.

CppCXY commented 1 month ago

Would you implement it in a way that supports LuaCATS? Although I am not a big fan of this annotation system, I think a unified annotation system (even if it comes from the community) would benefit the ecosystem.

Of course, I will support LuaCATS, but I will also add some of my own features. In fact, I have implemented this many times in different languages, so it's not very difficult for me.