Функции выталкиваются из стека и появляются при возврате вызова функции. Я хотел бы знать, где в коде ядра этот push и pop на самом деле происходит.
Это не происходит в коде ядра, это делается процессором. То есть когда сборка CPU x86 находит команду call
, она нажимает IP
на стек, а команда ret
выдает это значение.
Вы можете исправить все команды call
и ret
в ядре с call my_tracing_routine
и указатель инструкции по чтению там, чем контроль прохода к исходному вызываемому абоненту/вызывающему абоненту. Есть инструменты для этого: LTTng, SystemTap, а также в ядрах, таких как kprobes, ftrace ... Этот подход называется трассировкой.
Но если патч все инструкции, т. Е. С помощью зонда SystemTap kernel.function("*")
, вы убьете производительность и, вероятно, системную панику. Таким образом, вы не можете измерить каждый вызов, но вы можете измерить каждый вызов Nth и надеяться, что вы получите эквивалентные результаты, но вам понадобится большой пример (т. Е. Запустить программу на пару минут) - это называется профилирование.
Linux поставляется с профилировщика perf
:
# perf record -- dd if=/dev/zero of=/dev/null
...
^C
# perf report
9.75% dd [kernel.kallsyms] [k] __clear_user
6.69% dd [kernel.kallsyms] [k] __audit_syscall_exit
5.61% dd [kernel.kallsyms] [k] fsnotify
4.73% dd [kernel.kallsyms] [k] system_call_after_swapgs
4.37% dd [kernel.kallsyms] [k] system_call
...
Вы также можете использовать -g
собирать цепочки вызовов. По умолчанию perf
использует счетчики производительности процессора, поэтому после N циклов процессора прерывание повышается, а первичный обработчик (он уже встроен в ядро) экономит IP
.
Если вы хотите, чтобы собрать стеки, вы можете сделать это с SystemTap:
# stap --all-modules -e '
probe timer.profile {
if(execname() == "dd") {
println("----");
print_backtrace(); }
}' -c 'dd if=/dev/zero of=/dev/null'
...
----
0xffffffff813e714d : _raw_spin_unlock_irq+0x32/0x3c [kernel]
0xffffffff81047bb9 : spin_unlock_irq+0x9/0xb [kernel]
0xffffffff8104ac68 : get_signal_to_deliver+0x4f0/0x528 [kernel]
0xffffffff8100216f : do_signal+0x48/0x4b1 [kernel]
0xffffffff81002608 : do_notify_resume+0x30/0x63 [kernel]
0xffffffff813edd6a : int_signal+0x12/0x17 [kernel]
В этом примере SystemTap использует timer.profile
зонда, который крепит к событию перфорации cpu-clock
. Для этого он генерирует, строит и загружает модуль ядра. Вы можете проверить это с помощью stap -k -p 3
С функциями вы имеете в виду системные вызовы? Или просто какая-либо функция в пользовательской области, которую вызывает ваш код, также из пользовательского поля? –
По вызову функции я имею в виду все возможные функции, выполняемые как часть выполнения процесса. Например, для операции чтения файла уровня пользователя вызывается системный вызов read(), за которым следуют функции ядра, такие как do_page_fault(), do_generic_file_read() и т. Д. – user3550605
, так как я не могу комментировать с этого момента, вы пробовали комплектование/proc/ http://man7.org/linux/man-pages/man5/proc.5.html и strace для процесса? – macmania314