用我们的计时器跟踪一个linux内核,函数功能(仅限最大)

时间:2010-04-29 01:09:22

标签: linux-kernel trace

我想知道,linux内核如何做一些事情(接收tcp数据包)。以什么顺序调用主tcp函数。我希望在用户调用"read()"后看到内核处理程序(上半部分),下半部分甚至是内核完成的工作。

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

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

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

4 个答案:

答案 0 :(得分:2)

我认为最接近部分的最接近的工具是内核 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 :(得分:1)

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

答案 2 :(得分:0)

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

也许这过于迂腐,但你看过源代码了吗?我从经验中了解到,TCP层在记录意图和引用RFC方面都得到了很好的评论。

我强烈推荐TCP / IP Illustrated,特别是第2卷,实现(website)。非常好,并逐行遍历代码。从描述中,“将500个插图与15,000行实际工作代码相结合......”。包含的源代码来自BSD内核,但堆栈非常相似,比较两者通常具有指导意义。

答案 3 :(得分:0)

这个问题很旧,可能与原版海报无关,但我最近使用的一个很有用的技巧是对我有帮助的是设置&#34;标记&#34; sk_buf的字段为某个值而且只有&#34; printk&#34;如果值匹配。

所以例如,如果你知道上半部IRQ处理程序的位置(如问题所示),那么你可以硬编码一些检查(例如tcp端口,源IP,源MAC地址,你得到的点)并设置标记为某个任意值(例如skb-> gt; mark = 0x9999)。

如果标记具有相同的值,那么一直向上只有printk。只要没有其他人改变你的标记(在我可以看到的情况下通常就是典型设置),那么你只会看到你感兴趣的数据包。

由于大多数有趣的函数都是skb,它几乎适用于所有可能有趣的函数。