Skip to content

perf(pine-cpp): micro-optimizations for flat profile hotspots #54

Description

@Liam0205

背景

在 PERF-2a (per-thread bump arena) 之后,perf profile 显示剩余热点分布非常平坦(排除模拟负载后无单一热点超过 8%)。以下四个微优化已验证正确性(cross-validate 全通过),但在 realistic_for_you_calibrated fixture 上无可测量 QPS 提升(维持 ~183 QPS)。

留待将来有 data_parallel fixture 或更大 map 场景时验证收益。

优化内容

1. 窗口视图跳过锁(RowFrame + ColumnFrame)

动机: pthread_rwlock 占 5.5%。Window view 在 parallel_execute 期间保证父 frame 冻结,shared_lock 是纯开销。

原理: is_window_view() 为 true 时,所有读方法直接访问 view_items_/view_common_ 指针,不获取 shared_lock。安全性由 parallel_execute 的生命周期保证。

当前 fixture 无效原因: realistic_for_you_calibrated 的 38 个算子全部 data_parallel=0,不创建窗口视图。

2. JSON 序列化消除二次 hash 查找

动机: write_json_valueresult_items_to_json 中,先收集 key 指针排序,再对每个 key 调用 map.find(key) — 这是冗余的 O(1) hash 查找。

原理: 改为收集 pair<const string*, const JsonValue*> 排序,直接通过指针访问 value,消除排序后的二次查找。

当前 fixture 无效原因: JSON 序列化中 find 只占总 find 热点的一小部分(大部分 find 来自算子读 frame)。

3. 数字格式化避免临时 string

动机: go_format_json_number 每次返回 std::string,在 write_json_value 中每个数字都分配临时 string。

原理: 新增 go_format_json_number_buf(double, char*, size_t) 直接写入栈 buffer,避免 heap 分配。

当前 fixture 无效原因: 数字通常 < 15 字符,在 SSO 范围内,原本就不触发堆分配。

4. to_result 预分配

动机: _M_need_rehash + _M_next_bkt 占 2.2%。to_result 中每行创建空 map 逐字段插入会触发 rehash。

原理: 对输出 map 调用 reserve(item_out.size())

当前 fixture 无效原因: 输出字段数少(~5),默认 bucket count 已足够。

Patch

点击展开 patch
$(cat /tmp/perf-micro-opts.patch)

验证结果

  • 单元测试: 145 tests passed
  • Cross-validate section 4: 91/91
  • Cross-validate section 5: 26/26
  • Benchmark: ~183 QPS(与基线持平)

适用场景

这些优化在以下场景可能有可测量收益:

  • 使用 data_parallel 的 fixture(窗口视图跳过锁)
  • 输出字段数 > 10 的 pipeline(reserve 预分配)
  • 大量嵌套 object 的 JSON 序列化(消除二次 find)

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions