2015-04-19 3 views
1

Я пытаюсь контролировать, какие функции вызываются процессом во время его выполнения. Моя цель - узнать, сколько времени процесс проводит в каждой функции. Функции перетаскиваются поверх стека и появляются при возврате вызова функции. Я хотел бы знать, где в коде ядра этот push и pop на самом деле происходит.Как получить доступ к стеку ядра процесса в ядре Linux?

Я нашел поле void *stack в task_struct. Я не уверен, что это поле, которое я ищу. Если да, то каков способ узнать, как он обновляется?

Мне нужно написать модуль, который будет использовать этот код. Пожалуйста, помогите мне в этом случае.

+0

С функциями вы имеете в виду системные вызовы? Или просто какая-либо функция в пользовательской области, которую вызывает ваш код, также из пользовательского поля? –

+0

По вызову функции я имею в виду все возможные функции, выполняемые как часть выполнения процесса. Например, для операции чтения файла уровня пользователя вызывается системный вызов read(), за которым следуют функции ядра, такие как do_page_fault(), do_generic_file_read() и т. Д. – user3550605

+0

, так как я не могу комментировать с этого момента, вы пробовали комплектование/proc/ http://man7.org/linux/man-pages/man5/proc.5.html и strace для процесса? – macmania314

ответ

2

Функции выталкиваются из стека и появляются при возврате вызова функции. Я хотел бы знать, где в коде ядра этот 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

+0

Спасибо за тщательный ответ! Не могли бы вы рассказать о выходе продукта SystemTap? Чтобы получить выход формы, как указано выше (трассировка стека), где в коде ядра используются перформанс или утилиты SystemTap, внесенные изменения/обновления? – user3550605

Смежные вопросы