blob: 63443a5643a94049163f77c2665230f4608c63ef [file] [view]
# Chapter 5 实验结果分析
## 实验环境
| 项目 | |
|------|------|
| 平台 | Apple Silicon (ARM64, NEON) |
| 编译配置 | C1: SIMD OFF, 单线程; C3: SIMD ON, 单线程 |
| 编译器 | Apple Clang, Release (-O2) |
| SIMD 实现 | SIMDe 0.8.4 跨平台库 (ARM NEON / x86 AVX2) |
| E5-1 数据量 | 20M rows/dtype |
| E5-2 数据量 | 20M rows, 10 devices, 8 INT64 fields, TS_2DIFF+SNAPPY |
| E5-4 数据量 | 10,000 blocks × 129 rows = ~129 万点/page, in-memory |
| W0 随机种子 | 42, ni(-100,100), nf(-5,5), nd(-0.5,0.5) |
---
## E5-1: TS_2DIFF 编解码微基准
> 仅测试 INT32/INT64 TS_2DIFF 编码。FLOAT/DOUBLE W0 中使用 GORILLA 编码,
> GORILLA 当前无 SIMD 批量解码路径,不纳入对比。
### 编码吞吐量 (T5-1)
| 数据类型 | Per-value (M rows/s) | Batch Scalar (M rows/s) | Batch+SIMD (M rows/s) | Batch/PV |
|----------|---------------------|------------------------|----------------------|----------|
| INT32 | 85 | **122** | 123 | **1.43x** |
| INT64 | 87 | **141** | 137 | **1.62x** |
编码端 `encode_batch` 的优化点:
- **消除串行依赖**: 用相邻差分 `delta[i] = values[i] - values[i-1]` 替代逐值 `value - previous_value_`,允许编译器/SIMD 向量化
- **SIMD 批量差分**: 128-bit NEON 一次算 4 INT32 差分 (INT64 2 个)
- **SIMD 批量 min/max**: `simde_mm_min/max_epi32` 向量化规约
- **减少函数调用开销**: 无逐值虚函数调用、无逐值分支判断
编码端 SIMD ON vs OFF 差异微小 (123 vs 122),因为 SIMD 仅作用于 128 个元素的小数组,编译器自动向量化已做了类似优化。主要收益来自批量化本身。
### 解码吞吐量 (T5-2)
| 数据类型 | Per-value (M rows/s) | Batch Scalar (M rows/s) | Batch+SIMD (M rows/s) | Batch/PV | SIMD/PV |
|----------|---------------------|------------------------|----------------------|----------|---------|
| INT32 | 169 | 535 | **1130** | **3.16x** | **6.69x** |
| INT64 | 162 | 739 | 819 | **4.56x** | **5.06x** |
解码端优化层次:
1. **Per-value Batch (3.2-4.6x)**: `read_batch_int32/64` 直接用 raw pointer 访问 bit-packed 数据,跳过 `ByteStream::read_buf()` 的逐字节原子读、页边界检查和 memcpy 开销。一次性处理整个 block,避免逐值路径的状态机维护。
2. **Batch Batch+SIMD (INT32 再提 2.1x, INT64 再提 1.1x)**: `simd_decode_4_i32` 使用 128-bit SIMD gather + shift + prefix-sum 一次解 4 个值,2 组共 8 个值。INT32 使用原生 128-bit NEON,效率高。
3. **INT64 SIMD 加速弱于 INT32**: 数据 bit_width 相近 (≈8-9 bits),但 INT64 SIMD 路径有架构劣势:
- 使用 256-bit 指令,ARM NEON 无原生 256-bit 支持,SIMDe 拆为 2×128-bit 模拟
- 每次只解 4 个值 (vs INT32 8 个)
- Prefix sum store→标量修改→load 回退,打断流水线
- x86 AVX2 (原生 256-bit) 上预期加速比会显著提高
### 编解码对比
编码端批量化加速 (1.4-1.6x) 远小于解码端 (3.2-4.6x)。原因:
- 编码核心的 bit-packing (`write_bits`) 仍是逐值串行写入 ByteStream`encode_batch` 只优化了前置的 delta 计算和 min/max 查找
- 解码端的 batch 路径则整体绕过了 ByteStream,直接操作原始字节数组
---
## E5-2: 端到端读取 — 逐行 vs 批量+SIMD
### 不同选择率下的端到端读取性能
| 选择率 | Row-by-row (M rows/s) | Batch+SIMD (M rows/s) | 加速比 |
|--------|----------------------|----------------------|--------|
| 1% | 4.10 | 8.45 | 2.1x |
| 10% | 5.96 | 20.62 | **3.5x** |
| 50% | 6.20 | 24.98 | **4.0x** |
| 90% | 5.70 | 24.79 | **4.3x** |
| 100% | 5.87 | 24.53 | **4.2x** |
### 分析
1. **批量+SIMD 端到端加速 2.1-4.3x** 逐行读取 (`rs->next()` + `get_value()`) 稳定在 ~6 M rows/s,批量读取 (`get_next_tsblock()` + SIMD) 在高选择率下达到 ~25 M rows/s。加速比随选择率增大而增大,因为高选择率下解码量越大,批量化的优势越明显。
2. **低选择率加速较小 (2.1x)** 1% 选择率时,固定开销 (文件打开、metadata 解析、索引查找) 占比更大,解码本身占比小,批量化的优势被稀释。
3. **端到端 vs 纯解码** 端到端吞吐量 (~25 M rows/s) 远低于纯解码 (>500 M rows/s),差距约 20 倍。差距来自 SNAPPY 解压、Page 头解析、文件 I/OTsBlock 内存分配和 8 列并行解码的综合开销。
---
## E5-4: Block-Level 时间过滤精度
### E5-4a: 跳块率对比 (T5-5, 10,000 blocks/page, ~129 万点)
| bit_width | Plan A 跳块率 | Plan C 跳块率 | 幻影块数 |
|-----------|--------------|--------------|----------|
| 0 | 100.0% | 100.0% | 0 |
| 4 | 0.0% | 100.0% | 9,999 |
| 8 | 0.0% | 100.0% | 9,999 |
| 12 | 0.0% | 100.0% | 9,999 |
### E5-4b: 查询延迟对比 (T5-6, 10% 选择率, 1000 次重复)
| bit_width | Plan A p50 (ms) | Plan C p50 (ms) | 加速比 |
|-----------|----------------|----------------|--------|
| 0 | 0.317 | 0.310 | 1.02x |
| 4 | 0.372 | 0.368 | 1.01x |
| 8 | 0.339 | 0.335 | 1.01x |
| 12 | 0.397 | 0.394 | 1.01x |
### 分析
1. **bit_width=0 Plan A Plan C 完全一致** 采样完全规则时,保守上界 = 精确上界。验证退化路径正确性。
2. **bit_width >= 4 Plan A 几乎完全失效** 10,000 个块中仅 1 个块 (最后一个,无法 lookahead) Plan A 跳过。幻影区间宽度 = `write_index × (2^bit_width - 1) × delta_base`:
- bw=4: ~32 分钟; bw=8: ~9 小时; bw=12: ~6
- 对任何 jitter > 0 的数据,Plan A block 过滤基本失效
3. **延迟差异 ~1%** 10% 选择率查询中,窗口覆盖 ~1,000 个块(必须解码),窗口外 ~9,000 个块两种 Plan 都能跳过。幻影块集中在窗口边界,数量有限。
4. **Plan C 的价值在精度而非单次延迟** Lookahead 只需一次 raw pointer (8 字节),零成本消除 99.99% 的幻影块。
### Block 级过滤与 Page 大小的关系
TsFile page I/O 和解压的最小单位,page 大小(`page_writer_max_point_num_`,默认 10,000 点)决定了过滤粒度的分层:
| Page 大小 | Page 级过滤 | Block 级过滤价值 |
|-----------|-----------|-----------------|
| (≤10K 点, ~77 blocks) | 粒度细,整页跳过即可 | 低:page 本身时间范围窄,很少部分命中 |
| (100K+ 点, ~775+ blocks) | 粒度粗,query 常部分命中 page | **高:block 过滤填补 page 内过滤空白** |
**大 Page 的写入优势**:高频采集场景(振动传感器 10-100 kHz、车联网毫秒级采样)下,增大 page 可以:
- 提高压缩效率 压缩器看到更长的连续数据流
- 减少 page 封口开销 更少的 page header/statistics 写入
- 降低元数据占比 每个 page header 有固定字节开销
**大 Page 不影响读取粒度**:无论写入时 page 设多大,读取端的过滤能力是等价的:
- page page 级统计信息直接跳过整个 page
- page 进入 page 后,block 级过滤 (Plan C) 跳过不需要的 blocks
因此 **大 page + Plan C block 过滤** 是最优组合:写入端享受大 page 的压缩和减少封口开销的效率,读取端靠 block 级精确过滤弥补 page 粒度不足,不牺牲查询选择性。Plan C lookahead 使这种组合成为可能——没有 Plan C,大 page 下的 block 过滤会因幻影区间而完全失效。
---
## 总结
### 各层优化效果汇总
| 层次 | 优化 | INT32 | INT64 |
|------|------|-------|-------|
| 编码 | Per-value Batch | 85 **122** M rows/s (**1.43x**) | 87 **141** M rows/s (**1.62x**) |
| 编码 | Batch Batch+SIMD | 122 123 (~1.0x) | 141 137 (~1.0x) |
| 解码 | Per-value Batch | 169 **535** M rows/s (**3.16x**) | 162 **739** M rows/s (**4.56x**) |
| 解码 | Batch Batch+SIMD | 535 **1130** M rows/s (**2.11x**) | 739 **819** M rows/s (**1.11x**) |
| 解码 | Per-value Batch+SIMD | 169 **1130** M rows/s (**6.69x**) | 162 **819** M rows/s (**5.06x**) |
| 端到端 | Row Batch+SIMD (100%) | ~6 **25** M rows/s (**4.2x**) | |
| 过滤 | Plan A Plan C 跳块率 (bw4) | 0% **100%** | |
### 关键结论
1. **批量化是最大的加速来源** 解码端 batch 带来 3-5x 加速,编码端 1.4-1.6x。批量化通过绕过 ByteStream 逐字节开销、消除虚函数调用和串行依赖实现加速。
2. **SIMD 是批量化的增量收益** batch 基础上,SIMD INT32 解码再提 2.1x(总计 6.7x),对 INT64 ARM 256-bit 模拟限制仅 1.1x。编码端 SIMD 收益可忽略。
3. **端到端加速 2-4x** 逐行读取 ~6 M rows/s 提升到批量+SIMD ~25 M rows/s。解码优化的绝对收益被 I/O、解压等端到端开销稀释。
4. **Plan C lookahead 以零代价消除幻影块** bit_width4 Plan A block 过滤完全失效,Plan C 恢复 100% 跳块率。结合大 page 策略(高频采集场景),Plan C 使得 "大 page 高效写入 + block 级精确过滤读取" 成为可能。
### 待补充工作
1. **E5-3 跨平台** ARM NEON (本次) vs x86 AVX2 (fit39) 性能对比
2. **x86 AVX2 验证** INT64 SIMD ARM 上受 256-bit 模拟限制 (1.1x),原生 AVX2 预期显著提高
3. **大规模数据 (W0, 200M rows)** 当前 E5-2 使用 20M 行,可扩展至 200M 行验证线性扩展性
---
*实验日期: 2026-04-04*
*图表: `plot_all.py` 生成,PDF 格式*