Профилирование расширений Python C - PullRequest
34 голосов
/ 11 апреля 2010

Я разработал C-расширение Python, которое получает данные от Python и вычисляет некоторые интенсивные вычисления процессора. Можно ли профилировать C-расширение?

Проблема в том, что написание тестового примера в C для профилирования будет сложной задачей, поскольку код опирается на конкретные входные данные и структуры данных (генерируемые управляющим кодом python).

Есть ли у вас какие-либо предложения?

Ответы [ 4 ]

24 голосов
/ 04 марта 2011

После комментария pygabriel я решил загрузить пакет в pypi, который реализует профилировщик для расширений python, используя cpu-profiler из google-perftools: http://pypi.python.org/pypi/yep

19 голосов
/ 13 апреля 2010

Я нашел свой путь, используя google-perftools . Хитрость заключалась в том, чтобы обернуть функции StartProfiler и StopProfiler в python (через cython в моем случае).

Для профилирования расширения C достаточно обернуть код python внутри вызовов StartProfiler и StopProfiler.

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()

Затем, например, для анализа вы можете экспортировать в формате callgrind и посмотреть результат в kcachegrind:

pprof --callgrind c_extension.so output.prof > output.callgrind 
kcachegrind output.callgrind
4 голосов
/ 11 апреля 2010

С помощью gprof вы можете профилировать любую программу, которая была правильно скомпилирована и связана (gcc -pg и т. Д., В случае gprof). Если вы используете версию Python, не созданную с gcc (например, предварительно скомпилированную версию Windows, которую распространяет PSF), вам необходимо изучить, какие эквивалентные инструменты существуют для этой платформы и набора инструментов (в случае Windows PSF, возможно, mingw может помочь). Там могут быть «нерелевантные» данные (внутренние функции C во время выполнения Python), и, если это так, проценты, показанные gprof, могут быть неприменимы - но абсолютные числа (вызовов и их продолжительности) все еще остаются допустимый, и вы можете постобработать вывод gprof (например, с небольшим скриптом Python ;-), чтобы исключить ненужные данные и вычислить желаемый процент.

1 голос
/ 07 марта 2018

Один из моих коллег сказал мне ltrace(1). Это очень помогло мне в той же ситуации.

Предположим, что имя общего объекта вашего расширения C равно myext.so, и вы хотите выполнить benchmark.py, затем

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

Выходная информация равна

% 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
....

Требуется особая осторожность, если ваш общий объект имеет - или + в имени файла. Эти символы не обрабатываются как есть (подробности см. man 1 ltrace).

Подстановочный знак * может быть временным решением, например -x @myext* вместо -x @myext-2.so.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...