High-Resolution Timers
来源:互联网 发布:java异常机制 编辑:程序博客网 时间:2024/05/22 04:53
通常软时钟是建立在周期性的时钟中断的基础之上的,为了获取精度较高的软时钟中断,不得不提高时钟中断频率,但是过高的中断频率会造成CPU运算周期的浪费。High-Resolution机制,通过可编程的硬件定时器,把它的到期时间设置为软定时器队列中最早到期的时间,当时钟到期时,再把剩余的软定时器队列的最早到期时间编程到硬件定时器中,这样既能提高软时钟的精度,也不至于影响系统的性能。
High-Resolution Timers管理结构:
/** * struct hrtimer - the basic hrtimer structure * @node:timerqueue node, which also manages node.expires, *the absolute expiry time in the hrtimers internal *representation. The time is related to the clock on *which the timer is based. Is setup by adding *slack to the _softexpires value. For non range timers *identical to _softexpires. * @_softexpires: the absolute earliest expiry time of the hrtimer. *The time which was given as expiry time when the timer *was armed. * @function:timer expiry callback function * @base:pointer to the timer base (per cpu and per clock) * @state:state information (See bit values above) * @start_site:timer statistics field to store the site where the timer *was started * @start_comm: timer statistics field to store the name of the process which *started the timer * @start_pid: timer statistics field to store the pid of the task which *started the timer * * The hrtimer structure must be initialized by hrtimer_init() */struct hrtimer {struct timerqueue_nodenode; ktime_t_softexpires;enum hrtimer_restart(*function)(struct hrtimer *);struct hrtimer_clock_base*base;unsigned longstate;#ifdef CONFIG_TIMER_STATSintstart_pid;void*start_site;charstart_comm[16];#endif};struct timerqueue_node { struct rb_node node; //采用红黑树进行管理 ktime_t expires; //定时器到期时间};/** * struct hrtimer_clock_base - the timer base for a specific clock * @cpu_base: per cpu clock base * @index: clock type index for per_cpu support when moving a * timer to a base on another cpu. * @clockid: clock id for per_cpu support * @active: red black tree root node for the active timers * @resolution: the resolution of the clock, in nanoseconds * @get_time: function to retrieve the current time of the clock * @softirq_time: the time when running the hrtimer queue in the softirq * @offset: offset of this clock to the monotonic base */struct hrtimer_clock_base { struct hrtimer_cpu_base *cpu_base; int index; clockid_t clockid; struct timerqueue_head active; ktime_t resolution; ktime_t (*get_time)(void); ktime_t softirq_time; ktime_t offset;};
High-Resolution Timers的初始化:
void __init hrtimers_init(void){hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id());register_cpu_notifier(&hrtimers_nb);#ifdef CONFIG_HIGH_RES_TIMERSopen_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq);#endif}//最终调用/* * Functions related to boot-time initialization: */static void __cpuinit init_hrtimers_cpu(int cpu){ struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); int i; raw_spin_lock_init(&cpu_base->lock); for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { cpu_base->clock_base[i].cpu_base = cpu_base; timerqueue_init_head(&cpu_base->clock_base[i].active); } hrtimer_init_hres(cpu_base);}内核初始化之初,并没有启动High-Resolution Timers,每当执行时钟软中断时,会检查能否需要进入High-Resolution Timers模式,如果能,则进行进一步的初始化工作:
/* * This function runs timers and the timer-tq in bottom half context. */static void run_timer_softirq(struct softirq_action *h){ struct tvec_base *base = __this_cpu_read(tvec_bases); hrtimer_run_pending(); if (time_after_eq(jiffies, base->timer_jiffies)) __run_timers(base);}/* * Called from timer softirq every jiffy, expire hrtimers: * * For HRT its the fall back code to run the softirq in the timer * softirq context in case the hrtimer initialization failed or has * not been done yet. */void hrtimer_run_pending(void){ if (hrtimer_hres_active()) //如果已经启用了hrtimer机制,则返回。 return; /* * This _is_ ugly: We have to check in the softirq context, * whether we can switch to highres and / or nohz mode. The * clocksource switch happens in the timer interrupt with * xtime_lock held. Notification from there only sets the * check bit in the tick_oneshot code, otherwise we might * deadlock vs. xtime_lock. */ if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) /*hrtimer_is_hres_enabled: query if the highres mode is enabled * tick_check_oneshot_change: Check, if a change happened, which makes oneshot possible. */ hrtimer_switch_to_hres(); //Switch to high resolution mode}/* * Switch to high resolution mode */static int hrtimer_switch_to_hres(void){ int i, cpu = smp_processor_id(); struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu); unsigned long flags; if (base->hres_active) //如果已经启用了hres机制,则返回 return 1; local_irq_save(flags); if (tick_init_highres()) { local_irq_restore(flags); printk(KERN_WARNING "Could not switch to high resolution " "mode on CPU %d\n", cpu); return 0; } base->hres_active = 1; for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) base->clock_base[i].resolution = KTIME_HIGH_RES; tick_setup_sched_timer(); // setup the tick emulation timer /* "Retrigger" the interrupt to get things going */ retrigger_next_event(NULL); local_irq_restore(flags); return 1;}/** * tick_init_highres - switch to high resolution mode * * Called with interrupts disabled. */int tick_init_highres(void){ return tick_switch_to_oneshot(hrtimer_interrupt);}/** * tick_switch_to_oneshot - switch to oneshot mode */int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)){ struct tick_device *td = &__get_cpu_var(tick_cpu_device); struct clock_event_device *dev = td->evtdev; if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || !tick_device_is_functional(dev)) { printk(KERN_INFO "Clockevents: " "could not switch to one-shot mode:"); if (!dev) { printk(" no tick device\n"); } else { if (!tick_device_is_functional(dev)) printk(" %s is not functional.\n", dev->name); else printk(" %s does not support one-shot mode.\n", dev->name); } return -EINVAL; } td->mode = TICKDEV_MODE_ONESHOT;/*把CPU本地clock event device的event handler设置为hrtimer_interrupt()*/ dev->event_handler = handler; clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); tick_broadcast_switch_to_oneshot(); return 0;}/* * Select oneshot operating mode for the broadcast device */void tick_broadcast_switch_to_oneshot(void){ struct clock_event_device *bc; unsigned long flags; raw_spin_lock_irqsave(&tick_broadcast_lock, flags);/*把全局broadcast device的event_handler设置为tick_broadcast_setup_oneshot.de*/ tick_broadcast_device.mode = TICKDEV_MODE_ONESHOT; bc = tick_broadcast_device.evtdev; if (bc) tick_broadcast_setup_oneshot(bc); raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);}/**切换到High-Resolution Timers后,时钟中断设备主要不是为了周期性的tick而发出中断,所以每一个CPU有一个虚拟tick定时器。*//** * 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; unsigned long idle_jiffies; unsigned long idle_calls; unsigned long idle_sleeps; 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; ktime_t idle_expires; int do_timer_last;};/** * tick_setup_sched_timer - setup the tick emulation timer */void tick_setup_sched_timer(void){ struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); ktime_t now = ktime_get(); /* * Emulate tick processing via per-CPU hrtimers: */ hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ts->sched_timer.function = tick_sched_timer; /* Get the next period (per cpu) */ hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());/**添加hrtimer*/ 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(); }#ifdef CONFIG_NO_HZ if (tick_nohz_enabled) { ts->nohz_mode = NOHZ_MODE_HIGHRES; printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id()); }#endif}/* * Called from hardirq context every jiffy */void hrtimer_run_queues(void){struct timerqueue_node *node;struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);struct hrtimer_clock_base *base;int index, gettime = 1;/*如果已经启用了hrtimer,则返回*/if (hrtimer_hres_active())return; for (index = 0; index < HRTIMER_MAX_CLOCK_BASES; index++) { //处理CPU上所有的hr_clock_basebase = &cpu_base->clock_base[index];if (!timerqueue_getnext(&base->active))continue;if (gettime) {hrtimer_get_softirq_time(cpu_base);gettime = 0;}raw_spin_lock(&cpu_base->lock);while ((node = timerqueue_getnext(&base->active))) { //处理base上所有到期的定时器struct hrtimer *timer;timer = container_of(node, struct hrtimer, node);if (base->softirq_time.tv64 <= //如果发现一个定时器未到期,则其后的定时器肯定没有到期,则breakhrtimer_get_expires_tv64(timer))break;__run_hrtimer(timer, &base->softirq_time); //如果已经到期,则执行High-Resolution Timers的软中断函数}raw_spin_unlock(&cpu_base->lock);}}static void __run_hrtimer(struct hrtimer *timer, ktime_t *now){ struct hrtimer_clock_base *base = timer->base; struct hrtimer_cpu_base *cpu_base = base->cpu_base; enum hrtimer_restart (*fn)(struct hrtimer *); int restart; WARN_ON(!irqs_disabled()); debug_deactivate(timer); __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); //将传递过来的事件从红黑树中删除 timer_stats_account_hrtimer(timer); fn = timer->function; //获取到期时钟的处理函数 /* * Because we run timers from hardirq context, there is no chance * they get migrated to another cpu, therefore its safe to unlock * the timer base. */ raw_spin_unlock(&cpu_base->lock); trace_hrtimer_expire_entry(timer, now); restart = fn(timer); //处理timer trace_hrtimer_expire_exit(timer); raw_spin_lock(&cpu_base->lock); /* * Note: We clear the CALLBACK bit after enqueue_hrtimer and * we do not reprogramm the event hardware. Happens either in * hrtimer_start_range_ns() or in hrtimer_interrupt() */ if (restart != HRTIMER_NORESTART) { BUG_ON(timer->state != HRTIMER_STATE_CALLBACK); enqueue_hrtimer(timer, base); } WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK)); timer->state &= ~HRTIMER_STATE_CALLBACK;}
- High-Resolution Timers
- 从系统调用nanosleep()学习High-Resolution Timers
- High-Resolution Timer
- High-Resolution Timer
- PCL :Supporting High Resolution Printing
- Handling large/high resolution images
- Mobile Web in High Resolution
- High-resolution timer for C++
- High Resolution Timer内核高精度时钟
- linux_small laptop with a high resolution
- 高精度计时器(High Resolution Timer)
- 关于Linux的 High-Resolution Timer
- Timers
- iOS4 高分辨率的問題 high-resolution screen
- Reading notes about High-resolution timer managememt on linux
- Interface to x86/64's high resolution time counter
- RefineNet: Multi-Path Refinement Networks for High-Resolution Semantic Segmentation
- 《Vehicle Detection in High-Resolution Aerial Images via Sparse Representation and Superpixels》论文笔记
- Java基础 三步学会Java Socket编程(一)
- Java基础 三步学会Java Socket编程(二)
- LDAP服务器安装配置
- ORA-01033:ORACLE initialization or shutdown in process
- 去百度还是去创新工厂?信开复还是信彦宏?
- High-Resolution Timers
- Java基础 三步学会Java Socket编程(三)
- 开源协议介绍
- 对使用Java Socket网络编程的详细讲解
- 多线程异步实现(backgroundworker)
- Flyweight 模式
- ASP.NET的工作原理以及生命周期?
- SSH2 Step by Step- Step 4 - Struts2、Spring和Hibernate的整合
- Proxy 模式(一)