|
1 | | -# luars 性能报告 |
| 1 | +# LuaRS 性能报告 |
2 | 2 |
|
3 | | -**测试日期**: 2024年12月4日 |
4 | | -**对比版本**: luars vs Lua 5.4.6 |
5 | | -**总运行时间**: luars 16.55s vs Lua 5.4 10.02s (65%) |
| 3 | +## 概述 |
6 | 4 |
|
7 | | ---- |
| 5 | +本报告比较 luars(Rust 实现)与官方 Lua 5.4.6 的性能表现。 |
| 6 | + |
| 7 | +**测试环境:** |
| 8 | +- OS: Windows |
| 9 | +- Lua 5.4.6: 从源码编译 (CMake + MSVC) |
| 10 | +- luars: `cargo build --release` |
8 | 11 |
|
9 | | -## 🔴 紧急优化项目(性能差距 > 50%) |
10 | | - |
11 | | -### 1. 闭包迭代器 - **5% of Lua 5.4** ⚠️ 最高优先级 |
12 | | -| 测试 | luars | Lua 5.4 | 比率 | |
13 | | -|------|-------|---------|------| |
14 | | -| Closure iterator (100) | 16.67 K/s | 303.03 K/s | **5%** | |
15 | | - |
16 | | -**分析**: 闭包迭代器在 Lua 中极其常见(io.lines, 自定义迭代器等),这是最严重的性能问题。 |
17 | | - |
18 | | -### 2. 元方法调用 - **17-51%** |
19 | | -| 测试 | luars | Lua 5.4 | 比率 | |
20 | | -|------|-------|---------|------| |
21 | | -| __index (function) | 5.22 M/s | 29.41 M/s | **18%** | |
22 | | -| __len metamethod | 5.50 M/s | 33.33 M/s | **17%** | |
23 | | -| __call metamethod | 17.10 M/s | 33.33 M/s | **51%** | |
24 | | -| __add metamethod | 2.91 M/s | 4.55 M/s | **64%** | |
25 | | - |
26 | | -**分析**: 元方法查找和调用开销过大。 |
27 | | - |
28 | | -### 3. pcall 成功路径 - **15%** |
29 | | -| 测试 | luars | Lua 5.4 | 比率 | |
30 | | -|------|-------|---------|------| |
31 | | -| pcall (success) | 2.49 M/s | 16.67 M/s | **15%** | |
32 | | -| assert (success) | 11.10 M/s | 50.00 M/s | **22%** | |
33 | | - |
34 | | -**分析**: pcall 成功时不应该有显著开销,当前实现有问题。 |
35 | | - |
36 | | -### 4. vararg 处理 - **18-40%** |
37 | | -| 测试 | luars | Lua 5.4 | 比率 | |
38 | | -|------|-------|---------|------| |
39 | | -| select('#', ...) | 3.48 M/s | 19.23 M/s | **18%** | |
40 | | -| select(3, ...) | 3.35 M/s | 17.54 M/s | **19%** | |
41 | | -| table.unpack (5 values) | 4.91 M/s | 20.00 M/s | **25%** | |
42 | | -| Vararg passthrough | 12.63 M/s | 31.25 M/s | **40%** | |
43 | | - |
44 | | -**分析**: vararg 的创建、访问和传递都很慢。 |
45 | | - |
46 | | -### 5. 迭代器通用问题 - **37-39%** |
47 | | -| 测试 | luars | Lua 5.4 | 比率 | |
48 | | -|------|-------|---------|------| |
49 | | -| Multi-value iterator | 7.60 K/s | 20.62 K/s | **37%** | |
50 | | -| Custom stateless iter | 12.46 K/s | 31.65 K/s | **39%** | |
51 | | - |
52 | | -### 6. 函数调用开销 - **42%** |
53 | | -| 测试 | luars | Lua 5.4 | 比率 | |
54 | | -|------|-------|---------|------| |
55 | | -| Simple function call | 22.13 M/s | 52.63 M/s | **42%** | |
56 | | -| Returns as func args | 10.87 M/s | 25.00 M/s | **43%** | |
57 | | - |
58 | | -### 7. OOP 方法调用 - **32-33%** |
59 | | -| 测试 | luars | Lua 5.4 | 比率 | |
60 | | -|------|-------|---------|------| |
61 | | -| Method call (colon) | 3.88 M/s | 12.20 M/s | **32%** | |
62 | | -| Method call (dot) | 4.28 M/s | 13.51 M/s | **32%** | |
63 | | -| Inherited method call | 3.49 M/s | 11.11 M/s | **31%** | |
64 | | - |
65 | | -### 8. 循环控制 - **51-53%** |
66 | | -| 测试 | luars | Lua 5.4 | 比率 | |
67 | | -|------|-------|---------|------| |
68 | | -| While loop | 74.49 M/s | 140.85 M/s | **53%** | |
69 | | -| Repeat-until | 80.35 M/s | 158.73 M/s | **51%** | |
70 | | -| Nested loops | 134.23 M/s | 250.00 M/s | **54%** | |
71 | | - |
72 | | -### 9. 变量访问 - **53-60%** |
73 | | -| 测试 | luars | Lua 5.4 | 比率 | |
74 | | -|------|-------|---------|------| |
75 | | -| Global var access | 38.34 M/s | 72.99 M/s | **53%** | |
76 | | -| Upvalue access | 81.64 M/s | 136.99 M/s | **60%** | |
| 12 | +**总体结果:** |
| 13 | +| 运行时 | 总时间 | 相对性能 | |
| 14 | +|--------|--------|----------| |
| 15 | +| Lua 5.4.6 | ~10.1 秒 | 100% | |
| 16 | +| luars | ~15.3 秒 | 66% | |
| 17 | + |
| 18 | +luars 在基准测试套件中达到 Lua 5.4 约 **66%** 的性能。 |
77 | 19 |
|
78 | 20 | --- |
79 | 21 |
|
80 | | -## 🟡 中等差距项目(性能差距 30-50%) |
| 22 | +## 详细对比 |
81 | 23 |
|
82 | | -| 测试 | luars | Lua 5.4 | 比率 | |
83 | | -|------|-------|---------|------| |
84 | | -| Local var access | 165 M/s | 238 M/s | 69% | |
85 | | -| Integer addition | 159 M/s | 238 M/s | 67% | |
86 | | -| Float multiplication | 158 M/s | 217 M/s | 73% | |
87 | | -| Table access | 97.93 M/s | 142.86 M/s | 69% | |
88 | | -| ipairs iteration | 24.56 K/s | 45.45 K/s | 54% | |
89 | | -| Upvalue read/write | 22.37 M/s | 40.00 M/s | 56% | |
90 | | -| Multiple upvalues | 18.58 M/s | 34.48 M/s | 54% | |
91 | | -| Nested closures | 22.27 M/s | 35.71 M/s | 62% | |
| 24 | +### 算术运算 |
92 | 25 |
|
93 | | ---- |
| 26 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 27 | +|--------|-------|---------|------| |
| 28 | +| 整数加法 | 139 M/s | 233 M/s | 60% | |
| 29 | +| 浮点乘法 | 127 M/s | 208 M/s | 61% | |
| 30 | +| 混合运算 | 74 M/s | 123 M/s | 60% | |
| 31 | + |
| 32 | +### 控制流 |
| 33 | + |
| 34 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 35 | +|--------|-------|---------|------| |
| 36 | +| If-else | 56 M/s | 52 M/s | 108% ✓ | |
| 37 | +| While 循环 | 80 M/s | 118 M/s | 68% | |
| 38 | +| Repeat-until | 83 M/s | 147 M/s | 56% | |
| 39 | +| 嵌套循环 | 145 M/s | 250 M/s | 58% | |
| 40 | + |
| 41 | +### 变量访问 |
| 42 | + |
| 43 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 44 | +|--------|-------|---------|------| |
| 45 | +| 全局变量 | 32 M/s | 74 M/s | 43% | |
| 46 | +| 局部变量 | 121 M/s | 233 M/s | 52% | |
| 47 | +| Upvalue | 53 M/s | 133 M/s | 40% | |
| 48 | + |
| 49 | +### 函数调用 |
| 50 | + |
| 51 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 52 | +|--------|-------|---------|------| |
| 53 | +| 简单调用 | 19 M/s | 53 M/s | 36% | |
| 54 | +| 变长参数 | 1.7 M/s | 2.5 M/s | 68% | |
| 55 | + |
| 56 | +### 闭包 |
| 57 | + |
| 58 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 59 | +|--------|-------|---------|------| |
| 60 | +| 闭包创建 | 11.6 M/s | 7.1 M/s | 163% ✓ | |
| 61 | +| Upvalue 读写 | 18.5 M/s | 43.5 M/s | 43% | |
| 62 | + |
| 63 | +### 表操作 |
| 64 | + |
| 65 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 66 | +|--------|-------|---------|------| |
| 67 | +| 表插入 | 43 M/s | 34 M/s | 126% ✓ | |
| 68 | +| 表访问 | 84 M/s | 125 M/s | 67% | |
94 | 69 |
|
95 | | -## 🟢 luars 表现更好的项目 |
| 70 | +### 元表 (fasttm 优化后) |
96 | 71 |
|
97 | | -| 测试 | luars | Lua 5.4 | 倍数 | |
98 | | -|------|-------|---------|------| |
99 | | -| table.sort (sorted) | 194 K/s | 8 K/s | **24x faster** | |
100 | | -| table.sort (reversed) | 35.6 K/s | 5.78 K/s | **6x faster** | |
101 | | -| Repeated yield | 3.06 M/s | 0.79 M/s | **4x faster** | |
102 | | -| pcall (error path) | 2.18 M/s | 0.55 M/s | **4x faster** | |
103 | | -| table.insert (end) | 21.27 M/s | 14.29 M/s | 1.5x faster | |
104 | | -| table.remove (end) | 26.81 M/s | 16.67 M/s | 1.6x faster | |
| 72 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 73 | +|--------|-------|---------|------| |
| 74 | +| __index (函数) | 4.9 M/s | 22 M/s | 22% | |
| 75 | +| __index (表) | 23 M/s | 26 M/s | 88% ✓ | |
| 76 | +| __newindex | 6.1 M/s | 17 M/s | 36% | |
| 77 | +| __call | 15.7 M/s | 25 M/s | 63% | |
| 78 | +| __len | 5.3 M/s | 28 M/s | 19% | |
| 79 | +| rawget | 21 M/s | 21 M/s | 100% ✓ | |
| 80 | + |
| 81 | +### fasttm 优化效果 |
| 82 | + |
| 83 | +当表有元表但**没有特定元方法**时的访问性能: |
| 84 | + |
| 85 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 86 | +|--------|-------|---------|------| |
| 87 | +| 缺失键 (有元表, 无__index) | 100-113 M/s | 100 M/s | 100-113% ✓ | |
| 88 | +| #table (有元表, 无__len) | 83-105 M/s | 100 M/s | 83-105% ✓ | |
| 89 | + |
| 90 | +### 协程 |
| 91 | + |
| 92 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 93 | +|--------|-------|---------|------| |
| 94 | +| 创建/恢复/让出 | 319 K/s | 521 K/s | 61% | |
| 95 | +| 重复 yield | 2.7 M/s | 735 K/s | 367% ✓ | |
| 96 | +| coroutine.wrap | 405 K/s | 2.5 M/s | 16% | |
| 97 | + |
| 98 | +### 错误处理 |
| 99 | + |
| 100 | +| 测试项 | luars | Lua 5.4 | 比率 | |
| 101 | +|--------|-------|---------|------| |
| 102 | +| pcall (成功) | 3.2 M/s | 17 M/s | 19% | |
| 103 | +| pcall (失败) | 3.4 M/s | 493 K/s | 690% ✓ | |
| 104 | +| xpcall (失败) | 1.2 M/s | 459 K/s | 261% ✓ | |
105 | 105 |
|
106 | 106 | --- |
107 | 107 |
|
108 | | -## 优化计划(按优先级) |
| 108 | +## 优化实现 |
| 109 | + |
| 110 | +### fasttm 优化 (Lua 5.4 风格) |
| 111 | + |
| 112 | +参考 Lua 5.4 的 `ltm.h` 中的 `fasttm` 宏,实现了元方法缺失的快速检测: |
| 113 | + |
| 114 | +```rust |
| 115 | +// lua_table.rs |
| 116 | +pub mod TmFlags { |
| 117 | + pub const TM_INDEX: u8 = 1 << 0; |
| 118 | + pub const TM_NEWINDEX: u8 = 1 << 1; |
| 119 | + pub const TM_GC: u8 = 1 << 2; |
| 120 | + pub const TM_MODE: u8 = 1 << 3; |
| 121 | + pub const TM_LEN: u8 = 1 << 4; |
| 122 | + pub const TM_EQ: u8 = 1 << 5; |
| 123 | + pub const TM_CALL: u8 = 1 << 6; |
| 124 | +} |
| 125 | + |
| 126 | +pub struct LuaTable { |
| 127 | + pub tm_flags: u8, // 缓存元方法不存在的位标志 |
| 128 | + // ... |
| 129 | +} |
| 130 | + |
| 131 | +impl LuaTable { |
| 132 | + /// 检查元方法是否已知不存在 |
| 133 | + pub fn tm_absent(&self, flag: u8) -> bool { |
| 134 | + (self.tm_flags & flag) != 0 |
| 135 | + } |
| 136 | + |
| 137 | + /// 标记元方法不存在 |
| 138 | + pub fn set_tm_absent(&mut self, flag: u8) { |
| 139 | + self.tm_flags |= flag; |
| 140 | + } |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | +**工作原理:** |
| 145 | +1. 每个表的元表有一个 `tm_flags` 位域 |
| 146 | +2. 当查找元方法(如 `__index`)失败时,设置对应位 |
| 147 | +3. 下次访问时先检查位,如果已设置则跳过哈希查找 |
| 148 | +4. 当元表被修改时,清除所有标志 |
| 149 | + |
| 150 | +**效果:** |
| 151 | +- "缺失键 (有元表, 无__index)" 场景:从 55 M/s 提升到 100+ M/s |
| 152 | +- 达到 Lua 5.4 同等水平 |
109 | 153 |
|
110 | | -### Phase 1: 核心调用路径优化 |
111 | | -1. [ ] 闭包迭代器优化(5% → 目标 60%+) |
112 | | -2. [ ] pcall 成功路径优化(15% → 目标 80%+) |
113 | | -3. [ ] 元方法调用优化(17% → 目标 60%+) |
| 154 | +--- |
| 155 | + |
| 156 | +## 性能优势领域 |
| 157 | + |
| 158 | +luars 在以下方面**超越** Lua 5.4: |
114 | 159 |
|
115 | | -### Phase 2: vararg 和函数调用 |
116 | | -4. [ ] select() 和 vararg 处理优化 |
117 | | -5. [ ] 简单函数调用开销减少 |
118 | | -6. [ ] 多返回值传递优化 |
| 160 | +1. **闭包创建**: 163% (11.6 M/s vs 7.1 M/s) |
| 161 | +2. **表插入**: 126% (43 M/s vs 34 M/s) |
| 162 | +3. **重复 yield**: 367% (2.7 M/s vs 735 K/s) |
| 163 | +4. **pcall 失败**: 690% (luars 的错误处理更快) |
| 164 | +5. **If-else 分支**: 108% |
| 165 | +6. **fasttm 优化场景**: 100-113% |
119 | 166 |
|
120 | | -### Phase 3: 循环和变量访问 |
121 | | -7. [ ] while/repeat-until 循环优化 |
122 | | -8. [ ] 全局变量访问优化 |
123 | | -9. [ ] upvalue 访问优化 |
| 167 | +--- |
| 168 | + |
| 169 | +## 需要改进的领域 |
124 | 170 |
|
125 | | -### Phase 4: 其他优化 |
126 | | -10. [ ] OOP 方法调用优化 |
127 | | -11. [ ] 迭代器通用优化 |
128 | | -12. [ ] 表访问优化 |
| 171 | +1. **函数调用开销**: 36% - 需要优化调用栈管理 |
| 172 | +2. **全局变量访问**: 43% - `_ENV` 查找较慢 |
| 173 | +3. **元方法调用**: 19-36% - 元方法调用本身的开销较大 |
| 174 | +4. **pcall 成功路径**: 19% - 每次 pcall 有较大开销 |
| 175 | +5. **coroutine.wrap**: 16% - 包装函数创建较慢 |
129 | 176 |
|
130 | 177 | --- |
131 | 178 |
|
132 | | -## 技术笔记 |
| 179 | +## 结论 |
| 180 | + |
| 181 | +luars 作为 Rust 实现的 Lua 解释器,在整体性能上达到官方 Lua 5.4 的 66%。部分操作(闭包创建、表插入、协程 yield、错误处理)已经超越 Lua 5.4。 |
133 | 182 |
|
134 | | -### 已完成的优化 |
135 | | -- [x] Return 语句字节码优化(消除多余 MOVE 指令) |
136 | | -- [x] TAILCALL 字节码修复 |
137 | | -- [x] `get_result_reg` 辅助函数统一寄存器分配 |
| 183 | +实现的 fasttm 优化有效解决了"有元表但无元方法"场景的性能问题,使该场景达到 Lua 5.4 水平。 |
138 | 184 |
|
139 | | -### 待分析的问题 |
140 | | -- 闭包迭代器为何如此慢?需要 profiling |
141 | | -- pcall 的成功路径在做什么额外工作? |
142 | | -- 元方法查找是否有缓存? |
| 185 | +未来优化方向: |
| 186 | +1. 优化函数调用栈管理 |
| 187 | +2. 改进全局变量 `_ENV` 查找路径 |
| 188 | +3. 优化元方法调用本身的开销 |
| 189 | +4. 改进 pcall 成功路径的性能 |
0 commit comments