2012-03-24 9 views
22

Desidero scoprire qual è la quantità massima di RAM allocata durante la chiamata a una funzione (in Python). Ci sono altre domande sul SO collegate a monitoraggio l'utilizzo della RAM:Tracciamento * massimo * dell'utilizzo della memoria con una funzione Python

Which Python memory profiler is recommended?

How do I profile memory usage in Python?

ma quelli sembrano consentire di più per monitorare l'utilizzo della memoria, al momento il metodo heap() (nel caso di guppy) è chiamato. Tuttavia, quello che voglio tracciare è una funzione in una libreria esterna che non posso modificare, e che cresce per usare molta RAM ma poi la libera una volta completata l'esecuzione della funzione. C'è un modo per scoprire quale è stata la quantità totale di RAM utilizzata durante la chiamata di funzione?

risposta

18

Questa domanda mi è sembrata piuttosto interessante e mi ha dato un motivo per esaminare Guppy/Heapy, per questo ti ringrazio.

Ho provato per circa 2 ore per ottenere Heapy per monitorare una funzione chiamata/processo senza modificare la sua origine con zero fortuna.

Ho trovato un modo per completare l'attività utilizzando la libreria Python integrata resource. Si noti che la documentazione non indica cosa restituisce il valore RU_MAXRSS. Un altro utente SO noted che era in kB. Eseguendo Mac OSX 7.3 e osservando le risorse del mio sistema risalire durante il codice di prova riportato di seguito, ritengo che i valori restituiti siano in byte, non in kbyte.

Una vista 10000ft su come ho usato la biblioteca resource per monitorare la chiamata di libreria è stato quello di lanciare la funzione in un thread (monitor-grado) separato e monitorare le risorse di sistema per il processo nel thread principale. Di seguito ho i due file che dovresti eseguire per testarlo.

Resource Library Monitor - whatever_you_want.py

import resource 
import time 

from stoppable_thread import StoppableThread 


class MyLibrarySniffingClass(StoppableThread): 
    def __init__(self, target_lib_call, arg1, arg2): 
     super(MyLibrarySniffingClass, self).__init__() 
     self.target_function = target_lib_call 
     self.arg1 = arg1 
     self.arg2 = arg2 
     self.results = None 

    def startup(self): 
     # Overload the startup function 
     print "Calling the Target Library Function..." 

    def cleanup(self): 
     # Overload the cleanup function 
     print "Library Call Complete" 

    def mainloop(self): 
     # Start the library Call 
     self.results = self.target_function(self.arg1, self.arg2) 

     # Kill the thread when complete 
     self.stop() 

def SomeLongRunningLibraryCall(arg1, arg2): 
    max_dict_entries = 2500 
    delay_per_entry = .005 

    some_large_dictionary = {} 
    dict_entry_count = 0 

    while(1): 
     time.sleep(delay_per_entry) 
     dict_entry_count += 1 
     some_large_dictionary[dict_entry_count]=range(10000) 

     if len(some_large_dictionary) > max_dict_entries: 
      break 

    print arg1 + " " + arg2 
    return "Good Bye World" 

if __name__ == "__main__": 
    # Lib Testing Code 
    mythread = MyLibrarySniffingClass(SomeLongRunningLibraryCall, "Hello", "World") 
    mythread.start() 

    start_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss 
    delta_mem = 0 
    max_memory = 0 
    memory_usage_refresh = .005 # Seconds 

    while(1): 
     time.sleep(memory_usage_refresh) 
     delta_mem = (resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) - start_mem 
     if delta_mem > max_memory: 
      max_memory = delta_mem 

     # Uncomment this line to see the memory usuage during run-time 
     # print "Memory Usage During Call: %d MB" % (delta_mem/1000000.0) 

     # Check to see if the library call is complete 
     if mythread.isShutdown(): 
      print mythread.results 
      break; 

    print "\nMAX Memory Usage in MB: " + str(round(max_memory/1000.0, 3)) 

Discussione Stoppable - stoppable_thread.py

import threading 
import time 

class StoppableThread(threading.Thread): 
    def __init__(self): 
     super(StoppableThread, self).__init__() 
     self.daemon = True 
     self.__monitor = threading.Event() 
     self.__monitor.set() 
     self.__has_shutdown = False 

    def run(self): 
     '''Overloads the threading.Thread.run''' 
     # Call the User's Startup functions 
     self.startup() 

     # Loop until the thread is stopped 
     while self.isRunning(): 
      self.mainloop() 

     # Clean up 
     self.cleanup() 

     # Flag to the outside world that the thread has exited 
     # AND that the cleanup is complete 
     self.__has_shutdown = True 

    def stop(self): 
     self.__monitor.clear() 

    def isRunning(self): 
     return self.__monitor.isSet() 

    def isShutdown(self): 
     return self.__has_shutdown 


    ############################### 
    ### User Defined Functions #### 
    ############################### 

    def mainloop(self): 
     ''' 
     Expected to be overwritten in a subclass!! 
     Note that Stoppable while(1) is handled in the built in "run". 
     ''' 
     pass 

    def startup(self): 
     '''Expected to be overwritten in a subclass!!''' 
     pass 

    def cleanup(self): 
     '''Expected to be overwritten in a subclass!!''' 
     pass 
+0

Grazie per la risposta dettagliata! – astrofrog

+0

@astrofrog Felice di aiutare. È qualcosa di cui posso beneficiare anche in futuro. –

+0

Inserisco questo codice come un esempio, quindi è facile scaricare i file: https://gist.github.com/b54fafd87634f017d50d – Tom

11

E 'possibile fare questo con memory_profiler. La funzione memory_usage restituisce un elenco di valori, che rappresentano l'utilizzo della memoria nel tempo (per impostazione predefinita su blocchi di 0,1 secondi). Se hai bisogno del massimo, prendi il massimo di quella lista. Piccolo esempio:

from memory_profiler import memory_usage 
from time import sleep 

def f(): 
    # a function that with growing 
    # memory consumption 
    a = [0] * 1000 
    sleep(.1) 
    b = a * 100 
    sleep(.1) 
    c = b * 100 
    return a 

mem_usage = memory_usage(f) 
print('Memory usage (in chunks of .1 seconds): %s' % mem_usage) 
print('Maximum memory usage: %s' % max(mem_usage)) 

Nel mio caso (memory_profiler 0,25) se stampe il seguente output:

Memory usage (in chunks of .1 seconds): [45.65625, 45.734375, 46.41015625, 53.734375] 
Maximum memory usage: 53.734375 
+1

soluzione brillante per Windows. https://pypi.python.org/pypi/memory_profiler ma ha anche bisogno di disinstallare psutil – mrgloom

+0

Si ferma alla console quando provo ... – Wajahat

+0

Che sistema stai usando @Wajahat? –

5

Questo sembra funzionare sotto Windows. Non so su altri sistemi operativi.

In [50]: import os 

In [51]: import psutil 

In [52]: process = psutil.Process(os.getpid()) 

In [53]: process.get_ext_memory_info().peak_wset 
Out[53]: 41934848 
+1

Credo che questo dovrebbe essere "memory_info_ex.peak_set' – gbronner

+0

Vedere i documenti. https://pythonhosted.org/psutil/#psutil.Process.memory_info Dovrebbe essere "process.memory_info(). rss' essere cross plateform –

-2

Sono stato alle prese con questo compito pure. Dopo aver sperimentato con psutil e metodi di Adam, ho scritto una funzione (crediti per Adam Lewis) per misurare la memoria utilizzata da una funzione specifica. Le persone potrebbero trovare più facile afferrare e utilizzare.

1) measure_memory_usage

2) test measure_memory_usage

ho trovato che i materiali circa threading e superclasse imperativi sono davvero utili per comprendere ciò che Adam sta facendo nei suoi scritti. Spiacente, non posso pubblicare i collegamenti a causa della mia limitazione massima "2 link".

0

È possibile utilizzare la risorsa della libreria Python per ottenere l'utilizzo della memoria.

importazione risorsa resource.getrusage (resource.RUSAGE_SELF) .ru_maxrss

Darà utilizzo della memoria in kilobyte, per convertire in MB dividere per 1000.

Problemi correlati