2.6.21内核之前,时钟中断是周期的,即以HZ为频率,系统总是被动的接受时钟中断,然后运行中断处理程序。
实在没有任务可以运行,那么就执行idle,但是时钟中断还是会周期性的打破idle,然后查询有没有需要做的事。如果没继续idle,以往的进程在自己时间片中运行,时钟的定时中断负责监督时间片,系统内核没有主权,一切都在硬件安排下运行。
2.6.22以后,nohz动态设置下一次的中断时间而不是使用系统无条件的默认的HZ中断。
CFS调度器再也不用受制于底层的时钟以及时间片分配特性,linux可以动态设置时间片长短,按照自己的方式来进行调度。
nohz和clocksource和 clock_event_device是时钟以及时钟行为的抽象
struct timer_list :软件时钟,记录了软件时钟到期时间以及到期后要执行的操作。
struct timer_list {
struct list_head entry; //所在的链表
unsigned long expires; //到期时间,以 tick 为单位
void (*function)(unsigned long); //回调函数,到期后执行的操作
unsigned long data; //回调函数的参数
struct tvec_t_base_s *base; //记录该软件时钟所在的 struct tvec_base 变量
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
};
struct tvec_base :管理软件时钟。在 SMP 系统每个 CPU 有一个。
跟踪内核中timer的代码,内核版本2.6.32
//This function runs timers and the timer-tq in bottom half context.
static void run_timer_softirq(struct softirq_action *h)
{
tvec_base_t *base = __get_cpu_var(tvec_bases);
hrtimer_run_queues(); //这里切换到nohz,进而调用tick_nohz_switch_to_nohz(); //如果满足调节,切换到nohz
}
static void tick_nohz_switch_to_nohz(void)
{
printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n",
smp_processor_id());
}
如同内核串口的打印消息了