Как я могу профилировать память многопоточной программы на Python?

Есть ли способ профилировать память многопоточной программы в Python?

Для профилирования ЦП я использую cProfile для создания отдельной статистики профилировщика для каждого потока, а затем их объединения. Однако я не смог найти способ сделать это с помощью профилировщиков памяти. Я использую heapy.

Есть ли способ объединить статистику в кучу, как cProfile? Или какие другие профилировщики памяти, по вашему мнению, больше подходят для этой задачи.

Связанный вопрос был задан для профилирования использования ЦП в многопоточной программе: Как я могу профилировать многопоточную программу на Python?

Также еще один вопрос относительно профилировщика памяти: Профилировщик памяти Python


person Utku Zihnioglu    schedule 25.01.2011    source источник
comment
Что вам не нравится в решениях других вопросов?   -  person Falmarri    schedule 26.01.2011
comment
@Falmarri, я ищу профилировщик памяти. Первый - это в основном профилировщик ЦП. Второй работает только для одного потока.   -  person Utku Zihnioglu    schedule 26.01.2011
comment
Основная особенность потоков заключается в том, что они разделяют память (в отличие от процессов). Как вы ожидаете профилировать различную статистику памяти для потоков, которые используют одну и ту же память?   -  person scoffey    schedule 29.01.2011
comment
Профилировщик памяти @scoffey heapy не профилирует все потоки как один. Он только профилирует использование памяти потоком, в котором он запущен. Я ищу способ профилировать память всего процесса. Та же идея относится к профилировщику ЦП, модулю cProfile. Однако есть способ объединить статистику профилей разных потоков с cProfile, что объясняется в приведенной выше ссылке.   -  person Utku Zihnioglu    schedule 29.01.2011


Ответы (4)


Если вам нравится профилировать объекты, а не необработанную память, вы можете использовать gc.get_objects() функция, поэтому вам не нужен собственный метакласс. В более поздних версиях Python sys.getsizeof() также позволит вам попытаться выяснить сколько базовой памяти используется этими объектами.

person ncoghlan    schedule 14.02.2011
comment
Отлично. Намного чище, чем мой подход. - person Utku Zihnioglu; 14.02.2011

Есть способы заставить valgrind профилировать память программ на Python: http://www.python.org/dev/faq/#can-i-run-valgrind-against-python

person Foo Bah    schedule 07.02.2011
comment
Никогда раньше не слышал о valgrind; обязательно проверю. - person Utku Zihnioglu; 07.02.2011
comment
@funktku - это стандартный инструмент для профилирования использования памяти и обнаружения утечек памяти. - person Foo Bah; 07.02.2011

В порядке. То, что я искал, похоже, не существует. Итак, я нашел решение - обходной путь для этой проблемы.

Вместо профилирования памяти я профилирую объекты. Таким образом, я смогу увидеть, сколько объектов существует в программе в определенный момент времени. Для достижения своей цели я использовал метаклассы с минимальной модификацией уже существующего кода.

Следующий метакласс добавляет очень простую подпрограмму к __init__ и __del__ функциям класса. Подпрограмма для __init__ увеличивает количество объектов с этим именем класса на единицу, а __del__ уменьшается на единицу.

class ObjectProfilerMeta(type):
    #Just set metaclass of a class to ObjectProfilerMeta to profile object
    def __new__(cls, name, bases, attrs):
        if name.startswith('None'):
            return None

        if "__init__" in attrs:
            attrs["__init__"]=incAndCall(name,attrs["__init__"])
        else:
            attrs["__init__"]=incAndCall(name,dummyFunction)

        if "__del__" in attrs:
            attrs["__del__"]=decAndCall(name,attrs["__del__"])
        else:
            attrs["__del__"]=decAndCall(name,dummyFunction)

        return super(ObjectProfilerMeta, cls).__new__(cls, name, bases, attrs)

    def __init__(self, name, bases, attrs):
        super(ObjectProfilerMeta, self).__init__(name, bases, attrs)


    def __add__(self, other):
        class AutoClass(self, other):
            pass
        return AutoClass

Функции incAndCall и decAndCall используют глобальную переменную модуля, в котором они существуют.

counter={}
def incAndCall(name,func):
    if name not in counter:
        counter[name]=0

    def f(*args,**kwargs):
        counter[name]+=1
        func(*args,**kwargs)

    return f

def decAndCall(name,func):
    if name not in counter:
        counter[name]=0

    def f(*args,**kwargs):
        counter[name]-=1
        func(*args,**kwargs)

    return f

def dummyFunction(*args,**kwargs):
    pass

DummyFunction - это очень простой обходной путь. Я уверен, что есть гораздо лучшие способы сделать это.

Наконец, когда вы хотите увидеть количество существующих объектов, вам просто нужно посмотреть словарь счетчиков. Пример;

>>> class A:
    __metaclass__=ObjectProfilerMeta
    def __init__(self):
        pass


>>> class B:
    __metaclass__=ObjectProfilerMeta


>>> l=[]
>>> for i in range(117):
    l.append(A())


>>> for i in range(18):
    l.append(B())


>>> counter
{'A': 117, 'B': 18}
>>> l.pop(15)
<__main__.A object at 0x01210CB0>
>>> counter
{'A': 116, 'B': 18}
>>> l=[]
>>> counter
{'A': 0, 'B': 0}

Я надеюсь, это поможет вам. В моем случае этого было достаточно.

person Utku Zihnioglu    schedule 13.02.2011

Я использовал Yappi, с которым я добился успеха для нескольких специальных многопоточных случаи. У него отличная документация, поэтому у вас не должно возникнуть особых проблем с ее настройкой.

Для профилирования памяти см. Heapy. Будьте осторожны, он может создавать одни из самых больших файлов журналов, которые вы когда-либо видели!

person KushalP    schedule 18.02.2011
comment
К сожалению, мне известны оба этих профилировщика, и я дал ссылку на связанные вопросы, в которых конкретно говорится о Yappi и Heapy. Проблема в том, что yappi не профилирует память, а heapy профилирует только использование памяти основными потоками (точнее, поток, из которого он вызывается). - person Utku Zihnioglu; 18.02.2011
comment
@KushalP. Я пробовал Yaapi, думаю, он не может дать мне построчное время выполнения. Я что-то упускаю? - person scott huang; 04.01.2018