免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3888 | 回复: 6
打印 上一主题 下一主题

[时钟管理] 内核是如何从低精度NO_HZ切换到高精度NO_HZ的 [复制链接]

论坛徽章:
46
2015小元宵徽章
日期:2015-03-06 15:58:18羊年新春福章
日期:2015-04-14 10:37:422015年亚洲杯之阿曼
日期:2015-04-14 10:41:50NBA常规赛纪念章
日期:2015-05-04 22:32:03NBA季后赛大富翁
日期:2015-05-04 22:34:11菠菜明灯
日期:2015-05-04 22:35:49新奥尔良黄蜂
日期:2015-05-04 22:49:2315-16赛季CBA联赛之广夏
日期:2015-12-11 15:02:342015年亚洲杯之巴勒斯坦
日期:2015-03-04 19:56:562015年亚洲杯之阿联酋
日期:2015-03-04 11:19:04休斯顿火箭
日期:2015-03-02 16:32:11纽约尼克斯
日期:2015-03-02 16:09:04
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-11-17 17:44 |只看该作者 |倒序浏览
void hrtimer_run_pending(void)
{
        if (hrtimer_hres_active())
                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()))/*这里如果满足one shot就会切换到no_hz,也就是切换到低精度的no_hz,此时我想将低精度切换到高精度是在哪里实现的呢?*/
                hrtimer_switch_to_hres();
}

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
2 [报告]
发表于 2014-11-18 09:30 |只看该作者
呵呵,没大看明白,具体想干嘛?

论坛徽章:
46
2015小元宵徽章
日期:2015-03-06 15:58:18羊年新春福章
日期:2015-04-14 10:37:422015年亚洲杯之阿曼
日期:2015-04-14 10:41:50NBA常规赛纪念章
日期:2015-05-04 22:32:03NBA季后赛大富翁
日期:2015-05-04 22:34:11菠菜明灯
日期:2015-05-04 22:35:49新奥尔良黄蜂
日期:2015-05-04 22:49:2315-16赛季CBA联赛之广夏
日期:2015-12-11 15:02:342015年亚洲杯之巴勒斯坦
日期:2015-03-04 19:56:562015年亚洲杯之阿联酋
日期:2015-03-04 11:19:04休斯顿火箭
日期:2015-03-02 16:32:11纽约尼克斯
日期:2015-03-02 16:09:04
3 [报告]
发表于 2014-11-18 09:42 |只看该作者
我就想知道是通过那个函数切换过去的,hrtimer这块有点乱

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
4 [报告]
发表于 2014-11-18 12:50 |只看该作者
只知道clocksource是在clocksource_find_best里面切换成高精度的

论坛徽章:
46
2015小元宵徽章
日期:2015-03-06 15:58:18羊年新春福章
日期:2015-04-14 10:37:422015年亚洲杯之阿曼
日期:2015-04-14 10:41:50NBA常规赛纪念章
日期:2015-05-04 22:32:03NBA季后赛大富翁
日期:2015-05-04 22:34:11菠菜明灯
日期:2015-05-04 22:35:49新奥尔良黄蜂
日期:2015-05-04 22:49:2315-16赛季CBA联赛之广夏
日期:2015-12-11 15:02:342015年亚洲杯之巴勒斯坦
日期:2015-03-04 19:56:562015年亚洲杯之阿联酋
日期:2015-03-04 11:19:04休斯顿火箭
日期:2015-03-02 16:32:11纽约尼克斯
日期:2015-03-02 16:09:04
5 [报告]
发表于 2014-11-18 15:25 |只看该作者
void hrtimer_run_pending(void)这个函数用来切换到高精度,注册clocksource时,会比对注册的clocksource和当前使用的时钟源,如果注册的时钟源rating更高的话,会去替换当前使用的时钟源

论坛徽章:
46
2015小元宵徽章
日期:2015-03-06 15:58:18羊年新春福章
日期:2015-04-14 10:37:422015年亚洲杯之阿曼
日期:2015-04-14 10:41:50NBA常规赛纪念章
日期:2015-05-04 22:32:03NBA季后赛大富翁
日期:2015-05-04 22:34:11菠菜明灯
日期:2015-05-04 22:35:49新奥尔良黄蜂
日期:2015-05-04 22:49:2315-16赛季CBA联赛之广夏
日期:2015-12-11 15:02:342015年亚洲杯之巴勒斯坦
日期:2015-03-04 19:56:562015年亚洲杯之阿联酋
日期:2015-03-04 11:19:04休斯顿火箭
日期:2015-03-02 16:32:11纽约尼克斯
日期:2015-03-02 16:09:04
6 [报告]
发表于 2014-11-18 15:26 |只看该作者
void hrtimer_run_pending(void)这个函数用来切换到高精度,注册clocksource时,会比对注册的clocksource和当前使用的时钟源,如果注册的时钟源rating更高的话,会去替换当前使用的时钟源

论坛徽章:
0
7 [报告]
发表于 2015-08-27 08:32 |只看该作者
本帖最后由 l4rmbr 于 2015-08-27 09:09 编辑
super皮波 发表于 2014-11-17 17:44
void hrtimer_run_pending(void)
{
        if (hrtimer_hres_active())


就在hrtimer_switch_to_hres里切换的。

高精度(hres) 和 nohz 都依赖于 ONESHOT 模式。 以前的 tick 模式,时钟是周期性触发的,也就是到点就来一个中断。

但在 高精度(hres)  模式下,这不可行。因为高精度(hres) 是 ns 级别的高精度,如此频繁的周期中断,系统不用干别的事了。
nohz 情况下,周期性的 tick 当然也不可行。nohz 本来就是动态tick, 需要的时候来,不需要的时候干脆关掉。这就是 ONESHOT mode 的作用。
ONESHOT, 顾名思义,就是一次中断来了后,要配置下一次什么时候来,也可以配置暂时关闭。

看内核配置也可以看到出来:

config NO_HZ_COMMON
        bool
        select TICK_ONESHOT

config HIGH_RES_TIMERS
        bool "High Resolution Timer Support"
        select TICK_ONESHOT
        help
        | This option enables high resolution timer support. If your
        | hardware is not capable then this option only increases
        | the size of the kernel image.

这两者者要 选择 TICK_ONESHOT。

系统启动时只在 低精度 和 非 nohz 模式下, 切换到这两种模式的代码是在时钟中断上下文调用的:

时钟中断来了 -》 tick_handle_periodic -》 tick_periodic -》update_process_times -》 run_local_timers -》 hrtimer_run_pending:

if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {
                hrtimer_switch_to_hres();
                return;
        }



tick_check_oneshot_change 是进入 高精度(hres)  和 nohz 的总入口:

int tick_check_oneshot_change(int allow_nohz)
{
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);

        if (!test_and_clear_bit(0, &ts->check_clocks))
                return 0;

        if (ts->nohz_mode != NOHZ_MODE_INACTIVE)
                return 0;

        if (!timekeeping_valid_for_hres() || !tick_is_oneshot_available())
                return 0;

        if (!allow_nohz)
                return 1;

        tick_nohz_switch_to_nohz();
        return 0;
}



如果 高精度(hres)  还不可用 , 那么,检查 nohz 是否可以激活,可以的话,我们先进入 nohz.
tick_nohz_switch_to_nohz 被调用,系统现在进入 低精度,nohz 模式。

这一函数的主要功能是

1) 把 时钟中断 处理 函数 改为: tick_nohz_handler . 注意看前文 ,一开始的时钟中断函数是 tick_handle_periodic。
2) 用hrtimer 框架, 设定下一次触发的时间,也就 是下一个 tick (注意,你看到用了hrtimer_* 函数,但不代表 高精度(hres) 激活了,
    hrtimer 框架 和 高精度(hres)  是两回事,hres是建立 在 hrtimer 框架上的,低精度也可以使用 hrtimer 框架, 这个框架提供的无非
   是配置动态时钟的功能,看 kernel/time/Makefile 也可以看出来,hrtimer.c 是无条件编译的,而 高精度(hres)  可不可用要看 CONFIG_HIGH_RES_TIMERS)


OK, 现在是低精度,nohz 模式了, 时钟中断处理函数是 tick_nohz_handler.

下一次时钟中断来了,时钟中断处理过程是:

tick_nohz_handler -》 tick_sched_handle -》 update_process_times -》 run_local_timers -》 hrtimer_run_pending:

看,其实做的事差不多。

现在我们又来到 hrtimer_run_pending 了, 记住,现在已经是 低精度,nohz 模式 了, 我们要检查 高精度(hres) 是否可用了,
是的话,我们要进入 高精度 (hres) 模式了。 假设可用了,.

if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {
                hrtimer_switch_to_hres();
                return;
        }



hrtimer_switch_to_hres 试图把系统切换到 高精度 (hres) 模式.

hrtimer_switch_to_hres -> tick_init_highres -> tick_switch_to_oneshot(hrtimer_interrupt)

注意,切换的核心动作是要把时钟中断的处理函数变为 hrtimer_interrupt:

/*
* High resolution timer interrupt
* Called with interrupts disabled
*/
void hrtimer_interrupt(struct clock_event_device *dev)
{
...
}


这个函数就是 高精度 (hres) 模式 下的时钟中断处理函数 ,它负责跑已经到点的定时器,
根据系统是否在 nohz 模式下, 决定配置下次时钟中断的时间,或者关掉时钟中断,等。


上面整个流程也可以有别的途径,比如,先进入 高精度 (hres) 模式, 再进入 nohz;或
只进入 高精度 (hres) 模式,不进入 nohz (原因是用户没把 nohz 功能编译进来 )。具体流程
与上文无多大差别,还是在时钟中断中去判断,然后进入。不再赘述。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP