Как получить максимальное использование памяти в программе с помощью psutil в Python

Я использую следующий код, чтобы получить максимальное использование памяти в памяти.

    import os, subprocess , psutil
    def mem(cmd):
        try:
            with open('in.txt','r') as infile, open('out.txt', 'w') as outfile:
                p=psutil.Popen("./"+cmd,shell=False,stdin=infile,stdout = outfile)
            print p.memory_info()
        except Exception:
             print "Error"
    cmd=raw_input()
    mem(cmd)

Проблема заключается в том, что иногда для начальных прогонов программы используется использование памяти (0,0), но впоследствии она отображает правильный вывод. Я не знаю, почему это происходит. Для некоторых программ, таких как глобальная программа hello в С++, результат равен pmem(rss=4096, vms=315392), который составляет около 0,3 М (я думаю, что вывод находится в байтах), но запуск глобальной программы hello в ideone.com дает результат как ~ 3M. Почему существует эта диспропорция?

cmd - это имя исполняемого файла.

Вывод команды print subprocess.check_output(['ps', 'v', '-p', str(p.pid)])

PID TTY STAT TIME MAJFL TRS DRS RSS %MEM COMMAND 16150 pts/16 Z+ 0:00 0 0 0 0 0.0 [a.out] <defunct>

Одна из моих программ на С++:

`int a[1000000];
int main()
{
    return 0;
}`

возвращает pmem (rss = 4096, vms = 4313088) иногда и pmem (rss = 0, vms = 0) иногда

Ответ 1

<defunct> означает, что подпроцессом является зомби-процесс (он мертв, но его статус еще не был прочитан родителем ( p.poll() или p.wait())). Кажется, что оба psutil и ps показывают RSS равными нулю для таких процессов.

Результат зависит от того, выйдет ли подпроцесс раньше, чем p.memory_info(). Это гонка. Если вы добавите задержку на выходе в программе на С++, тогда p.memory_info() может быть вызван до выхода подпроцесса, и вы должны получить ненулевые результаты.

Проблема в том, что я могу получить произвольные программы для оценки. Язык также не фиксирован. Разве нет элегантного решения этой проблемы?

Возможно, вам понадобится поддержка ОС, чтобы сохранить информацию об использовании памяти подпроцессом даже после ее выхода. Или вы можете запустить программу, используя профайлер памяти, например valgrind, и прочитать его результаты. Чтобы собрать результаты:

$ valgrind --tool=massif cmd arg1 arg2 

Чтобы увидеть результаты, вы можете использовать ms_print:

$ ms_print massif.out.* | less

Или графический интерфейс Massif-Visualizer

@mdadm предложил более простое решение: time команда:

from subprocess import Popen, PIPE

p = Popen(['time', '-f', '%M'] + args, stderr=PIPE)
ru_maxrss = int(p.communicate()[1])
print("Maximum rss %d KB" % ru_maxrss)

Время GNU использует wait3() для заполнения информации об использовании ресурсов, если она доступна. Его можно вызвать в Python:

import os
from subprocess import Popen

p = Popen(args)
ru = os.wait4(p.pid, 0)[2]
print("Maximum rss %d KB" % ru.ru_maxrss)

Я сравнил максимальное значение, возвращаемое psutil.Process.memory_info (rss), с ru_maxrss значением, возвращаемым os.wait4, и с максимальной суммарной памятью, сообщенной valgrind --tool=massif: они похожи.

См. также:

Ответ 2

Проблема в том, что psutils берет быстрый снимок из файловой системы /proc, как вы можете видеть в source.

Когда вы запускаете свой пример hello world, в некоторых случаях он заканчивается до того, как python получит возможность прочитать значения из /proc.

Как только процесс будет завершен, он больше не будет потреблять баран. Вы можете подтвердить это с помощью strace.

open("/proc/13420/statm", O_RDONLY)     = 3
read(3, "0 0 0 0 0 0 0\n", 1024)        = 14

Если вы измените свой пример, чтобы использовать что-то вроде сна, вы заметите, что psutils последовательно возвращает память.

#include <iostream>
#include <unistd.h>

int main()
{
  std::cout << "Hello World.. sleeping!";
  sleep(3);
}

Вывод вашего python script...

a.out
meminfo(rss=286720, vms=12931072)

Один простой способ выполнить то, что вы пытаетесь сделать, - это использовать команду /usr/bin/time, которая на большинстве платформ даст вам среднюю общую память использования процесса, который вы запускаете, или используйте valgrind как JF Sebastian предлагает... кого отправил, когда я изучал и тестировал свой ответ;)

Hello World.. sleeping!0.00user 0.00system 0:03.00elapsed 0%CPU     
(0avgtext+0avgdata 1144maxresident)k
0inputs+0outputs (0major+348minor)pagefaults 0swaps