2009-05-09 10 views
42

Ich profile in Python mit cProfile. Ich habe eine Funktion gefunden, die viel CPU-Zeit benötigt. Wie finde ich heraus, welche Funktion diese schwere Funktion am häufigsten aufruft?Profiling in Python: Wer hat die Funktion aufgerufen?

EDIT:

ich für dieses Problem zu umgehen regeln würde: Kann ich eine Python Linie innerhalb dieser schweren Funktion schreiben, die den Namen der Funktion gedruckt werden, die sie aufgerufen?

Antwort

32

Das kann Ihre Frage nicht direkt beantworten, wird aber definitiv helfen. Wenn Sie den Profiler mit der Option --sort kumulativ verwenden, werden die Funktionen nach kumulativer Zeit sortiert. Dies ist hilfreich, um nicht nur schwere Funktionen, sondern auch die Funktionen, die sie aufrufen, zu erkennen.

python -m cProfile --sort cumulative myScript.py 

Es gibt eine Problemumgehung die CLIP-Funktion zu erhalten:

import inspect 
print inspect.getframeinfo(inspect.currentframe().f_back)[2] 

Sie können so viele f_back hinzufügen, wie Sie im Fall, dass Sie den Anrufer Anrufer etc Wenn Sie möchten, dass Sie häufige Anrufe berechnen dies tun können:

record = {} 

caller = inspect.getframeinfo(inspect.currentframe().f_back)[2] 
record[caller] = record.get(caller, 0) + 1 

Dann drucken sie sie von der Reihenfolge der Häufigkeit:

print sorted(record.items(), key=lambda a: a[1]) 
+2

Wenn Sie die Ergebnisse von cProfile in eine Datei speichern und das Modul 'pstats' verwenden, um das Profil zu laden, können Sie direkt nach den Aufrufern der schweren Funktion fragen:' loaded_stats_object.print_callers ('heavy_function') ' –

1

Ich habe cProfile nicht selbst verwendet, aber die meisten Profiler geben Ihnen eine Anrufhierarchie.
Googeln fand ich diese slides über cProfile. Vielleicht hilft das. Seite 6 sieht aus wie cProfile bietet eine Hierarchie.

+0

Link funktioniert nicht mehr – industryworker3595112

94

ich fast immer die Ausgabe der cProfile-Moduls Gprof2dot verwenden, grundsätzlich wandelt es die Ausgabe in eine graphvis Graph (a .dot-Datei), zum Beispiel:

example gprof2dot output

Es macht es sehr einfach, Bestimmen Sie, welche Funktion am langsamsten ist und welche Funktion sie aufgerufen hat.

Verbrauch ist:

python -m cProfile -o output.pstats path/to/your/script arg1 arg2 
gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png 
+2

Scheint wie ein cooles Werkzeug, muss das ausprobieren ;-) – ChristopheD

+2

+1 DAS IST F ******** BEEINDRUCKEND UND ERSTAUNLICH! Danke, dass du mir das gezeigt hast .. wow .. –

+0

Wenn du einen Ausdruck wie mit cProfile.run (exp) profilieren willst, kannst du dies verwenden (erzeugt immer noch eine temporäre pstats Datei): def run (exp, output = "profile.png", statsFileName = "Statistik.pstats "): cProfile importieren cProfile.run (exp, statsFileName) os.system (" python gprof2dot.py -fpstats% s | dot -Tpng -o% s>/dev/null 2> & 1 "% (statsFileName, output)) – Ant6n

0

Leider habe ich mit Python nicht vertraut bin, aber es gibt ein general method, das funktioniert, vorausgesetzt, Sie manuell die Ausführung zu einem beliebigen Zeitpunkt unterbrechen können.

Tun Sie es einfach und zeigen Sie den Aufruf-Stack an. Es wird Ihnen mit hoher Wahrscheinlichkeit sagen, was Sie wissen wollen. Wenn Sie sicherer sein wollen, tun Sie es einfach mehrmals.

Es funktioniert, weil der schuldige Anrufer für den Bruchteil der Zeit, die verschwendet wird, auf dem Anruf-Stack sein muss, was es für die meiste Zeit Ihren Interrupts aussetzt, ob es über viele kurze Anrufe verteilt ist oder nur wenige langwierige.

HINWEIS: Dieser Prozess ähnelt mehr der Diagnose als der Messung. Nehmen wir an, dass ein schlechter Anruf 90% der Zeit verschwendet. Dann ist jedes Mal, wenn Sie es anhalten, die Wahrscheinlichkeit 90%, dass die schlechte Call-Anweisung genau dort auf dem Call-Stack für Sie zu sehen ist, und Sie werden sehen können, dass es schlecht ist.Wenn Sie jedoch die Verschwendung genau messen möchten, ist das ein anderes Problem. Dazu benötigen Sie viel mehr Samples, um zu sehen, wie viele% dieser Aufrufe enthalten sind. Oder alternativ, einfach den schuldigen Ruf beheben, die Beschleunigung beschleunigen, und das wird dir genau sagen, was die Verschwendung war.

0

Pycscope tut dies. Ich habe es gerade heute gefunden, also kann ich nicht sagen, wie gut es ist, aber die paar Beispiele, die ich ausprobiert habe, waren ziemlich gut (wenn auch nicht perfekt).

https://pypi.python.org/pypi/pycscope/

Sie würden diese verwenden, um eine cscope-Datei zu erzeugen und dann eine cscope Plugin von einem Editor VIM speziell. Ich habe versucht, es mit Vanille cscope zu verwenden, es scheint, dass normale cscope verwirrt wird.

0

Es ist möglich, es mit Profiler cProfile in Standardbibliothek zu tun.
In pstats.Stats (das Profiler-Ergebnis) gibt es Methode print_callees (oder alternativ print_callers).


Beispielcode:

Function       called... 
             ncalls tottime cumtime 
ElementTree.py:1517(_start_list) -> 24093 0.048 0.124 ElementTree.py:1399(start) 
             46429 0.015 0.041 ElementTree.py:1490(_fixtext) 
             70522 0.015 0.015 ElementTree.py:1497(_fixname) 
ElementTree.py:1527(_data)   -> 47827 0.017 0.026 ElementTree.py:1388(data) 
             47827 0.018 0.053 ElementTree.py:1490(_fixtext) 

Auf der linken Seite haben Sie den Anrufer, auf der rechten Seite Sie den Angerufenen haben:

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

# ... do something ... 

pr.disable() 
ps = pstats.Stats(pr).strip_dirs().sort_stats('cumulative') 
ps.print_callees() 

Ergebnis wird so etwas wie sein.
(zum Beispiel _fixtext wurde aus _data 47.827 mal und von _start_list 46429 mal aufgerufen)


Siehe auch:


Paar von Noten:

  • Ihr Code muss für diese (fügen diese Profil-Anweisungen) werden bearbeitet.
    (also nicht möglich, wie python -m cProfile myscript.py von der Kommandozeile zu verwenden. Obwohl es möglich ist, dass separater Skript zu schreiben)
  • Ein bisschen in keinem Zusammenhang, aber strip_dirs() vor sort_stats() gehen muss (sonst Sortier nicht funktioniert)
+0

Dies wurde in einem der Kommentare erwähnt, aber ich dachte, dass es eine separate Antwort verdient, weil manchmal externe Tools/Abhängigkeiten nicht möglich sind . (obwohl Ausgabe ist nicht so schön, wie in anderen Antworten) – industryworker3595112

Verwandte Themen