我编写了一个启动hrtimer的linux模块,它的回调函数每20us调用一次。假设开始时间为0,则回调函数的执行时间应为20us,40us,60us,......,但在我的程序中,结果是在某些情况下,回调函数的执行可能会延迟很久。我想知道为什么会这样。
我的模块在x86_64平台上运行,tsc用于计算延迟。以下是我的代码:
static enum hrtimer_restart hwt_timer_fn(struct hrtimer *timer) {
unsigned long long tick_start;
rdtscll(tick_start);
tick_err = tick_start - cmp_cycle;
cmp_cycle += tick_cycle; //cmp_cycle means the next execute time of the callback function
hrtimer_add_expires(timer, expires);
count++;
if(tick_err > max_err)
max_err = tick_err;
if(tick_err < min_err)
min_err = tick_err;
return HRTIMER_RESTART;
}
static int kthread_hrtimer(void *arg) {
struct timespec val;
unsigned long long tick_start;
val.tv_sec = 0;
val.tv_nsec = 20*1000;
expires = timespec_to_ktime(val);
count = 0;
max_err = min_err = 0;
tick_cycle = cpu_khz/50; //the tsc cycle of 20us
printk("cpu_freq:%u,tick_cycle:%llu\n",cpu_khz,tick_cycle);
hrtimer_init(&timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
timer.function = hwt_timer_fn;
rdtscll(tick_start);
hrtimer_start(&timer,expires,HRTIMER_MODE_REL);
cmp_cycle = tick_start + tick_cycle;
return 0;
}
int hwt_timer_init(void) {
cpumask_t mask;
cpus_clear(mask);
cpu_set(0,mask);
thread = kthread_create(kthread_hrtimer,NULL,"kthread_hrtimer");
if(IS_ERR(thread))
{
printk("create failure\n");
return 1;
}
set_cpus_allowed_ptr(thread,&mask);
wake_up_process(thread);
return 0;
}
void hwt_timer_exit(void) {
while(hrtimer_try_to_cancel(&timer) < 0);
printk("max_err:%lld,min_err:%lld\n",max_err,min_err);
printk("count:%lld\n",count);
printk("\n\n");
}
答案 0 :(得分:2)
首先,Linux不是一个硬实时操作系统。虽然hrtimers保证在设定目标已经过去之后而不是之前触发,但是响应时间没有保证限制。具体来说,hrtimers机制不保证在目标时间发生和计时器触发之间经过的时间量。
可能会延迟触发的一个可能原因是内核可能处于涉及禁用中断的关键部分。在这种情况下,将导致调用hrtimer函数的定时中断被屏蔽,直到内核退出临界区并再次启用中断。
为了解决单边计时器保证的第一个问题,我建议如下:
使用阈值,我们称之为TIMER_THRESHOLD
将计时器设置为目标时间时,请稍早设置实际目标。 (例如,使用“expires - (TIMER_THRESHOLD / 2)”而不是使用“expires”)
在计时器回调中,根据“目标时间”检查“当前时间”,并假设如果“当前时间”在目标时间的TIMER_THRESHOLD范围内,则达到目标时间。
此外,对于周期性计时事件,我建议使用hrtimer_forward_now而不是hrtimer_add_expires。原因是处理计时器错过其截止时间超过计时器周期的情况。在这种情况下,hrtimer_add_expires仍会设置过去的目标。
最后,我提出的另一个建议是尽可能使用比20us更长的延迟。 20us是一段非常短的时间。在GHz处理器上,大约有20000条指令。
答案 1 :(得分:0)
我支持Safayet Ahmed的回答。无论如何,我想补充一些意见。
检查系统上的CONFIG_HZ选项,通常CONFIG_HZ为1000.这意味着系统计时器精度可以在1ms左右(通常优于1ms,但不能达到&#34; us&#34;精度)。 / p>
尝试将CONFIG_HZ更改为更大的值,以检查您的hrtimer精度是否得到改善。如果没有,请检查hrtimer API。也许这个问题与您对hrtimer API的误用有关。