linux - 获得/proc/pid/smaps 一致快照的正确方法是什么?

标签 linux procfs

我正在尝试解析来自 /proc/<pid>/smaps 的 PSS 值我的 C++ 二进制文件中的一个进程。

根据 this SO answer ,天真地读了/proc/<pid>/smaps文件例如 ifstream::getLine()将导致数据集不一致。建议的解决方案是使用 read()一次读取整个数据的系统调用,例如:

#include <unistd.h>
#include <fcntl.h>

...

char rawData[102400];
int file = open("/proc/12345/smaps", O_RDONLY, 0);

auto bytesRead = read(file, rawData, 102400); // this returns 3722 instead of expected ~64k
close(file);

std::cout << bytesRead << std::endl; 

// do some parsing here after null-terminating the buffer

...

我现在的问题是,尽管我使用了 100kB 的缓冲区,但只返回了 3722 个字节。看什么cat使用 strace 解析文件时,我看到它使用多次调用 read() (每次读取也获得大约 3k 字节)直到 read()返回 0 - 如 documentation 中所述的 read() :
...
read(3, "7fa8db3d7000-7fa8db3d8000 r--p 0"..., 131072) = 3588
write(1, "7fa8db3d7000-7fa8db3d8000 r--p 0"..., 3588) = 3588
read(3, "7fa8db3df000-7fa8db3e0000 r--p 0"..., 131072) = 3632
write(1, "7fa8db3df000-7fa8db3e0000 r--p 0"..., 3632) = 3632
read(3, "7fa8db3e8000-7fa8db3ed000 r--s 0"..., 131072) = 3603
write(1, "7fa8db3e8000-7fa8db3ed000 r--s 0"..., 3603) = 3603
read(3, "7fa8db41d000-7fa8db425000 r--p 0"..., 131072) = 3445
write(1, "7fa8db41d000-7fa8db425000 r--p 0"..., 3445) = 3445
read(3, "7fff05467000-7fff05496000 rw-p 0"..., 131072) = 2725
write(1, "7fff05467000-7fff05496000 rw-p 0"..., 2725) = 2725
read(3, "", 131072)                     = 0
munmap(0x7f8d29ad4000, 139264)          = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

但是,根据上面链接的 SO 答案,这不应该会产生不一致的数据吗?

我还找到了一些关于 proc here 的信息,这似乎支持以前的 SO 答案:

To see a precise snapshot of a moment, you can see /proc/<pid>/smaps file and scan page table.



然后在后面的文字中说:

Note: reading /proc/PID/maps or /proc/PID/smaps is inherently racy (consistent output can be achieved only in the single read call). This typically manifests when doing partial reads of these files while the memory map is being modified. Despite the races, we do provide the following guarantees:

1) The mapped addresses never go backwards, which implies no two regions will ever overlap.

2) If there is something at a given vaddr during the entirety of the life of the smaps/maps walk, there will be some output for it.



所以在我看来,如果我在单个 read() 中获得数据,我只能相信我获得的数据。称呼。
尽管缓冲区足够大,但它只返回一小块数据。
这反过来意味着实际上无法获得 /proc/<pid>/smaps 的一致快照。以及 cat/using multiple read() 返回的数据电话可能是垃圾取决于日月光比?

或者 2) 是否真的意味着我对上面列出的上一个 SO 答案太着迷了?

最佳答案

您受到 fs/seq_file.c 中内核缓冲区大小的限制,该缓冲区用于生成许多/proc 文件。
缓冲区是第一个 set to be the size of a page ,然后是指数 grown to fit at least one record , 然后塞满了 as many entire records as will fit ,但在能够适应第一个条目后不再增长。当内部缓冲区不能容纳更多条目时,读取结束。

关于linux - 获得/proc/pid/smaps 一致快照的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59737950/

相关文章:

c - 在/proc 文件系统中创建的文件的 open 系统调用中返回负值

linux - 使用 shell 脚本在当前窗口中打开新选项卡

linux - 无法访问 apache http 服务器上的 .mov 文件

java - 当我运行 Flutter 项目时,我的 Ubuntu 系统出现此错误

linux - SSH 守护进程 (NIO2) 不再启动

linux - 7 比特定日期更新的 zip 归档文件

linux - 第二次从 Proc-FS 文件读取时使用 lseek() 是否安全

c - procfs 是否需要 copy_to_user ?

linux-kernel - 在/proc/net中创建ProcFS条目

linux - 如何获取解释 Mapped in/proc/meminfo 的进程列表