当分配未使用的内存可将性能提高 2 倍 | Quickwit

主要观点:在搜索引擎quickwit中,术语聚合是关键聚合之一,可用于分析日志。在处理低基数数据(如日志级别)时性能良好,但在处理高基数数据(如 id 字段)时性能不佳,因此研究了可提高性能和减少内存消耗的专用数据结构。在性能测试中发现了奇怪的性能影响,通过深入研究发现与 Rust 中hashbrownHashMap实现有关,特别是在调整大小和内存映射方面。

关键信息

  • 术语聚合可用于统计特定时间段内每个日志级别的出现次数,等价于 SQL 中的SELECT term, COUNT(*) GROUP BY term WHERE <some complicate where clause>
  • 在性能测试中,添加未使用的数据集使函数吞吐量增加了 2 倍,但通过perf工具检查发现 L1 缓存访问计数器相同,突出的指标是MBr增加了 25%,但不足以解释 2 倍的吞吐量差异。
  • hashbrownHashMap在调整大小时使用copy_nonoverlapping复制数据,导致在复制到新表时触发页错误,将数据加载到内存中。
  • 分配器(glibc)和操作系统(OS)在内存管理方面有不同的操作,brk用于调整数据段的末尾,mmap用于分配新的内存区域。
  • glibc 的分配器根据M_MMAP_THRESHOLDM_TRIM_THRESHOLD参数决定使用mmap还是brk,默认情况下快速版本的M_TRIM_THRESHOLD设置为 8MB,导致分配器不释放内存回操作系统。
  • Vec不同,Hashmap需要复制数据,适当使用Hashmap::with_capacityVec::with_capacity对性能影响更大。

重要细节

  • 性能测试的函数为test_fx_hash_map,它简单地统计u32id 在FxHashMap中的出现次数。
  • 在测试中使用strace工具记录系统调用,发现慢版本在每次调整大小时多次调用mmapbrk,而快速版本在第一次调整大小时调用mmap,之后仅使用brk
  • 可以通过设置环境变量MALLOC_MMAP_THRESHOLD_MALLOC_TRIM_THRESHOLD_来控制分配器的行为,以复制快速版本的性能。
  • 测试代码的仓库为https://github.com/PSeitz/bench_riddle
阅读 10
0 条评论