使用我们的计时器跟踪Linux内核,逐个函数(仅最大)

问题描述 投票:4回答:4

我想知道,Linux内核如何做一些事情(接收tcp数据包)。主要tcp函数以什么顺序被调用。我想同时查看中断处理程序(上半部分),下半部分,甚至在用户调用"read()"之后由内核完成的工作。

如何从内核获取具有线性时间标度的函数跟踪?

我想从单个数据包中获取跟踪,而不是在接收第1000个数据包时获取内核的配置文件。

内核是2.6.18或2.6.23(在我的debian中受支持)。我可以添加一些补丁。

linux-kernel trace
4个回答
4
投票

我认为至少可以实现您想要的目标的最接近的工具是内核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。

追踪愉快!

更新:在以后的Linux发行版中,我建议使用trace-cmd命令行工具,将其“包裹”在/sys/kernel/debug/tracing周围。 trace-cmd使用起来比原始接口内核提供的直观得多。


1
投票

您想要oprofile。它可以为您提供整个系统(选定的子集)的时间,这意味着您可以跟踪从设备到应用程序的网络活动,并通过内核和所有库再次追溯。


0
投票

我无法立即看到一次仅跟踪一个数据包的方法。特别是,可能很难获得这种细粒度的跟踪,因为中断处理程序的上半部分不应该进行任何阻塞(这很容易发生死锁)。

也许这过于花哨,但您是否看过源代码?我从经验中知道,在记录意图和引用RFC方面,TCP层都得到了很好的注释。

我强烈建议使用TCP / IP图解,特别是第2卷,实现(website)。它非常好,并且逐行遍历代码。在描述中,“将500个插图与15,000行真实有效的代码相结合...”。包含的源代码来自BSD内核,但是堆栈极其相似,因此将两者进行比较通常是有启发性的。


0
投票

此问题很旧,可能与原始海报无关,但是我最近使用的一个不错的技巧对我很有帮助,那就是将sk_buf的“ mark”字段设置为某个值,如果该值匹配则仅设置“ printk” 。

因此,例如,如果您知道上半部分IRQ处理程序(如问题所提示的那样),则可以对某些检查进行硬编码(例如tcp端口,源IP,源MAC地址,好了,您就可以了)。标记为任意值(例如skb-> mark = 0x9999)。

然后一直到您仅在标记具有相同的值时才打印。只要没有其他人更改您的标记(就我所知,在典型设置中通常是这种情况),那么您只会看到您感兴趣的数据包。

由于大多数有趣的函数都得到了skb,所以它几乎可以处理所有可能有趣的事情。

© www.soinside.com 2019 - 2024. All rights reserved.