График функции (вход и выход с отметкой времени) для пользователя, библиотеки и пространства ядра в Linux?
Я пишу это более-менее разочарованно - но кто знает, может быть, есть способ и для этого...
Я хотел бы проанализировать, что происходит с функцией из ALSA, скажем, snd_pcm_readi
; для этого, скажем, я подготовил небольшой testprogram.c
где у меня это:
void doCapture() {
ret = snd_pcm_readi(handle, buffer, period_size);
}
Проблема с этой функцией заключается в том, что она в конечном итоге (должна) подключиться к snd_pcm_readi
в общей системной библиотеке /usr/lib/libasound.so
; оттуда я верю через ioctl
было бы как-то общаться с snd_pcm_read
в модуле ядра /lib/modules/$(uname -r)/kernel/sound/core/snd-pcm.ko
- и это должно в конечном итоге говорить с чем угодно .ko
модуль ядра, который является драйвером для конкретной звуковой карты.
Теперь, с организацией, как указано выше, я могу сделать что-то вроде:
valgrind --tool=callgrind --toggle-collect=doCapture ./testprogram
... а потом kcachegrind callgrind.out.12406
действительно показывает связь между snd_pcm_readi
, libasound.so
и ioctl
(Я не могу получить ту же информацию, чтобы показать с callgrind_annotate
) - так, что несколько охватывает пользовательское пространство; но это так далеко, как это идет. Кроме того, он генерирует граф вызовов, то есть общие отношения вызывающего / вызываемого абонентов между функциями (возможно, путем подсчета выборок / тиков, которые каждая функция потратила на работу по графику).
Тем не менее, то, что я хотел бы получить вместо этого, это что-то вроде вывода Linux ftrace
трассировщик называется function_graph
, который обеспечивает временную отметку входа и выхода отслеживаемых функций ядра... пример из ftrace: добавить документацию для функции graph tracer [LWN.net]:
$ cat /sys/kernel/debug/tracing/trace
# tracer: function_graph
#
# TIME CPU DURATION FUNCTION CALLS
# | | | | | | | |
2105.963678 | 0) | mutex_unlock() {
2105.963682 | 0) 5.715 us | __mutex_unlock_slowpath();
2105.963693 | 0) + 14.700 us | }
2105.963698 | 0) | dnotify_parent() {
(NB: новее ftrace
сначала документация не показывает временную метку для function\_graph
, только продолжительность - но я думаю, что это все еще можно изменить)
С ftrace
можно фильтровать, чтобы можно было только отслеживать функции в данном модуле ядра - так что в моем случае я мог бы добавить функции snd-pcm.ko
и все .ko
Модуль - это драйвер звуковой карты, и я хотел бы, чтобы все, что я нахожу интересным, охватывало пространство ядра. Но затем я теряю ссылку на программу пользовательского пространства (если я явно не printf
в /sys/kernel/debug/tracing/trace_marker
или сделать trace_printk
из пространства пользователя .c
файлы)
В конечном итоге, мне бы хотелось иметь возможность указать исполняемый файл, возможно, также библиотечные файлы и модули ядра, и получить график функции с метками времени (с отступом / вложенным входом и выходом для каждой функции), например ftrace
обеспечивает. Есть ли альтернативы для чего-то подобного? (Обратите внимание, что я могу жить без выхода из функции - но мне бы очень хотелось иметь временные метки для записей функций)
Как PS: кажется, я действительно нашел то, что соответствует описанию, которое является fulltrace
Приложение / скрипт:
fulltrace отслеживает выполнение программы ELF, предоставляя в качестве вывода полную трассировку вызовов ее пользовательского пространства, библиотеки и функций ядра....
(предварительные условия) следующие включенные параметры конфигурации ядра и их зависимости должны быть включены (=y): FTRACE, TRACING_SUPPORT, UPROBES, UPROBE_EVENT, FUNCTION_GRAPH_TRACER.
Звучит идеально - но проблема в том, что я на Ubuntu 11.04, и пока это 2.6.38
Ядро, к счастью, имеет CONFIG_FTRACE=y
включен - его /boot/config-`uname -r`
даже не упоминает UPROBES
: / Так как я хотел бы избежать взлома ядра, к сожалению, я не могу использовать этот скрипт...
(Между прочим, если бы UPROBES были доступны, (насколько я понимаю) каждый устанавливает зонд трассировки на адрес символа (как получено из, скажем, objdump -d
), и вывод снова идет в /sys/kernel/debug/tracing/trace
- так что некоторые нестандартные решения были бы возможны с использованием UPROBES, даже без fulltrace
сценарий)
Итак, чтобы немного сузить мой вопрос - есть ли решение, которое позволило бы одновременно выполнять трассировку "графа функций" в пространстве пользователя (включая разделяемые библиотеки) и в пространстве ядра, но где UPROBES
не доступны в ядре?