Как рассчитать общий RSS всех стеков потоков до Linux? - PullRequest
2 голосов
/ 21 июня 2020

У меня сильно многопоточное приложение под 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 .

...