web-dev-qa-db-fra.com

enregistrement des résultats de cProfile dans un fichier externe lisible

J'utilise cProfile essayez de profiler mes codes:

pr = cProfile.Profile()
pr.enable()
my_func()   # the code I want to profile
pr.disable()
pr.print_stats()

Cependant, les résultats sont trop longs et ne peuvent pas être entièrement affichés dans le terminal Spyder (les appels de fonction qui prennent le plus de temps à s'exécuter ne sont pas visibles ...). J'ai également essayé d'enregistrer les résultats en utilisant

 cProfile.run('my_func()','profile_results')

mais le fichier de sortie n'est pas au format lisible par l'homme (essayé avec et sans .txt suffixe).

Ma question est donc de savoir comment enregistrer les résultats du profilage dans un fichier externe qui est lisible par l'homme (comme dans un .txt format avec tous les mots correctement affichés)?

7
Physicist

Mise à jour. Vous pouvez obtenir la sortie du profileur en utilisant io.StringIO () et l'enregistrer dans un fichier. Voici un exemple:

import cProfile
import pstats
import io


def my_func():
    result = []
    for i in range(10000):
        result.append(i)

    return result

pr = cProfile.Profile()
pr.enable()

my_result = my_func()

pr.disable()
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats('tottime')
ps.print_stats()

with open('test.txt', 'w+') as f:
    f.write(s.getvalue())

Exécutez notre script et ouvrez test.txt. Vous verrez un résultat lisible:

   10002 function calls in 0.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.002    0.002    0.003    0.003 /path_to_script.py:26(my_func)
    10000    0.001    0.000    0.001    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Je peux également recommander d'utiliser dump_stats + pstats.Stats . Voici un exemple d'utilisation. Structure des fichiers:

# test_ex.py - just a small web app
import cProfile
import json
from functools import wraps
from flask import Flask

from example.mod1 import func1
from example.mod2 import func2

app = Flask(__name__)

# profiling decorator
def profiling():

    def _profiling(f):
        @wraps(f)
        def __profiling(*rgs, **kwargs):
            pr = cProfile.Profile()
            pr.enable()

            result = f(*rgs, **kwargs)

            pr.disable()
            # save stats into file
            pr.dump_stats('profile_dump')

            return result
        return __profiling
    return _profiling

# demonstration route with profiler
@app.route('/test')
@profiling()
def test():
    counter = func1()
    dict_data = func2()
    result = dict()

    for key, val in dict_data.items():
        result[key] = val + counter

    return json.dumps(result)


if __name__ == '__main__':
    app.run(debug=True, port=8083)

exemple de package - imaginons qu'il s'agit d'une sorte de logique d'application.

# example.mod1
def func1():
    counter = 0

    for i in range(100000):
        counter += i

    return counter

# example.mod2
def func2():
    res = dict()

    for i in range(300000):
        res['key_' + str(i)] = i

    return res

Maintenant, exécutons le serveur (python3 test_ex.py) et ouvrez http://localhost:8083/test. Après quelques secondes, vous verrez un long json. Après cela, vous verrez le fichier profile_dump dans le dossier du projet. Maintenant, exécutez python live interpreter dans le dossier du projet et imprimez notre vidage en utilisant pstats :

import pstats
p = pstats.Stats('profile_dump')
# skip strip_dirs() if you want to see full path's
p.strip_dirs().print_stats()

stats

Vous pouvez également trier facilement les résultats:

p.strip_dirs().sort_stats('tottime').print_stats()
p.strip_dirs().sort_stats('cumulative').print_stats()
p.strip_dirs().sort_stats().print_stats('mod1')

J'espère que cela t'aides.

12
Danila Ganchar

Vous n'avez pas vraiment besoin de StringIO, car un fichier est considéré comme un flux.

import pstats

with open("profilingStatsAsText.txt", "w") as f:
    ps = pstats.Stats("profilingResults.cprof", stream=f)
    ps.sort_stats('cumulative')
    ps.print_stats()
3

En développant la réponse précédente, vous pouvez tout vider dans un fichier .csv pour trier et jouer avec dans votre application de feuille de calcul préférée.

import pstats,StringIO

# print stats to a string
result=StringIO.StringIO()
pstats.Stats(filename,stream=result).print_stats()
result=result.getvalue()

# chop the string into a csv-like buffer
result='ncalls'+result.split('ncalls')[-1]
result='\n'.join([','.join(line.rstrip().split(None,6)) for line in result.split('\n')])

# save it to disk
f=open(filename.rsplit('.')[0]+'.csv','w')
f.write(result)
f.close()
2

vous pouvez utiliser dump_stats . Dans Python 3.8:

with cProfile.Profile() as pr:
    my_func()  

pr.dump_stats('/path/to/filename.prof')
0
Jay