Je veux savoir quelle est la quantité maximale de RAM allouée lors de l'appel d'une fonction (en Python). Il y a d'autres questions sur SO liées au suivi de l'utilisation de RAM:
Quel profileur de mémoire Python est recommandé?
Comment profiler l'utilisation de la mémoire en Python?
mais ceux-ci semblent vous permettre davantage de suivre l'utilisation de la mémoire au moment où la méthode heap()
(dans le cas de guppy) est appelée. Cependant, ce que je veux suivre est une fonction dans une bibliothèque externe que je ne peux pas modifier et qui utilise de plus en plus de RAM, mais la libère une fois l'exécution de la fonction terminée. Existe-t-il un moyen de savoir quelle est la quantité totale de RAM utilisée lors de l'appel de fonction?
Cette question semblait plutôt intéressante et m'a donné une raison de regarder Guppy/Heapy, je vous en remercie.
J'ai essayé pendant environ 2 heures de faire surveiller par Heapy un appel/un processus sans modifier sa source avec zéro chance.
J'ai trouvé un moyen d'accomplir votre tâche en utilisant la bibliothèque Python intégrée resource
. Notez que la documentation n'indique pas ce que la valeur RU_MAXRSS
renvoie. Un autre SO utilisateur a noté qu'il était en Ko. Exécuter Mac OSX 7.3 et regarder mes ressources système grimper pendant le code de test ci-dessous, je pense que les valeurs renvoyées sont en octets, pas en kilo-octets.
Une vue de 10 000 pieds sur la façon dont j'ai utilisé la bibliothèque resource
pour surveiller l'appel de bibliothèque a été de lancer la fonction dans un thread séparé (pouvant être contrôlé) et de suivre les ressources système pour ce processus dans le thread principal. Ci-dessous, j'ai les deux fichiers que vous devez exécuter pour le tester.
Moniteur de ressources de bibliothèque - any_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 __== "__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))
Stoppable Thread - 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
Il est possible de faire cela avec memory_profiler . La fonction memory_usage
renvoie une liste de valeurs, qui représentent l'utilisation de la mémoire au fil du temps (par défaut sur des fragments de 0,1 seconde). Si vous avez besoin du maximum, prenez simplement le maximum de cette liste. Petit exemple:
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))
Dans mon cas (memory_profiler 0.25) si imprime la sortie suivante:
Memory usage (in chunks of .1 seconds): [45.65625, 45.734375, 46.41015625, 53.734375]
Maximum memory usage: 53.734375
Cela semble fonctionner sous Windows. Je ne sais pas sur les autres systèmes d'exploitation.
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
Vous pouvez utiliser une ressource de la bibliothèque python pour obtenir l’utilisation de la mémoire.
import resource
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
Il donnera l'utilisation de la mémoire en kilo-octets, pour convertir en diviser par 1000 Mo.
L'utilitaire Unix standard time
suit l'utilisation maximale de la mémoire du processus ainsi que d'autres statistiques utiles pour votre programme.
Exemple de sortie (maxresident
est l'utilisation maximale de la mémoire, en kilo-octets.):
> time python ./scalabilty_test.py
45.31user 1.86system 0:47.23elapsed 99%CPU (0avgtext+0avgdata 369824maxresident)k
0inputs+100208outputs (0major+99494minor)pagefaults 0swaps