2011-01-25 3 views
8

C'è un modo per profilare la memoria di un programma multithread in Python?Come posso profilare la memoria del programma multithread in Python?

Per il profilo della CPU, sto utilizzando il cProfile per creare statistiche separate del profiler per ogni thread e successivamente combinarle. Tuttavia, non sono riuscito a trovare un modo per farlo con i profiler della memoria. Sto usando un po 'di soldi.

C'è un modo per combinare le statistiche in un heap come il cProfile? O quali altri profiler di memoria suggeriresti che siano più adatti a questo compito.

Una questione collegata è stato chiesto per la profilatura l'utilizzo della CPU sul programma multi-thread: How can I profile a multithread program in Python?

anche un'altra domanda per quanto riguarda il profiler di memoria: Python memory profiler

+0

Cosa non ti piace delle soluzioni in quelle altre domande? – Falmarri

+0

@Falmarri, sto cercando un profiler 'memoria'. Il primo è principalmente un profilo della CPU. Il secondo funziona solo per un singolo thread. –

+1

La caratteristica principale dei thread è che condividono la memoria (al contrario dei processi). Come ti aspetti di profilare diverse statistiche di memoria per i thread che condividono la stessa memoria? – scoffey

risposta

7

Se si è soddisfatti degli oggetti profilo anziché della memoria non elaborata, è possibile utilizzare la funzione gc.get_objects() in modo da non aver bisogno di un metaclasse personalizzato. Nelle versioni più recenti di Python, lo sys.getsizeof() ti consente anche di capire quanta memoria sottostante è in uso da quegli oggetti.

+0

Questo è fantastico. Molto più pulito del mio approccio. –

3

Ci sono modi per ottenere Valgrind al profilo di memoria dei programmi Python: http://www.python.org/dev/faq/#can-i-run-valgrind-against-python

+0

Mai sentito parlare di valgrind prima; lo controlleremo sicuramente. –

+0

@funktku questo è uno strumento standard per profilare l'utilizzo della memoria e rilevare perdite di memoria. –

1

Ok. Quello che stavo cercando esattamente non sembra esistere. Quindi, ho trovato una soluzione, una soluzione per questo problema.

Invece della memoria di profilazione, eseguirò il profilo degli oggetti. In questo modo, sarò in grado di vedere quanti oggetti esistono in un momento specifico nel programma. Per raggiungere il mio obiettivo, ho fatto uso di metaclassi con modifiche minime al codice già esistente.

Il seguente metaclasse aggiunge una subroutine molto semplice alle funzioni __init__ e __del__ della classe. La subroutine per __init__ aumenta di uno il numero di oggetti con quel nome di classe e lo __del__ diminuisce di 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 

Le funzioni incAndCall e decAndCall utilizzano la variabile globale di utilizzo del modulo esistente.

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 

Il dummyFunction è solo una soluzione molto semplice. Sono sicuro che ci sono modi molto migliori per farlo.

Infine, ogni volta che si desidera vedere il numero di oggetti esistenti, è sufficiente consultare il dizionario del contatore. Un esempio;

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

Spero che questo ti aiuta. Era sufficiente per il mio caso.

0

Ho usato Yappi, con cui ho avuto successo per alcuni casi speciali multi-thread. Ha un'ottima documentazione, quindi non dovresti avere troppi problemi a configurarlo.

Per la profilatura specifica della memoria, vedere Heapy. Stai attento, potrebbe creare alcuni dei file di registro più grandi che tu abbia mai visto!

+0

Sfortunatamente sono a conoscenza di entrambi questi profiler e ho fornito link a domande correlate che parlano specificamente di Yappi e Heapy. Il problema è che yappi non profila la memoria e solo i profili un po 'pesanti l'uso della memoria dei thread principali (più precisamente il thread da cui è chiamato). –

+0

@KushalP. Ho provato Yaapi, penso che non possa dare il mio tempo di esecuzione linea per linea. Mi manca qualcosa? –