Использование памяти в 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).