C++如何获取当前进程每秒发生的硬页错误(Hard Page Faults)次数

Linux下获取硬页错误需读取/proc/pid/stat的第12个字段majflt,而非statm或status;须定时采样求差再除以时间间隔,注意解析时跳过含空格的命令名字段。

c++如何获取当前进程每秒发生的硬页错误(hard page faults)次数

Linux下用/proc/pid/statm和/proc/pid/status无法获取硬页错误

硬页错误(major page fault)不是靠读取 /proc/pid/statm/proc/pid/status 能拿到的——这两个文件只提供内存占用、RSS、共享页等静态快照,不包含页错误计数。真正记录硬页错误的是 /proc/pid/stat 的第12个字段(majflt),它表示**进程自启动以来累计发生的硬页错误总数**。

从/proc/pid/stat提取majflt并计算每秒增量

要得到“每秒硬页错误次数”,必须做两件事:定时读取 stat 文件、两次采样求差、再除以时间间隔。注意以下关键点:

  • /proc/pid/stat 是空格分隔的纯文本,字段数固定但字段长度可变(如命令名含空格时会被括号包裹),不能简单按空格切分;必须按规范解析:第12个字段(索引从1开始)是 majflt,位置固定
  • 推荐用 std::ifstream 逐行读 + std::istringstream 提取前12个字段,跳过命令名(第2字段,被括号包围)避免解析错位
  • 两次采样间隔建议 ≥100ms,太短会导致增量为0(硬页错误本身不频繁,且内核只在缺页处理完成时更新计数)

示例片段(仅核心逻辑):

long long get_majflt(pid_t pid) {
    std::ifstream f("/proc/" + std::to_string(pid) + "/stat");
    std::string line;
    if (!std::getline(f, line)) return -1;
    std::istringstream iss(line);
    std::string dummy;
    // 跳过第1字段(pid)、第2字段(comm,含括号)、第3字段(state)
    iss >> dummy >> dummy >> dummy;
    for (int i = 4; i <= 11; ++i) iss >> dummy; // 跳过第4~11字段
    long long majflt;
    iss >> majflt;
    return majflt;
}

硬页错误统计受内核版本和权限影响

不是所有进程都能被任意用户读取其 /proc/pid/stat ——尤其当目标进程属于其他用户时,/proc/pid/ 目录默认权限为 dr-xr-xr-x,但 stat 文件本身权限是 -r--r--r--,只要目录可进入就能读。不过从 Linux 4.1 开始,若启用了 hidepid=2(常见于容器或加固系统),非同组/非特权用户将无法访问其他用户的 /proc/pid/ 目录,此时会直接返回 ENOENTEACCES

立即学习“C++免费学习笔记(深入)”;

  • 普通用户只能监控自己启动的进程;监控系统级进程(如 pid=1)需 root 权限
  • 硬页错误计数由内核在每次 major fault 处理完成后原子递增,无竞态问题,但采样时刻的值是“截至该时刻的累计值”,不是瞬时速率
  • 不要混淆 majflt(硬页错误)和 minflt(软页错误,第11字段)——后者不触发磁盘IO,通常无需关注

替代方案:用perf_event_open直接抓取PERF_COUNT_SW_PAGE_FAULTS_MAJ

如果需要更高精度或跨进程聚合(比如整个cgroup的硬页错误),可以用 perf_event_open 系统调用监听 PERF_COUNT_SW_PAGE_FAULTS_MAJ 事件。但这要求:

  • 内核开启 CONFIG_PERF_EVENTS=y(绝大多数发行版默认开启)
  • 调用进程有 CAP_SYS_ADMINperf_event_paranoid ≤ 2(可通过 sysctl kernel.perf_event_paranoid 查看)
  • 需手动管理 perf event fd、mmap ring buffer、样本解析——比读 /proc/pid/stat 复杂一个数量级,且对单进程监控属于过度设计

除非你在写性能分析工具或需要纳秒级时间戳关联,否则老老实实读 majflt 就够了。

硬页错误本身是低频事件,采样窗口拉太短没意义;而 majflt 字段不会溢出(long long 类型),但要注意两次采样间进程可能已退出——读 /proc/pid/stat 失败时得跳过本次计算,别拿旧值硬减。

文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/124080.html

C++如何获取程序标准错误流是否已被重定向至外部文件或设备
上一篇 2026-07-01 17:00
php7.4部署宝塔后网站打开速度慢如何优化
下一篇 2026-07-01 17:00

相关推荐