You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用perf stat分析大文件读取的缓存行为与内存流量异常

问题描述

我用以下C语言代码做大文件读取实验:

int main(int argc, char** argv) {
  int buf_size = 1024*1024*1024;
  char* buffer = malloc(buf_size);
  char* buffer2 = malloc(buf_size);
  for (int i = 0; i < 10; i++){
    int fd = open(argv[1], O_DIRECT | O_RDONLY);
    read(fd, buffer, buf_size);
    memcpy(buffer2, buffer, buf_size);
  }
  free(buffer);
  free(buffer2);
  return 0;
}

在1 GiB的输入文件上运行程序,用perf stat统计性能计数器,发现read操作带来了超过3.6 GiB的缓存引用,但实际只读取了1 GiB的文件。注释掉read(fd, buffer, buf_size);后,性能计数器结果大幅降低。

补充系统信息:

  • 服务器:双路AMD EPYC 7H12
  • 系统:Ubuntu 24.04.1 LTS(内核6.8.0-41)
  • 编译命令:gcc -D_GNU_SOURCE main.c -o main
  • 文件系统:ZFS
  • 其他:缓存行大小64字节,Transparent HugePage (THP)已启用且运行时分配了大页;移除O_DIRECT或替换malloc为valloc后结果无显著变化。
原因分析
  • ZFS的特性带来额外内存访问:ZFS为保证数据完整性,读取数据时会同步计算校验和,这个过程会额外访问存储校验和的内存区域。另外ZFS的ARC缓存不会被O_DIRECT完全绕过——一次read操作会把数据同时写入用户态buffer和ARC缓存,相当于1GiB数据被加载两次,直接拉高缓存引用量。
  • NUMA架构的缓存一致性开销:双路AMD EPYC是NUMA架构,malloc分配的两个1GiB缓冲区很大概率落在不同NUMA节点上。跨节点执行memcpy时,CPU缓存一致性协议会触发缓存行共享、失效等操作,这些操作都会被perf统计为缓存引用,进一步增加总流量。
  • 数据复制的二次缓存访问:memcpy(buffer2, buffer, buf_size)会把buffer里的1GiB数据复制到buffer2,这个过程需要先从缓存读取buffer内容,再写入buffer2对应的缓存行,又是一次完整的1GiB量级缓存操作。
  • 巨页与块大小不匹配的额外开销:虽然启用了THP,但ZFS默认块大小(比如128KiB)和巨页粒度(2MiB/1GiB)不匹配,加载数据时可能触发额外的缓存行加载,带来少量但累积的缓存引用增量。

内容的提问来源于stack exchange,提问作者smz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:45:04