Использование памяти в Python: в чем разница между memory_profiler и guppy?

Я полностью сбит с толку насчет использования памяти конкретным скриптом Python. Думаю, я не знаю, как составить профиль использования, несмотря на советы нескольких SO вопросов / ответов.

Мои вопросы: в чем разница между memory_profiler а также guppy.hpy ? Почему один говорит мне, что я использую огромное количество памяти, а другой говорит, что я нет?

Я работаю с pysam библиотека для доступа к файлам SAM/BAM биоинформатики. Мой основной скрипт быстро исчерпывает память при преобразовании SAM (ASCII) в BAM (Binary) и манипулировании файлами между ними.

Я создал небольшой тестовый пример, чтобы понять, сколько памяти выделяется на каждом шаге.

# test_pysam.py: 

import pysam
#from guppy import hpy

TESTFILENAME = ('/projectnb/scv/yannpaul/MAR_CEJ082/' +
                'test.sam')
#H = hpy()

@profile # for memory_profiler
def samopen(filename):
#    H.setrelheap()
    samf = pysam.Samfile(filename)
#    print H.heap()
    pass


if __name__ == "__main__":
    samopen(TESTFILENAME)

Мониторинг использования памяти с помощью memory_profiler (python -m memory_profiler test_pysam.py) приводит к следующему выводу:

Filename: test_pysam.py

Line #    Mem usage    Increment   Line Contents
================================================
    10                             @profile # for memory_profiler
    11                             def samopen(filename):
    12     10.48 MB      0.00 MB   #    print H.setrelheap()
    13    539.51 MB    529.03 MB       samf = pysam.Samfile(filename)
    14                             #    print H.heap()
    15    539.51 MB      0.00 MB       pass

Затем комментируя @profile декоратор и раскомментирует guppy связанные строки, я получаю следующий вывод (python test_pysam.py):

Partition of a set of 3 objects. Total size = 624 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0      1  33      448  72       448  72 types.FrameType
     1      1  33       88  14       536  86 __builtin__.weakref
     2      1  33       88  14       624 100 csamtools.Samfile

Общий размер строки 13 составляет 529,03 МБ в одном случае и 624 байта в другом. Что на самом деле здесь происходит? 'test.sam' - это файл SAM размером ~ 52 МБ (снова в формате ASCII). Это немного сложно для меня, чтобы углубиться в pysam, так как это обертка вокруг библиотеки C, связанной с samtools, Независимо от того, что Samfile на самом деле, я думаю, я должен быть в состоянии узнать, сколько памяти выделяется для его создания. Какую процедуру я должен использовать, чтобы правильно профилировать использование памяти каждого шага моей большей, более сложной программы на Python?

1 ответ

Решение

В чем разница между memory_profiler и guppy.hpy?

Понимаете ли вы разницу между вашим внутренним представлением кучи и внешним представлением ОС вашей программы? (Например, когда интерпретатор Python вызывает free на 1 МБ это не сразу - или, возможно, даже - не возвращает в ОС страницы объемом 1 МБ по нескольким причинам.) Если вы это сделаете, то ответ довольно прост: memory_profiler запрашивает у ОС использование вашей памяти; Гуппи выясняет это из структур кучи.

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

Почему один говорит мне, что я использую огромное количество памяти, а другой говорит, что я нет?

Трудно быть уверенным, но вот некоторые предположения; ответ, вероятно, будет комбинацией более чем одного:

Возможно, samtools использует mmap для отображения достаточно маленьких файлов в памяти. Это увеличит использование вашей страницы по размеру файла, но не увеличит использование кучи вообще.

Может быть, samtools или pysam создает много временных объектов, которые быстро освобождаются. У вас может быть много фрагментации (только пара активных PyObjects на каждой странице), или malloc вашей системы, возможно, решил, что из-за того, как вы размещаете ресурсы, он должен хранить множество узлов в своем свободном списке, или он может не возвращать страницы операционной системе, или виртуальная машина операционной системы может не иметь восстановленных страниц, которые были возвращены. Точную причину почти всегда невозможно угадать; самое простое, что нужно сделать, это предположить, что освобожденная память никогда не возвращается.

Какую процедуру я должен использовать, чтобы правильно профилировать использование памяти каждого шага моей большей, более сложной программы на Python?

Если вы спрашиваете об использовании памяти с точки зрения ОС, memory_profiler делает именно то, что вы хотите. В то время как серьезное копание в pysam может быть трудным, должно быть тривиально обернуть некоторые функции @profile декоратор. Тогда вы будете знать, какие функции C отвечают за память; если вы хотите копать глубже, вам, очевидно, придется профилировать на уровне C (если нет информации в документации samtools или в сообществе samtools).

Другие вопросы по тегам