测量linux内核中函数的执行时间

时间:2011-01-11 08:45:09

标签: linux-kernel

我正在使用Linux安全模块挂钩为recv()系统调用添加一些自定义功能。与pristine recv()相比,我想测量此功能的开销。我编写了一个简单的tcp服务器,我运行和没有我的模块。此tcp服务器调用recv()函数'N'次。它用以下的方式测量每个recv所用的时间:

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

最后,我使用“global_time / N”打印单个recv()的平均时间。让我们把这次称为“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进行测量,要么在将值从周期转换为毫秒时出错。

  4. 我基本上使用以下公式将周期转换为毫秒:

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

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

    有些观点:

    • 我的用户空间程序使用set affinity绑定到单个核心。

    • 我使用的是内核2.6.22.14

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

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

3 个答案:

答案 0 :(得分:21)

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

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

请注意,任何形式的跟踪都会导致额外的延迟 - do_gettimeofday()需要进行大量的原子比较和交换操作,并且ftrace将日志记录代码放在每个函数的前后码上。在解释结果时应该考虑到这一点。

答案 1 :(得分:3)

我不确定你会得到你想要的结果,但我们使用以下代码来获得微秒。

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。

答案 2 :(得分:0)

您是否尝试过使用OProfile?

相关问题