Skip to content
Merged

Gc #8

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 167 additions & 120 deletions PERFORMANCE_REPORT.md
Original file line number Diff line number Diff line change
@@ -1,142 +1,189 @@
# luars 性能报告
# LuaRS 性能报告

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

---
本报告比较 luars(Rust 实现)与官方 Lua 5.4.6 的性能表现。

**测试环境:**
- OS: Windows
- Lua 5.4.6: 从源码编译 (CMake + MSVC)
- luars: `cargo build --release`

## 🔴 紧急优化项目(性能差距 > 50%)

### 1. 闭包迭代器 - **5% of Lua 5.4** ⚠️ 最高优先级
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| Closure iterator (100) | 16.67 K/s | 303.03 K/s | **5%** |

**分析**: 闭包迭代器在 Lua 中极其常见(io.lines, 自定义迭代器等),这是最严重的性能问题。

### 2. 元方法调用 - **17-51%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| __index (function) | 5.22 M/s | 29.41 M/s | **18%** |
| __len metamethod | 5.50 M/s | 33.33 M/s | **17%** |
| __call metamethod | 17.10 M/s | 33.33 M/s | **51%** |
| __add metamethod | 2.91 M/s | 4.55 M/s | **64%** |

**分析**: 元方法查找和调用开销过大。

### 3. pcall 成功路径 - **15%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| pcall (success) | 2.49 M/s | 16.67 M/s | **15%** |
| assert (success) | 11.10 M/s | 50.00 M/s | **22%** |

**分析**: pcall 成功时不应该有显著开销,当前实现有问题。

### 4. vararg 处理 - **18-40%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| select('#', ...) | 3.48 M/s | 19.23 M/s | **18%** |
| select(3, ...) | 3.35 M/s | 17.54 M/s | **19%** |
| table.unpack (5 values) | 4.91 M/s | 20.00 M/s | **25%** |
| Vararg passthrough | 12.63 M/s | 31.25 M/s | **40%** |

**分析**: vararg 的创建、访问和传递都很慢。

### 5. 迭代器通用问题 - **37-39%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| Multi-value iterator | 7.60 K/s | 20.62 K/s | **37%** |
| Custom stateless iter | 12.46 K/s | 31.65 K/s | **39%** |

### 6. 函数调用开销 - **42%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| Simple function call | 22.13 M/s | 52.63 M/s | **42%** |
| Returns as func args | 10.87 M/s | 25.00 M/s | **43%** |

### 7. OOP 方法调用 - **32-33%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| Method call (colon) | 3.88 M/s | 12.20 M/s | **32%** |
| Method call (dot) | 4.28 M/s | 13.51 M/s | **32%** |
| Inherited method call | 3.49 M/s | 11.11 M/s | **31%** |

### 8. 循环控制 - **51-53%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| While loop | 74.49 M/s | 140.85 M/s | **53%** |
| Repeat-until | 80.35 M/s | 158.73 M/s | **51%** |
| Nested loops | 134.23 M/s | 250.00 M/s | **54%** |

### 9. 变量访问 - **53-60%**
| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| Global var access | 38.34 M/s | 72.99 M/s | **53%** |
| Upvalue access | 81.64 M/s | 136.99 M/s | **60%** |
**总体结果:**
| 运行时 | 总时间 | 相对性能 |
|--------|--------|----------|
| Lua 5.4.6 | ~10.1 秒 | 100% |
| luars | ~15.3 秒 | 66% |

luars 在基准测试套件中达到 Lua 5.4 约 **66%** 的性能。

---

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

| 测试 | luars | Lua 5.4 | 比率 |
|------|-------|---------|------|
| Local var access | 165 M/s | 238 M/s | 69% |
| Integer addition | 159 M/s | 238 M/s | 67% |
| Float multiplication | 158 M/s | 217 M/s | 73% |
| Table access | 97.93 M/s | 142.86 M/s | 69% |
| ipairs iteration | 24.56 K/s | 45.45 K/s | 54% |
| Upvalue read/write | 22.37 M/s | 40.00 M/s | 56% |
| Multiple upvalues | 18.58 M/s | 34.48 M/s | 54% |
| Nested closures | 22.27 M/s | 35.71 M/s | 62% |
### 算术运算

---
| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 整数加法 | 139 M/s | 233 M/s | 60% |
| 浮点乘法 | 127 M/s | 208 M/s | 61% |
| 混合运算 | 74 M/s | 123 M/s | 60% |

### 控制流

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| If-else | 56 M/s | 52 M/s | 108% ✓ |
| While 循环 | 80 M/s | 118 M/s | 68% |
| Repeat-until | 83 M/s | 147 M/s | 56% |
| 嵌套循环 | 145 M/s | 250 M/s | 58% |

### 变量访问

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 全局变量 | 32 M/s | 74 M/s | 43% |
| 局部变量 | 121 M/s | 233 M/s | 52% |
| Upvalue | 53 M/s | 133 M/s | 40% |

### 函数调用

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 简单调用 | 19 M/s | 53 M/s | 36% |
| 变长参数 | 1.7 M/s | 2.5 M/s | 68% |

### 闭包

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 闭包创建 | 11.6 M/s | 7.1 M/s | 163% ✓ |
| Upvalue 读写 | 18.5 M/s | 43.5 M/s | 43% |

### 表操作

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 表插入 | 43 M/s | 34 M/s | 126% ✓ |
| 表访问 | 84 M/s | 125 M/s | 67% |

## 🟢 luars 表现更好的项目
### 元表 (fasttm 优化后)

| 测试 | luars | Lua 5.4 | 倍数 |
|------|-------|---------|------|
| table.sort (sorted) | 194 K/s | 8 K/s | **24x faster** |
| table.sort (reversed) | 35.6 K/s | 5.78 K/s | **6x faster** |
| Repeated yield | 3.06 M/s | 0.79 M/s | **4x faster** |
| pcall (error path) | 2.18 M/s | 0.55 M/s | **4x faster** |
| table.insert (end) | 21.27 M/s | 14.29 M/s | 1.5x faster |
| table.remove (end) | 26.81 M/s | 16.67 M/s | 1.6x faster |
| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| __index (函数) | 4.9 M/s | 22 M/s | 22% |
| __index (表) | 23 M/s | 26 M/s | 88% ✓ |
| __newindex | 6.1 M/s | 17 M/s | 36% |
| __call | 15.7 M/s | 25 M/s | 63% |
| __len | 5.3 M/s | 28 M/s | 19% |
| rawget | 21 M/s | 21 M/s | 100% ✓ |

### fasttm 优化效果

当表有元表但**没有特定元方法**时的访问性能:

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 缺失键 (有元表, 无__index) | 100-113 M/s | 100 M/s | 100-113% ✓ |
| #table (有元表, 无__len) | 83-105 M/s | 100 M/s | 83-105% ✓ |

### 协程

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| 创建/恢复/让出 | 319 K/s | 521 K/s | 61% |
| 重复 yield | 2.7 M/s | 735 K/s | 367% ✓ |
| coroutine.wrap | 405 K/s | 2.5 M/s | 16% |

### 错误处理

| 测试项 | luars | Lua 5.4 | 比率 |
|--------|-------|---------|------|
| pcall (成功) | 3.2 M/s | 17 M/s | 19% |
| pcall (失败) | 3.4 M/s | 493 K/s | 690% ✓ |
| xpcall (失败) | 1.2 M/s | 459 K/s | 261% ✓ |

---

## 优化计划(按优先级)
## 优化实现

### fasttm 优化 (Lua 5.4 风格)

参考 Lua 5.4 的 `ltm.h` 中的 `fasttm` 宏,实现了元方法缺失的快速检测:

```rust
// lua_table.rs
pub mod TmFlags {
pub const TM_INDEX: u8 = 1 << 0;
pub const TM_NEWINDEX: u8 = 1 << 1;
pub const TM_GC: u8 = 1 << 2;
pub const TM_MODE: u8 = 1 << 3;
pub const TM_LEN: u8 = 1 << 4;
pub const TM_EQ: u8 = 1 << 5;
pub const TM_CALL: u8 = 1 << 6;
}

pub struct LuaTable {
pub tm_flags: u8, // 缓存元方法不存在的位标志
// ...
}

impl LuaTable {
/// 检查元方法是否已知不存在
pub fn tm_absent(&self, flag: u8) -> bool {
(self.tm_flags & flag) != 0
}

/// 标记元方法不存在
pub fn set_tm_absent(&mut self, flag: u8) {
self.tm_flags |= flag;
}
}
```

**工作原理:**
1. 每个表的元表有一个 `tm_flags` 位域
2. 当查找元方法(如 `__index`)失败时,设置对应位
3. 下次访问时先检查位,如果已设置则跳过哈希查找
4. 当元表被修改时,清除所有标志

**效果:**
- "缺失键 (有元表, 无__index)" 场景:从 55 M/s 提升到 100+ M/s
- 达到 Lua 5.4 同等水平

### Phase 1: 核心调用路径优化
1. [ ] 闭包迭代器优化(5% → 目标 60%+)
2. [ ] pcall 成功路径优化(15% → 目标 80%+)
3. [ ] 元方法调用优化(17% → 目标 60%+)
---

## 性能优势领域

luars 在以下方面**超越** Lua 5.4:

### Phase 2: vararg 和函数调用
4. [ ] select() 和 vararg 处理优化
5. [ ] 简单函数调用开销减少
6. [ ] 多返回值传递优化
1. **闭包创建**: 163% (11.6 M/s vs 7.1 M/s)
2. **表插入**: 126% (43 M/s vs 34 M/s)
3. **重复 yield**: 367% (2.7 M/s vs 735 K/s)
4. **pcall 失败**: 690% (luars 的错误处理更快)
5. **If-else 分支**: 108%
6. **fasttm 优化场景**: 100-113%

### Phase 3: 循环和变量访问
7. [ ] while/repeat-until 循环优化
8. [ ] 全局变量访问优化
9. [ ] upvalue 访问优化
---

## 需要改进的领域

### Phase 4: 其他优化
10. [ ] OOP 方法调用优化
11. [ ] 迭代器通用优化
12. [ ] 表访问优化
1. **函数调用开销**: 36% - 需要优化调用栈管理
2. **全局变量访问**: 43% - `_ENV` 查找较慢
3. **元方法调用**: 19-36% - 元方法调用本身的开销较大
4. **pcall 成功路径**: 19% - 每次 pcall 有较大开销
5. **coroutine.wrap**: 16% - 包装函数创建较慢

---

## 技术笔记
## 结论

luars 作为 Rust 实现的 Lua 解释器,在整体性能上达到官方 Lua 5.4 的 66%。部分操作(闭包创建、表插入、协程 yield、错误处理)已经超越 Lua 5.4。

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

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