/**
* struct tick_sched - sched tick emulation and no idle tick control/stats
* @sched_timer: hrtimer to schedule the periodic tick in high
* resolution mode
* @idle_tick: Store the last idle tick expiry time when the tick
* timer is modified for idle sleeps. This is necessary
* to resume the tick timer operation in the timeline
* when the CPU returns from idle
* @tick_stopped: Indicator that the idle tick has been stopped
* @idle_jiffies: jiffies at the entry to idle for idle time accounting
* @idle_calls: Total number of idle calls
* @idle_sleeps: Number of idle calls, where the sched tick was stopped
* @idle_entrytime: Time when the idle call was entered
* @idle_waketime: Time when the idle was interrupted
* @idle_exittime: Time when the idle state was left
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
* @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding
* @sleep_length: Duration of the current idle sleep
* @do_timer_lst: CPU was the last one doing do_timer before going idle
*/
struct tick_sched {
struct hrtimer sched_timer; //实现时钟的定时器
unsigned long check_clocks;
enum tick_nohz_mode nohz_mode; //当前运作模式
ktime_t idle_tick; //在禁用周期时钟之前,上一个时钟信号的到期时间。
int inidle;
int tick_stopped; //如果周期时钟已经停用,则为1.
unsigned long idle_jiffies; //周期时钟听用的jiffies值
unsigned long idle_calls; //内核试图停用时钟周期的次数
unsigned long idle_sleeps; //成功停用时钟周期的次数。(如果下一个时钟即将在一个jiffy之后到期,内核是不会停用时钟的)。
int idle_active; //
ktime_t idle_entrytime;
ktime_t idle_waketime;
ktime_t idle_exittime;
ktime_t idle_sleeptime;//周期时钟上一次禁用的准确时间
ktime_t iowait_sleeptime;
ktime_t sleep_length; //周期时钟将禁用的时间长度。
unsigned long last_jiffies;
unsigned long next_jiffies; //下一个定时器到期时间的jiffy值。
ktime_t idle_expires; //下一个将到期的经典定时器的的到期时间。
int do_timer_last;
};
tick_cpu_sched是一个全局各CPU变量,提供一个struct tick_sched实例。这是必须的,因为对时钟的禁用是按照CPU指定的,而不是对整个系统指定的。
1、低精度系统下的动态时钟
(1)切换到动态时钟
/**
* tick_nohz_switch_to_nohz - switch to nohz mode
*/
static void tick_nohz_switch_to_nohz(void)
{
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
ktime_t next;
if (!tick_nohz_enabled)
return;
local_irq_disable();
if (tick_switch_to_oneshot(tick_nohz_handler)) {
local_irq_enable();
return;
}
ts->nohz_mode = NOHZ_MODE_LOWRES;
/*
* Recycle the hrtimer in ts, so we can share the
* hrtimer_forward with the highres code.
*/
hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
/* Get the next period */
next = tick_init_jiffy_update();
for (;;) {
hrtimer_set_expires(&ts->sched_timer, next);
if (!tick_program_event(next, 0))
break;
next = ktime_add(next, tick_period);
}
local_irq_enable();
printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
}
(2)动态时钟处理程序
/*
* The nohz low res interrupt handler
*/
static void tick_noh