微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux 时钟管理

Linux 时钟管理

时间:06-13 来源:IBM 点击:

hrtimer_interrupt的使用环境
hrtimer_interrupt 有 2 种常见的使用方式。一是作为 tick 的推动器在产生 tick 中断时被调用;另一种情况就是通过软中断 HRTIMER_SOFTIRQ(run_hrtimer_softirq)被调用,通常是被驱动程序或者间接的使用这些驱动程序的用户程序所调用

在这个函数中,首先使用 tick_init_highres 更新与原来的 tick device 绑定的时钟事件设备的 event handler,例如将在低精度模式下的工作函数 tick_handle_periodic / tick_handle_periodic_broadcast 换成 hrtimer_interrupt(它是 hrtimer 在高精度模式下的 timer 中断处理函数),同时将 tick device 的触发模式变为 one-shot,即单次触发模式,这是使用 dynamic tick 或者 hrtimer 时 tick device 的工作模式。由于 dynamic tick 可以随时停止和开始,以不规律的速度产生 tick,因此支持 one-shot 模式的时钟事件设备是必须的;对于 hrtimer,由于 hrtimer 采用事件机制驱动 timer 前进,因此使用 one-shot 的触发模式也是顺理成章的。不过这样一来,原本 tick device 每次执行中断时需要完成的周期性任务如更新 jiffies / wall time (do_timer) 以及更新 process 的使用时间(update_process_times)等工作在切换到高精度模式之后就没有了,因此在执行完 tick_init_highres 之后紧接着会调用 tick_setup_sched_timer 函数来完成这部分设置工作,如清单 7 所示:

清单 7. hrtimer 高精度模式下模拟周期运行的 tick device 的简化实现

void tick_setup_sched_timer(void) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); ktime_t now = ktime_get(); u64 offset; /* * Emulate tick processing via per-CPU hrtimers: */ hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ts->sched_timer.function = tick_sched_timer; . . . . for (;;) { hrtimer_forward(&ts->sched_timer, now, tick_period); hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) break; now = ktime_get(); } . . . . }

这个函数使用 tick_cpu_sched 这个 per-CPU 变量来模拟原来 tick device 的功能。tick_cpu_sched 本身绑定了一个 hrtimer,这个 hrtimer 的超时值为下一个 tick,回调函数为 tick_sched_timer。因此,每过一个 tick,tick_sched_timer 就会被调用一次,在这个回调函数中首先完成原来 tick device 的工作,然后设置下一次的超时值为再下一个 tick,从而达到了模拟周期运行的 tick device 的功能。如果所有的 CPU 在同一时间点被唤醒,并发执行 tick 时可能会出现 lock 竞争以及 cache-line 冲突,为此 Linux 内核做了特别处理:如果假设 CPU 的个数为 N,则所有的 CPU 都在 tick_period 前 1/2 的时间内执行 tick 工作,并且每个 CPU 的执行间隔是 tick_period / (2N),见清单 8 所示:

清单 8. hrtimer 在高精度模式下 tick 执行周期的设置

void tick_setup_sched_timer(void) { . . . . /* Get the next period (per cpu) */ hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); offset = ktime_to_ns(tick_period) >> 1; do_div(offset, num_possible_cpus()); offset *= smp_processor_id(); hrtimer_add_expires_ns(&ts->sched_timer, offset); . . . . }

回到 hrtimer_switch_to_hres 函数中,在一切准备就绪后,调用 retrigger_next_event 激活下一次的 timer 就可以开始正常的运作了。

随着 hrtimer 子系统的发展,一些问题也逐渐暴露了出来。一个比较典型的问题就是 CPU 的功耗问题。现代 CPU 都实现了节能的特性,在没有工作时 CPU 会主动降低频率,关闭 CPU 内部一些非关键模块以达到节能的目的。由于 hrtimer 的精度很高,触发中断的频率也会很高,频繁的中断会极大的影响 CPU 的节能。在这方面 hrtimer 一直在不断的进行调整。以下几个例子都是针对这一问题所做的改进。

schedule_hrtimeout 函数

/** * schedule_hrtimeout - sleep until timeout * @expires: timeout value (ktime_t) * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL */ int __sched schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode)

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top