Как правильно получить согласованный снимок / proc / pid / smaps? - PullRequest
4 голосов
/ 14 января 2020

Я пытаюсь проанализировать значение PSS из /proc/<pid>/smaps процесса в моем двоичном файле C ++.

Согласно этому SO-ответу , например, наивно читая файл /proc/<pid>/smaps с ifstream::getLine() приведет к несовместимому набору данных. Предложенное решение состоит в том, чтобы использовать системный вызов read() для чтения всех данных в одном go, что-то вроде:

#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

...

Моя проблема сейчас заключается в том, что, несмотря на использование буфера 100 КБ, только 3722 байта возвращаются. Глядя на то, что cat делает при разборе файла с использованием strace, я вижу, что он использует несколько вызовов read() (также получая около 3 Кбайт при каждом чтении), пока read() не вернет 0 - как описано в документация из 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, указанным выше?

Я также нашел некоторую информацию о c здесь , который, кажется, поддерживает предыдущий ответ SO:

Чтобы увидеть точный моментальный снимок, вы можете увидеть файл / proc / / smaps и отсканируйте таблицу страниц.

Затем в тексте говорится:

Примечание: чтение / proc / PID / maps или / proc / PID / smaps по своей природе является очень быстрым. (последовательный вывод может быть достигнут только в одном вызове чтения). Обычно это проявляется при частичном чтении этих файлов во время изменения карты памяти. Несмотря на гонки, мы предоставляем следующие гарантии:

1) Преобразованные адреса никогда не go в обратном направлении, что означает, что никакие две области никогда не будут перекрываться.

2) Если что-то есть в данный vaddr в течение всей жизни прогулки smaps / maps, для него будет какой-то вывод.

Так что мне кажется, я могу доверять только данным, которые получаю, если Я получаю это за один read() звонок. Который возвращает только небольшой кусок данных, несмотря на то, что буфер достаточно большой. Что, в свою очередь, означает, что на самом деле нет способа получить непротиворечивый снимок /proc/<pid>/smaps, а данные, возвращаемые cat / с использованием нескольких вызовов read(), могут быть мусором в зависимости от соотношения света Солнца и Луны?

Или 2) означает ли это, что я слишком зациклен на предыдущем ответе SO, указанном выше?

...