2009-10-18 10 views
15

Je suis en train de profiler une méthode d'instance, donc je l'ai fait quelque chose comme:Valeur de retour lors de l'utilisation cprofile

import cProfile 

class Test(): 

    def __init__(self): 
     pass 

    def method(self): 
     cProfile.runctx("self.method_actual()", globals(), locals()) 

    def method_actual(self): 
     print "Run" 

if __name__ == "__main__": 
    Test().method() 

Mais maintenant problèmes surgissent quand je veux « méthode » pour renvoyer une valeur qui est calculée par "method_actual". Je ne veux pas vraiment appeler "method_actual" deux fois.

Y a-t-il un autre moyen, quelque chose qui peut être sûr pour les threads? (Dans ma demande, les données cprofile sont enregistrées dans les fichiers de données nommés par l'un des args, de sorte qu'ils ne reçoivent pas matraquée et je peux les combiner plus tard.)

Répondre

26

J'ai découvert que vous pouvez faire ceci:

prof = cProfile.Profile() 
retval = prof.runcall(self.method_actual, *args, **kwargs) 
prof.dump_stats(datafn) 

L'inconvénient est qu'il n'est pas documenté.

+2

Brillant! Cela semble parfait - mais qu'est-ce que 'datafn'? –

+0

@JonathanHartley - Le nom du fichier de données IIRC. – detly

+0

Ah, merci. Je pensais que 'fn' signifiait fonction, pas nom de fichier. –

6

Je luttais avec le même problème et utilisé une fonction d'emballage pour dépasser les valeurs de retour direct. Au lieu de

cP.runctx("a=foo()", globals(), locales()) 

Je crée une fonction enveloppe

def wrapper(b): 
    b.append(foo()) 

et le profil de l'appel à la fonction enveloppe

b = [] 
cP.runctx("wrapper(b)", globals(), locals()) 
a = b[0] 

extraire le résultat du calcul de foo du hors param (b) par la suite .

+0

Fonctionne comme un charme. –

18

Une option pour un code arbitraire: l »

import cProfile, pstats, sys 
pr = cProfile.Profile() 
pr.enable() 

my_return_val = my_func(my_arg) 

pr.disable() 
ps = pstats.Stats(pr, stream=sys.stdout) 
ps.print_stats() 

Taken de https://docs.python.org/2/library/profile.html#profile.Profile

+0

Vous pourriez même faire un petit gestionnaire de contexte pour cela en utilisant 'contextlib's' contextmanager' décorateur. – detly

+0

Je reçois «ordre de liste aléatoire a été utilisé» - comment puis-je spécifier l'ordre de la liste? –

+1

ps.sort_stats ('cumulatif') – marsh

1

Je pense que le @detly .runcall() est fondamentalement la meilleure réponse, mais pour être complet, je voulais juste prendre @ThomasH répondre à être fonction indépendante:

def wrapper(b, f, *myargs, **mykwargs): 
    try: 
     b.append(f(*myargs, **mykwargs)) 
    except TypeError: 
     print 'bad args passed to func.' 

# Example run 
def func(a, n): 
    return n*a + 1 

b = [] 
cProfile.runctx("wrapper(b, func, 3, n=1)", globals(), locals()) 
a = b[0] 
print 'a, ', a 
1

J'ai créé un décorateur:

import cProfile 
import functools 
import pstats 

def profile(func): 

    @functools.wraps(func) 
    def inner(*args, **kwargs): 
     profiler = cProfile.Profile() 
     profiler.enable() 
     try: 
      retval = func(*args, **kwargs) 
     finally: 
      profiler.disable() 
      with open('profile.out', 'w') as profile_file: 
       stats = pstats.Stats(profiler, stream=profile_file) 
       stats.print_stats() 
     return retval 

    return inner 

décorez votre fonction ou méthode avec elle:

@profile 
def somefunc(...): 
    ... 

Maintenant, cette fonction sera profiler.

Sinon, si vous souhaitez les données de profil brut, non traité (par exemple parce que vous voulez exécuter l'excellent RunSnakeRun spectateur graphique sur elle), puis:

import cProfile 
import functools 
import pstats 

def profile(func): 

    @functools.wraps(func) 
    def inner(*args, **kwargs): 
     profiler = cProfile.Profile() 
     profiler.enable() 
     try: 
      retval = func(*args, **kwargs) 
     finally: 
      profiler.disable() 
      profiler.dump_stats('profile.out') 
     return retval 

    return inner 

Ceci est une légère amélioration sur plusieurs les autres réponses sur cette page.

Questions connexes