У меня сильно многопоточное приложение под Linux, потребляющее много памяти, и я пытаюсь классифицировать его RSS. Мне было особенно сложно оценить общий RSS всех стеков потоков в программе. У меня были следующие идеи:
Идея 1 : загляните в /proc/<pid>/smaps
и рассмотрите сопоставления для стеков; есть информация о резидентном размере каждого отображения, но только отображение основного потока аннотировано как [stack]; остальные из них неотличимы от обычных сопоставлений 8 MiB (с размером стека по умолчанию). Кроме того, чтение /proc/<pid>/smaps
довольно дорогое, так как оно вызывает конфликт между внутренними структурами данных VMA ядра.
Идея 2 : посмотрите на /proc/<tid>/status
; есть раздел VmStk
, который должен описывать размер резидентного стека, но он всегда показывает размер стека основного потока. Выглядит довольно понятно, почему: поскольку основной поток - единственный, для которого ядро выделяет стек само, тогда как остальные потоки получают стек из кода pthreads, который выделяет его как обычное отображение памяти.
Идея 3 : пройти потоки из пользовательского пространства, используя некоторые данные из pthreads, получить адрес отображения стека и размер стека для каждого потока, а затем выяснить, сколько страниц является резидентными, используя mincore(2)
. В качестве возможной оптимизации мы можем пропустить вызов mincore для спящих потоков, используя для них кешированное значение. К сожалению, я не нашел подходящего способа перебора структур pthread_t
. Обратите внимание, что часть потоков поступает из библиотек, которые я не могу контролировать, поэтому поддержание любого типа реестра потоков путем регистрации потоков при запуске невозможно.
Идея 4 : используйте ptrace(2)
, чтобы получить регистры потоков, извлечь из них указатели стека, затем перейти к Идея 1 . Этот способ выглядит чрезмерно сложным и навязчивым.
Может ли кто-нибудь предоставить мне более или менее продуманный способ сделать это? Быть непереносимым - нормально.
Еще две идеи, которые я получил после дополнительных исследований:
Идея 5 : от man 5 proc
на /proc/<pid>/maps
:
There are additional helpful pseudo-paths:
[stack]
The initial process's (also known as the main thread's) stack.
[stack:<tid>] (since Linux 3.4)
A thread's stack (where the <tid> is a thread ID). It corresponds to the /proc/[pid]/task/[tid]/ path.
Выглядит интригующе, но кажется, что этот лог c был возвращен, поскольку он был реализован неэффективно: https://lore.kernel.org/patchwork/patch/716239/. Страница руководства кажется устаревшей (по крайней мере, на моей Ubuntu Disco 19.04).
Идея 6 : Эта может действительно работать. Существует файл /proc/<tid>/syscall
, который может открывать регистр стека потоков для заблокированного потока. Учитывая тот факт, что большинство моих потоков спят при вводе-выводе, это позволяет мне отслеживать их значение rsp, которое я могу проецировать на /proc/<pid>/maps
, чтобы найти соответствие между потоком и его отображением стека. После этого я могу реализовать Идею 3 .