Profiling von Python-C-Erweiterungen

Lesezeit: 4 Minuten

Ich habe eine Python-C-Erweiterung entwickelt, die Daten von Python empfängt und einige CPU-intensive Berechnungen durchführt. Ist es möglich, die C-Erweiterung zu profilieren?

Das Problem dabei ist, dass das Schreiben eines Beispieltests in C, der profiliert werden soll, eine Herausforderung darstellen würde, da der Code auf bestimmten Eingaben und Datenstrukturen beruht (generiert durch Python-Steuercode).

Haben Sie Vorschläge?

Nach dem Kommentar von pygabriel habe ich mich entschieden, ein Paket auf pypi hochzuladen, das einen Profiler für Python-Erweiterungen mit dem cpu-profiler von google-perftools implementiert: http://pypi.python.org/pypi/yep

  • Danke, ich fand das wirklich nützlich und es war ziemlich einfach, damit loszulegen!

    – Raub

    15. März 2011 um 20:29 Uhr

  • Das ist großartig und sehr einfach zu bedienen. Vielen Dank.

    – rd11

    12. August 2015 um 12:42 Uhr

  • Wie benutzt man es unter Windows?

    – Mudit Jain

    19. Januar 2018 um 6:56 Uhr

Benutzeravatar von pygabriel
Pygabriel

Ich habe meinen Weg gefunden mit google-perftools. Der Trick bestand darin, die Funktionen StartProfiler und StopProfiler in Python zu verpacken (in meinem Fall durch Cython).

Um die C-Erweiterung zu profilieren, reicht es aus, den Python-Code in die StartProfiler- und StopProfiler-Aufrufe einzuschließen.

from google_perftools_wrapped import StartProfiler, StopProfiler
import c_extension # extension to profile c_extension.so

StartProfiler("output.prof")
... calling the interesting functions from the C extension module ...
StopProfiler()

Zur Analyse können Sie dann beispielsweise im Callgrind-Format exportieren und das Ergebnis in kcachegrind anzeigen:

pprof --callgrind c_extension.so output.prof > output.callgrind 
kcachegrind output.callgrind

  • Vielen Dank für diesen Hinweis!! Ich habe eigentlich nach dem gleichen gesucht. Ich werde versuchen.

    – ThR37

    7. Oktober 2010 um 14:35 Uhr

  • EDIT: Es funktioniert tatsächlich perfekt! Ein einfacher Wrapper mit ctypes ist in Ordnung, auch wenn ich manchmal Segfaults während der CPU-Profilierung bekomme (aber das ist “normal” und in der Dokumentation erklärt … Ich verwende x86_64 🙁 )

    – ThR37

    7. Oktober 2010 um 15:28 Uhr

  • Vielen Dank für dieses kleine Nugget. Es war sehr, sehr nützlich 🙂 Was ich sehe, ist, dass pprof (oder besser gesagt, google-pprof im Paket für Debian) nicht so viele Symbole entstellt erhalte, wie ich es beim Profilieren von tun würde gleichen Code mit valgrind. Kann es sein, dass ich beim Kompilieren -pg angeben muss?

    – Miquel Ramírez

    20. August 2013 um 6:29 Uhr

  • Die Verbindung ist unterbrochen. Ich habe hier einen funktionierenden Link gefunden: github.com/google/pprof

    – MaBekitsur

    10. Mai 2020 um 7:07 Uhr


  • Wäre es möglich, Heap-Profiling auf diese Weise durchzuführen?

    – der Frosch

    4. Juni 2021 um 10:40 Uhr

Benutzeravatar von somay
somai

Einer meiner Kollegen hat es mir gesagt ltrace(1). Es hat mir in der gleichen Situation sehr geholfen.

Angenommen, der Name des gemeinsam genutzten Objekts Ihrer C-Erweiterung lautet myext.so und Sie ausführen möchten benchmark.pydann

ltrace -x @myext.so -c python benchmark.py

Seine Ausgabe ist wie

% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 24.88   30.202126     7550531         4 ldap_result
 12.46   15.117625     7558812         2 l_ldap_result4
 12.41   15.059652     5019884         3 ldap_chase_v3referrals
 12.41   15.057678     3764419         4 ldap_new_connection
 12.40   15.050310     3762577         4 ldap_int_open_connection
 12.39   15.042360     3008472         5 ldap_send_server_request
 12.38   15.029055     3757263         4 ldap_connect_to_host
  0.05    0.057890       28945         2 ldap_get_option
  0.04    0.052182       26091         2 ldap_sasl_bind
  0.03    0.030760       30760         1 l_ldap_get_option
  0.03    0.030635       30635         1 LDAP_get_option
  0.02    0.029960       14980         2 ldap_initialize
  0.02    0.027988       27988         1 ldap_int_initialize
  0.02    0.026722       26722         1 l_ldap_simple_bind
  0.02    0.026386       13193         2 ldap_send_initial_request
  0.02    0.025810       12905         2 ldap_int_select
....

Besondere Sorgfalt ist erforderlich, wenn Ihr gemeinsames Objekt dies hat - oder + in seinem Dateinamen. Diese Zeichen werden nicht unverändert behandelt (siehe man 1 ltrace für Details).

Die Wildcard * kann eine Problemumgehung sein, z -x @myext* anstelle von -x @myext-2.so.

Mit gprofkönnen Sie jedes Programm profilieren, das war richtig zusammengestellt und verlinkt (gcc -pg usw., hinein gprofs Fall). Wenn Sie eine Python-Version verwenden, die nicht mit erstellt wurde gcc (z. B. die vorkompilierte Windows-Version, die das PSF verteilt), müssen Sie recherchieren, welche äquivalenten Tools für diese Plattform und Toolchain existieren (im Fall von Windows PSF vielleicht). mingw kann helfen). Dort können “irrelevante” Daten stehen (interne C-Funktionen in der Python-Laufzeit), und wenn ja, die Prozentsätze, die von angezeigt werden gprof möglicherweise nicht zutreffend — aber die absoluten Zahlen (der Anrufe und deren Dauer) sind immer noch gültig, und Sie können sie nachbearbeiten gprof‘s Ausgabe (z. B. mit einem kleinen Python-Skript;-), um die irrelevanten Daten auszuschließen und die gewünschten Prozentsätze zu berechnen.

Benutzeravatar von Hammer
Hammer

ich fand Spionage sehr einfach zu bedienen. Sehen diesen Blogbeitrag für eine Erläuterung der nativen Erweiterungsunterstützung.

Höhepunkte:

  • Pip installierbar
  • CPU-Sampling basiert
  • keine Compiler-Flags erforderlich
  • führt Ihr Programm aus oder hängt sich an einen laufenden Prozess an
  • mehrere Ausgabeformate (ich empfehle --format speedscope)
  • konfigurierbare Abtastrate

  • Dies sollte die Top-Antwort sein!

    – Labor

    6. September 2020 um 18:30 Uhr

  • Dies sollte die Top-Antwort sein!

    – Labor

    6. September 2020 um 18:30 Uhr

1408310cookie-checkProfiling von Python-C-Erweiterungen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy