Профилирование с помощью GCC: получить количество вызовов функций в общей библиотеке - PullRequest
1 голос
/ 28 февраля 2011

Я бы хотел посчитать, сколько раз вызывается функция в библиотеке.У меня есть источник библиотеки C ++, но у меня нет источника исполняемого файла, который его использует. Gprof кажется популярным инструментом, но он работает только для исполняемых файлов.Я нашел очень ограниченную информацию о sprof, которая должна анализировать данные профиля, собранные во время выполнения, когда библиотека компилируется и связывается с опцией «-g».К сожалению, sprof не может открыть полученный файл профиля.Я почти отказался от попыток с sprof , так как он показывает, что это было написано много лет назад и не устарело.

Может возникнуть вопрос: знаете ли вы какой-нибудь инструмент,в сочетании с GCC, может рассчитать количество вызовов?

Ответы [ 5 ]

3 голосов
/ 28 февраля 2011

GCC, в последних версиях, имеет переключатель компилятора -finstrument-functions, который можно использовать для автоматического генерирования хуков трассировки в скомпилированном коде.См. Опции генерации кода GCC в руководстве.При этом вам даже не нужен полноценный перехватчик, только крошечная пара функций:

  • __cyg_profile_func_enter()
  • __cyg_profile_func_exit()

, которые автоматически вызываются при входе / выходе для каждого фрагмента кода, скомпилированного с опцией -finstrument-functions.
Вы бы просто связали библиотеку заглушек, которая ничего не делает (просто возвращает) для них, при обычном использовании, идругая библиотека трассировки через LD_PRELOAD позже, если вы хотите фактически записать вызовы.

Обратите внимание, что аргументы, передаваемые этим хукам сайта трассировки, являются адресами вызываемой функции и вызывающей стороны;чтобы дать имена, вам нужно будет передать их через таблицу символов, которую лучше всего сделать вне самой трассировки.

Пример кода (на самом деле, быстрый Google): здесь , здесь или здесь .

1 голос
/ 28 февраля 2011

Вы должны быть в состоянии сделать это с помощью ltrace , запустить вашу программу с ltrace -c -l yourlibrary или сбросить -l, чтобы получить счетчик всех вызовов динамической библиотеки.

0 голосов
/ 28 февраля 2011

Вы можете использовать systemtap , чтобы получить счетчик вызовов функций.Это мощный инструмент, который позволяет вам обрабатывать во время выполнения любое приложение без необходимости его перекомпиляции, требуются только символы отладки.

Вот скрипт, который подсчитывает количество вызовов функции вместе с ее выполнениемвремя в наносекундах:

# call-counts.stp

global calls, times

probe process(@1).function(@2) {
    times[probefunc()] = gettimeofday_ns()
}

probe process(@1).function(@2).return {
    now = gettimeofday_ns()
    delta = now - times[probefunc()]
    calls[probefunc()] <<< delta
}

Вот как его использовать для подсчета вызовов getenv() в /lib64/libc-2.12.2.so при запуске ls -1:

$ sudo stap -c "ls -1" ~/tmp/count-calls.stp /lib64/libc-2.12.2.so getenv
binned_market_data
count-calls.stp
count-calls.stp~
Makefile
md
nohup.out
calls["getenv"] @count=23 @min=4841 @max=19257 @sum=142529 @avg=6196

Другой пример просмотра вызовов функций "str *":

$ sudo stap -c "ls -1" ~/tmp/count-calls.stp /lib64/libc-2.12.2.so "str*"
binned_market_data
count-calls.stp
count-calls.stp~
Makefile
md
nohup.out
calls["__strdup"] @count=14 @min=5035 @max=10664 @sum=80479 @avg=5748
calls["strcoll"] @count=11 @min=11626 @max=20018 @sum=140851 @avg=12804
calls["__strcoll_l"] @count=11 @min=4992 @max=9393 @sum=63179 @avg=5743
calls["strstr_ifunc"] @count=2 @min=4902 @max=7429 @sum=12331 @avg=6165
0 голосов
/ 28 февраля 2011

Если это динамическая библиотека (DLL), вы можете просто перекомпилировать ее так, чтобы она подсчитывала и распечатывала число, которое увеличивается при каждом вызове функции, как файл или по сети

0 голосов
/ 28 февраля 2011

Вы можете сделать это довольно легко с помощью библиотеки LD_PRELOAD. Вы пишете библиотеку, которая перехватывает вызовы функции, которую вы используете, увеличивает счетчик, а затем вызывает исходную реализацию (путем разделения общего объекта и вызова в него). Затем вы запускаете LD_PRELOAD вашу библиотеку-перехватчик при запуске исполняемого файла, и она выдает свои значения в _exit (или SIGUSR1, или всякий раз).

Это работает без какой-либо программной поддержки, кроме загрузчика динамических библиотек, и является обычной техникой для косвенного обращения к библиотекам, даже если источник недоступен.

...