отслеживание ядра Linux, функция за функцией (только самая большая) с использованием таймера - PullRequest
3 голосов
/ 29 апреля 2010

Я хочу знать, как ядро ​​Linux делает что-то (получая пакет tcp). В каком порядке вызываются основные функции tcp. Я хочу видеть обработчик прерываний (верхняя половина), нижнюю половину и даже работу, выполняемую ядром после пользовательских вызовов "read()".

Как получить трассировку функции от ядра с линейной шкалой времени?

Я хочу получить трассировку от одного пакета, а не от профиля ядра при получении 1000-го пакета.

Ядро 2.6.18 или 2.6.23 (поддерживается в моем Debian). Я могу добавить к нему несколько патчей.

Ответы [ 4 ]

2 голосов
/ 30 марта 2011

Я думаю, что ближайший инструмент, который хотя бы частично может достичь того, чего вы хотите, это ядро ​​ ftrace . Вот пример использования:

root@ansis-xeon:/sys/kernel/debug/tracing# cat available_tracers 
blk function_graph mmiotrace function sched_switch nop
root@ansis-xeon:/sys/kernel/debug/tracing# echo 1 > ./tracing_on 
root@ansis-xeon:/sys/kernel/debug/tracing# echo function_graph > ./current_trace
root@ansis-xeon:/sys/kernel/debug/tracing# cat trace

 3)   0.379 us    |        __dequeue_entity();
 3)   1.552 us    |      }
 3)   0.300 us    |      hrtick_start_fair();
 3)   2.803 us    |    }
 3)   0.304 us    |    perf_event_task_sched_out();
 3)   0.287 us    |    __phys_addr();
 3)   0.382 us    |    native_load_sp0();
 3)   0.290 us    |    native_load_tls();
 ------------------------------------------
 3)    <idle>-0    =>  ubuntuo-2079 
 ------------------------------------------

 3)   0.509 us    |              __math_state_restore();
 3)               |              finish_task_switch() {
 3)   0.337 us    |                perf_event_task_sched_in();
 3)   0.971 us    |              }
 3) ! 100015.0 us |            }
 3)               |            hrtimer_cancel() {
 3)               |              hrtimer_try_to_cancel() {
 3)               |                lock_hrtimer_base() {
 3)   0.327 us    |                  _spin_lock_irqsave();
 3)   0.897 us    |                }
 3)   0.305 us    |                _spin_unlock_irqrestore();
 3)   2.185 us    |              }
 3)   2.749 us    |            }
 3) ! 100022.5 us |          }
 3) ! 100023.2 us |        }
 3)   0.704 us    |        fget_light();
 3)   0.522 us    |        pipe_poll();
 3)   0.342 us    |        fput();
 3)   0.476 us    |        fget_light();
 3)   0.467 us    |        pipe_poll();
 3)   0.292 us    |        fput();
 3)   0.394 us    |        fget_light();
 3)               |        inotify_poll() {
 3)               |          mutex_lock() {
 3)   0.285 us    |            _cond_resched();
 3)   1.134 us    |          }
 3)   0.289 us    |          fsnotify_notify_queue_is_empty();
 3)               |          mutex_unlock() {
 3)   2.987 us    |        }
 3)   0.292 us    |        fput();
 3)   0.517 us    |        fget_light();
 3)   0.415 us    |        pipe_poll();
 3)   0.292 us    |        fput();
 3)   0.504 us    |        fget_light();
 3)               |        sock_poll() {
 3)   0.480 us    |          unix_poll();
 3)   4.224 us    |        }
 3)   0.183 us    |        fput();
 3)   0.341 us    |        fget_light();
 3)               |        sock_poll() {
 3)   0.274 us    |          unix_poll();
 3)   0.731 us    |        }
 3)   0.182 us    |        fput();
 3)   0.269 us    |        fget_light();

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

Если этого недостаточно, используйте GDB. Но, как вы, возможно, уже знаете, настройка GDB для отладки ядра не так проста, как для процессов в пользовательском пространстве. Я предпочитаю использовать GDB + qemu, если это необходимо.

Счастливого отслеживания!

1 голос
/ 29 апреля 2010

Вы хотите oprofile . Он может дать вам время для (выбранного подмножества) всей вашей системы, что означает, что вы можете отслеживать сетевую активность от устройства до приложения и обратно через ядро ​​и все библиотеки.

0 голосов
/ 26 июля 2015

Этот вопрос старый и, вероятно, не имеет отношения к оригинальному постеру, но в последнее время я использовал один хороший трюк, который мне пригодился, чтобы установить для поля «mark» в sk_buf какое-то значение и только «printk», если значение спички.

Так, например, если вы знаете, где находится верхняя половина обработчика IRQ (как следует из вопроса), то вы можете жестко закодировать некоторую проверку (например, порт tcp, IP-адрес источника, MAC-адрес источника, хорошо, вы поняли точку) и установить метка к некоторому произвольному значению (например, skb-> mark = 0x9999).

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

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

0 голосов
/ 29 апреля 2010

Я не могу сразу увидеть способ отследить только один пакет за раз. В частности, может быть трудно получить такую ​​мелкозернистую трассировку, поскольку верхняя половина обработчика прерываний не должна делать ничего блокирующего (это склонно к тупиковой блокировке).

Может быть, это слишком педантично, но вы взглянули на исходный код? Я знаю по своему опыту, что уровень TCP очень хорошо прокомментирован, как для записи намерений, так и для ссылок на RFC.

Я настоятельно рекомендую TCP / IP Illustrated, особенно том 2, Реализация ( веб-сайт ). Это очень хорошо, и проходит по коду построчно. Из описания «Объединение 500 иллюстраций с 15 000 строк реального, рабочего кода ...». Включенный исходный код взят из ядра BSD, но стеки чрезвычайно похожи, и сравнение двух часто бывает поучительным.

...