Как профилировать несколько подпроцессов, используя многопроцессорность Python и memory_profiler?

У меня есть утилита, которая порождает несколько рабочих процессов с помощью модуля Python multiprocessing, и я хотел бы иметь возможность отслеживать использование памяти с помощью превосходной утилиты memory_profiler, которая делает все, что я хочу - в частности, выборка использования памяти с течением времени и построение окончательного результата (меня не интересует построчное профилирование памяти для этого вопроса).

Чтобы задать этот вопрос, я создал более простую версию скрипта с рабочей функцией, которая выделяет память, аналогичную пример из библиотеки memory_profiler. Рабочий выглядит следующим образом:

import time

X6 = 10 ** 6
X7 = 10 ** 7

def worker(num, wait, amt=X6):
    """
    A function that allocates memory over time.
    """
    frame = []

    for idx in range(num):
        frame.extend([1] * amt)
        time.sleep(wait)

    del frame

Учитывая последовательную рабочую нагрузку 4 рабочих следующим образом:

if __name__ == '__main__':
    worker(5, 5, X6)
    worker(5, 2, X7)
    worker(5, 5, X6)
    worker(5, 2, X7)

Запуск исполняемого файла mprof для профилирования моего сценария занимает 70 секунд, когда каждый рабочий процесс запускается один за другим. Скрипт запускается следующим образом:

$ mprof run python myscript.py

Создает следующий график использования памяти:

Последовательное создание рабочих процессов в памяти

Если эти рабочие процессы выполняются параллельно с multiprocessing, это означает, что скрипт завершится так же медленно, как самый медленный рабочий процесс (25 секунд). Этот сценарий выглядит следующим образом:

import multiprocessing as mp

if __name__ == '__main__':
    pool    = mp.Pool(processes=4)
    tasks   = [
        pool.apply_async(worker, args) for args in
        [(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
    ]

    results = [p.get() for p in tasks]

Профилировщик памяти действительно работает, по крайней мере, при использовании mprof ошибок нет, но результаты немного странные:

введите описание изображения здесь

Беглый взгляд на Activity Monitor показывает, что на самом деле существует 6 процессов Python, один для mprof, один для python myscript.py, а затем по одному для каждого рабочего подпроцесса. Похоже, что mprof измеряет использование памяти только для процесса python myscript.py.

«Процессы

Библиотека memory_profiler обладает широкими возможностями настройки, и я вполне уверен, что смогу захватывать память каждого процесса и, возможно, записывать их в отдельные файлы журналов с помощью самой библиотеки. Я просто не уверен, с чего начать или как подойти к этому уровню настройки.

ИЗМЕНИТЬ

Прочитав сценарий mprof, я обнаружил флаг -C, который суммирует использование памяти всеми дочерними (разветвленными) процессами. Это приводит к следующему (значительно улучшенному) графику:

«Многопроцессорные

Но то, что я ищу, - это использование памяти каждым отдельным подпроцессом с течением времени, чтобы я мог отображать всех рабочих (и мастер) на одном графике. Моя идея состоит в том, чтобы каждый подпроцесс memory_usage записывался в отдельный файл журнала, который я затем могу визуализировать.


person bbengfort    schedule 13.07.2016    source источник
comment
Этот вопрос обсуждается с разработчиками на GitHub по адресу github.com/fabianp/memory_profiler/issues/118. если кому интересно.   -  person bbengfort    schedule 16.07.2016


Ответы (1)


На сегодняшний день в библиотеку профилировщика памяти добавлена ​​новая функция, которая делает именно это. Если вам нужна эта функциональность, сначала обновите memory_profiler следующим образом:

$ pip install -U memory_profiler 

Это должно установить версию v0.44 профилировщика памяти. Чтобы убедиться, что это так, используйте команду справки в действии запуска:

mprof run --help
Usage: mprof run [options]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  --python              Activates extra features when the profiling executable
                        is a Python program (currently: function
                        timestamping.)
  --nopython            Disables extra features when the profiled executable
                        is a Python program (currently: function
                        timestamping.)
  -T INTERVAL, --interval=INTERVAL
                        Sampling period (in seconds), defaults to 0.1
  -C, --include-children
                        Monitors forked processes as well (sum up all process
                        memory)
  -M, --multiprocess    Monitors forked processes creating individual plots
                        for each child

Если вы видите флаг -M, то все готово!

Затем вы можете запустить свой скрипт следующим образом:

$ mprof run -M python myscript.py
$ mprof plot 

И у вас должна получиться фигура, которая выглядит так:

mprof отслеживает отдельные дочерние процессы

Обратите внимание, что если вы также используете флаг --include-children, основной памятью процесса будет общее использование памяти всеми дочерними и основными процессами, что также является полезным графиком.

person bbengfort    schedule 22.03.2017
comment
особая благодарность @fabian-pedregosa за помощь в этом! - person bbengfort; 22.03.2017
comment
Как насчет включения временных меток и декоратора @profile в этом режиме? Является ли это возможным? - person petroslamb; 01.06.2017
comment
Я не уверен, что вы имеете в виду о включении временных меток? Я думаю, что это должно быть возможно с декоратором @profile, он использует те же аргументы. - person bbengfort; 05.06.2017
comment
К сожалению, я не смог заставить его работать. Пожалуйста, взгляните на github.com/fabianp/memory_profiler/issues/148. - person petroslamb; 06.06.2017
comment
Ах, да, я вижу проблему - кстати, это был очень хороший отчет об ошибке. К сожалению, проблема рассола возникает везде при работе с различными типами многопроцессорного профилирования. Извини за это. - person bbengfort; 07.06.2017
comment
есть ли способ иметь имена для дочерних процессов? child-n на самом деле не объяснимо :) - person Alon Gouldman; 07.04.2020
comment
Было бы здорово, если бы был какой-то способ - я думаю, вам, возможно, придется углубиться в детали cprofile, чтобы увидеть, есть ли какой-нибудь способ сделать это. - person bbengfort; 07.04.2020
comment
@fabian-pedregosa Можем ли мы автоматически сохранить этот график? - person Pe Dro; 03.06.2020
comment
Я нашел пакет TAMPPA для сохранения результатов профилировщика памяти и профилировщика строк в формате csv. .. хорошо для будущего использования :) Надеюсь, это поможет - person Pe Dro; 29.08.2020