技术开发 频道

Linux驱动开发必看:详解神秘内核

  2.4.3 短延时

  在内核中,小于jiffy的延时被认为是短延时。这种延时在进程或中断上下文都可能发生。由于不可能使用基于jiffy的方法实现短延时,之前讨论的睡眠等待将不再能用于短的超时。这种情况下,唯一的解决途径就是忙等待。

  实现短延时的内核API包括mdelay()、udelay()和ndelay(),分别支持毫秒、微秒和纳秒级的延时。这些函数的实际实现取决于体系架构,而且也并非在所有平台上都被完整实现。

  忙等待的实现方法是测量处理器执行一条指令的时间,为了延时,执行一定数量的指令。从前文可知,内核会在启动过程中进行测量并将该值存储在loops_per_jiffy变量中。短延时API就使用了loops_per_jiffy值来决定它们需要进行循环的数量。为了实现握手进程中1微秒的延时,USB主机控制器驱动程序(drivers/usb/host/ehci-hcd.c)会调用udelay(),而udelay()会内部调用loops_per_jiffy:

do {
  result
= ehci_readl(ehci, ptr);
  
/* ... */
  
if (result == done) return 0;
  udelay(
1);     /* Internally uses loops_per_jiffy */
  usec
--;
}
while (usec > 0);

  2.4.4 Pentium时间戳计数器

  时间戳计数器(TSC)是Pentium兼容处理器中的一个计数器,它记录自启动以来处理器消耗的时钟周期数。由于TSC随着处理器周期速率的比例的变化而变化,因此提供了非常高的精确度。TSC通常被用于剖析和监测代码。使用rdtsc指令可测量某段代码的执行时间,其精度达到微秒级。TSC的节拍可以被转化为秒,方法是将其除以CPU时钟速率(可从内核变量cpu_khz读取)。

  在如下代码片段中,low_tsc_ticks和high_tsc_ticks分别包含了TSC的低32位和高32位。低32位可能在数秒内溢出(具体时间取决于处理器速度),但是这已经用于许多代码的剖析了:

unsigned long low_tsc_ticks0, high_tsc_ticks0;
unsigned
long low_tsc_ticks1, high_tsc_ticks1;
unsigned
long exec_time;
rdtsc(low_tsc_ticks0, high_tsc_ticks0);
/* Timestamp before */
printk(
"Hello World\n");                /* Code to be profiled */
rdtsc(low_tsc_ticks1, high_tsc_ticks1);
/* Timestamp after */
exec_time
= low_tsc_ticks1 - low_tsc_ticks0;

  在1.8 GHz Pentium 处理器上,exec_time的结果为871(或半微秒)。

在2.6.21内核中,针对高精度定时器的支持(CONFIG_HIGH_RES_TIMERS)已经被融入了内核。它使用了硬件特定的高速定时器来提供对nanosleep()等API高精度的支持。在基于Pentium的机器上,内核借助TSC实现这一功能。
0
相关文章