2011-01-25 12 views
8

¿Hay alguna manera de registrar la memoria de perfil de un programa multithread en Python?¿Cómo puedo perfilar la memoria del programa multiproceso en Python?

Para la creación de perfiles de CPU, utilizo cProfile para crear estadísticas de perfiles separadas para cada hilo y luego combinarlas. Sin embargo, no pude encontrar una manera de hacer esto con los perfiladores de memoria. Estoy usando Heapy.

¿Hay alguna manera de combinar estadísticas en heapy como el perfil c? O qué otros perfiladores de memoria sugeriría que son más adecuados para esta tarea.

Una cuestión relacionada se le pidió para el perfil de uso de la CPU por el programa multi-hilo: How can I profile a multithread program in Python?

También otra pregunta relacionada con el perfilador de memoria: Python memory profiler

+0

¿Qué no te gusta de las soluciones en esas otras preguntas? – Falmarri

+0

@Falmarri, estoy buscando un generador de perfiles de 'memoria'. El primero es principalmente un perfilador de CPU. El segundo solo funciona para un solo hilo. –

+1

La característica principal de los hilos es que comparten memoria (a diferencia de los procesos). ¿Cómo espera perfilar diferentes estadísticas de memoria para hilos que comparten la misma memoria? – scoffey

Respuesta

7

Si está contento con crear perfiles de objetos en lugar de memoria sin formato, puede usar la función gc.get_objects() para no necesitar una metaclase personalizada. En las versiones más recientes de Python, sys.getsizeof() también le permitirá intentar determinar la cantidad de memoria subyacente que utilizan esos objetos.

+0

Esto es genial. Mucho más limpio que mi enfoque. –

3

Hay maneras de conseguir valgrind al perfil memoria de los programas de Python: http://www.python.org/dev/faq/#can-i-run-valgrind-against-python

+0

Nunca escuché de valgrind antes; Definitivamente le echaré un vistazo. –

+0

@funktku esta es una herramienta estándar para perfilar el uso de memoria y detectar fugas de memoria. –

1

Ok. Lo que estaba buscando exactamente no parece existir. Entonces, encontré una solución, una solución para este problema.

En lugar de perfilar la memoria, voy a perfilar los objetos. De esta manera, podré ver cuántos objetos existen en un momento específico del programa. Para lograr mi objetivo, utilicé las metaclases con una modificación mínima al código ya existente.

La siguiente metaclase agrega una subrutina muy simple a las funciones __init__ y __del__ de la clase. La subrutina para __init__ aumenta el número de objetos con ese nombre de clase en uno y el __del__ disminuye en uno.

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 

Las funciones incAndCall y decAndCall utilizan el uso de la variable global del módulo que existen.

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 

La función dummyFunction es simplemente una solución muy simple. Estoy seguro de que hay formas mucho mejores de hacerlo.

Finalmente, siempre que quiera ver el número de objetos que existen, solo tiene que mirar el diccionario del contador. Un ejemplo;

>>> 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} 

Espero que esto te ayude. Fue suficiente para mi caso.

0

He usado Yappi, que he tenido éxito con algunas cajas especiales de múltiples hilos. Tiene una gran documentación por lo que no debería tener demasiados problemas para configurarlo.

Para perfilado específico de memoria, consulte Heapy. Ten en cuenta que puede crear algunos de los archivos de registro más grandes que hayas visto.

+0

Lamentablemente, conozco a estos dos perfiladores y proporcioné un enlace a preguntas relacionadas que hablan específicamente de Yappi y Heapy. El problema es que yappi no perfila la memoria y heapy solo perfila el uso de la memoria de los hilos principales (más precisamente el hilo desde el que se llama). –

+0

@KushalP. Intenté con Yaapi, creo que no puede dar mi tiempo de ejecución línea por línea. ¿Extraño algo? –

Cuestiones relacionadas