2011-01-11 46 views
21

我正在使用Linux安全模块钩子为recv()系统调用添加一些自定义功能。与原始recv()相比,我想测量此功能的开销。我写了一个简单的tcp服务器,我运行并没有我的模块。这个tcp服务器调用一个recv()函数'N'次。它测量与像对各时间的recv:测量Linux内核中函数的执行时间

clock_gettime(before); 
recv() 
clock_gettime(after); 
global_time += after - before. 

最后,我打印的平均时间为单个的recv()中包含“global_time/N”。这段时间称为“user_space_avg_recv”时间。

在我的模块内部,我想要放置时间测量函数来计算我的钩子的准确执行时间。我尝试了3种方法。

  1. 我用的jiffies如下:

    sj = jiffies; 
    my_hook(); 
    ej = jiffies; 
    current->total_oh = ej - sj; 
    

    但我看到有SJ和EJ值之间没有差别。因此total_oh不变。

  2. 我用current_kernel_time(),因为我认为它返回的时间以纳秒为单位。但是,再一次,前后没有差别。

  3. 我用过get_cycles。当进程退出时,我会打印整个周期。不过,当我将总周期值转换为毫秒时,它会比“user_space_avg_recv”值大得多。这是没有意义的,因为内核中的测量值总是小于从用户空间测量的时间值。这可能意味着我要么不使用正确的API进行测量,要么在将数值从周期转换为毫秒时出错。

我基本上是用下面的公式周期转换成毫秒:

avg overhead of my hook in milliseconds = 
      (((cycles/2.99)/10^6)/N) 

2.99,因为我的时钟频率为2.99Ghz

几点:

  • 我的用户空间程序使用集合关系绑定到单个核心。

  • 我使用的内核2.6.22.14

  • 要切换上下文,而我的钩内停止的内核,我用preempt_disable()和preempt_enable()。因此它不会计算其他内核线程的执行时间。即使这样,因为我的钩子使用了一些I/O,我的线程可能会自动释放控制器,或者可能会发生一些可能会增加总周期数的中断。

问题: 如何在内核中精确测量函数执行时间?

+0

尝试禁用BIOS中的频率更改并重新测量周期 – osgx 2011-01-11 08:47:35

回答

19

您可以使用function tracer API来获取所有函数调用和返回的跟踪,并使用高精度时间戳。这包括中断事件和上下文切换。然后,您可以分析用户空间中的结果轨迹,以准确了解您的函数运行多长时间。

如果您不能使用函数跟踪器API,则可以调用do_gettimeofday()调用以获得微秒级分辨率时间戳,或者在纳秒级分辨率下获得getnstimeofday()。这些是用户空间gettimeofday()调用在内部使用的相同功能。当然,对于非常快速的功能,这可能不够准确;任何更快的准确性,你可能需要深入计时器代码,看看它如何实现周期转换。还要注意,仅仅因为它们具有高分辨率并不意味着它们具有那么高的精度 - 但它们应该用于基准测试。

注意,任何形式的跟踪将导致额外的延迟 - do_gettimeofday()需要大量的原子比较并交换操作,并且ftrace把日志代码上每一个功能前和终曲。解释结果时应考虑到这一点。

+0

是不是写为2.6.28以上?我正在使用2.6.22.14。 – Methos 2011-01-11 09:00:01

+0

@Methos:用另一种方法更新。 – bdonlan 2011-01-11 09:30:37

+1

@bdonlan,感谢您的更新。但是,do_gettimeofday()从内部读取“xtime”中的值。在number-2中提到的current_kernel_time()函数也是相同的(它在同一个文件kernel/time.c中)。正如我在第二点中所说的,我没有看到我的钩子之前和之后返回的值之间有任何时间差。 – Methos 2011-01-11 09:46:24

3

我不确定你会得到你想要的结果,但我们使用follwing代码有微秒。

double Microsecs() 
{ 
    static struct timeval _t; 
    static struct timezone tz; 
    gettimeofday(&_t, &tz); 
    return (double)_t.tv_sec + (double)_t.tv_usec/(1000*1000); 
} 

比你打电话之前和之后你想要的电话,看看它有多少时间。
我们一直使用这种方法来评估IO时间监控读/写/查找操作,以优化性能,并且我们获得了很好的结果。

HTH。

-1

您是否尝试过使用OProfile?