Skip to content

Commit 2efece0

Browse files
authored
Merge pull request #8 from CppCXY/gc
Gc
2 parents c11ca98 + c898905 commit 2efece0

24 files changed

+2736
-743
lines changed

PERFORMANCE_REPORT.md

Lines changed: 167 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,189 @@
1-
# luars 性能报告
1+
# LuaRS 性能报告
22

3-
**测试日期**: 2024年12月4日
4-
**对比版本**: luars vs Lua 5.4.6
5-
**总运行时间**: luars 16.55s vs Lua 5.4 10.02s (65%)
3+
## 概述
64

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`
811

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%** 的性能。
7719

7820
---
7921

80-
## 🟡 中等差距项目(性能差距 30-50%)
22+
## 详细对比
8123

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+
### 算术运算
9225

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% |
9469

95-
## 🟢 luars 表现更好的项目
70+
### 元表 (fasttm 优化后)
9671

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% ✓ |
105105

106106
---
107107

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 同等水平
109153

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:
114159

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%
119166

120-
### Phase 3: 循环和变量访问
121-
7. [ ] while/repeat-until 循环优化
122-
8. [ ] 全局变量访问优化
123-
9. [ ] upvalue 访问优化
167+
---
168+
169+
## 需要改进的领域
124170

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% - 包装函数创建较慢
129176

130177
---
131178

132-
## 技术笔记
179+
## 结论
180+
181+
luars 作为 Rust 实现的 Lua 解释器,在整体性能上达到官方 Lua 5.4 的 66%。部分操作(闭包创建、表插入、协程 yield、错误处理)已经超越 Lua 5.4。
133182

134-
### 已完成的优化
135-
- [x] Return 语句字节码优化(消除多余 MOVE 指令)
136-
- [x] TAILCALL 字节码修复
137-
- [x] `get_result_reg` 辅助函数统一寄存器分配
183+
实现的 fasttm 优化有效解决了"有元表但无元方法"场景的性能问题,使该场景达到 Lua 5.4 水平。
138184

139-
### 待分析的问题
140-
- 闭包迭代器为何如此慢?需要 profiling
141-
- pcall 的成功路径在做什么额外工作?
142-
- 元方法查找是否有缓存?
185+
未来优化方向:
186+
1. 优化函数调用栈管理
187+
2. 改进全局变量 `_ENV` 查找路径
188+
3. 优化元方法调用本身的开销
189+
4. 改进 pcall 成功路径的性能

0 commit comments

Comments
 (0)