Linux时间子系统之一:clock source(时钟源)【转】
转自:http://blog.csdn.net/droidphone/article/details/7975694
clock source用于为linux内核提供一个时间基线,如果你用linux的date命令获取当前时间,内核会读取当前的clock source,转换并返回合适的时间单位给用户空间。在硬件层,它通常实现为一个由固定时钟频率驱动的计数器,计数器只能单调地增加,直到溢出为止。时钟源是内核计时的基础,系统启动时,内核通过硬件RTC获得当前时间,在这以后,在大多数情况下,内核通过选定的时钟源更新实时时间信息(墙上时间),而不再读取RTC的时间。本节的内核代码树基于V3.4.10。
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
1. struct clocksource结构
内核用一个clocksource结构对真实的时钟源进行软件抽象,现在我们从clock source的数据结构开始,它的定义如下:
- struct clocksource {
- /*
- * Hotpath data, fits in a single cache line when the
- * clocksource itself is cacheline aligned.
- */
- cycle_t (*read)(struct clocksource *cs);
- cycle_t cycle_last;
- cycle_t mask;
- u32 mult;
- u32 shift;
- u64 max_idle_ns;
- u32 maxadj;
- #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
- struct arch_clocksource_data archdata;
- #endif
- const char *name;
- struct list_head list;
- int rating;
- int (*enable)(struct clocksource *cs);
- void (*disable)(struct clocksource *cs);
- unsigned long flags;
- void (*suspend)(struct clocksource *cs);
- void (*resume)(struct clocksource *cs);
- /* private: */
- #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
- /* Watchdog related data, used by the framework */
- struct list_head wd_list;
- cycle_t cs_last;
- cycle_t wd_last;
- #endif
- } ____cacheline_aligned;
我们只关注clocksource中的几个重要的字段。
1.1 rating:时钟源的精度
- 1--99: 不适合于用作实际的时钟源,只用于启动过程或用于测试;
- 100--199:基本可用,可用作真实的时钟源,但不推荐;
- 200--299:精度较好,可用作真实的时钟源;
- 300--399:很好,精确的时钟源;
- 400--499:理想的时钟源,如有可能就必须选择它作为时钟源;
1.2 read回调函数
1.3 mult和shift字段
t = cycle/F;
t = (cycle * mult) >> shift;
F = (1 << shift) / mult;
- static inline s64 clocksource_cyc2ns(cycle_t cycles, u32 mult, u32 shift)
- {
- return ((u64) cycles * mult) >> shift;
- }
从转换精度考虑,mult的值是越大越好,但是为了计算过程不发生溢出,mult的值又不能取得过大。为此内核假设cycle计数值被转换后的最大时间值:10分钟(600秒),主要的考虑是CPU进入IDLE状态后,时间信息不会被更新,只要在10分钟内退出IDLE,clocksource的cycle计数值就可以被正确地转换为相应的时间,然后系统的时间信息可以被正确地更新。当然最后的结果不一定是10分钟,它由clocksource_max_deferment进行计算,并保存max_idle_ns字段中,tickless的代码要考虑这个值,以防止在NO_HZ配置环境下,系统保持IDLE状态的时间过长。在这样,由10分钟这个假设的时间值,我们可以推算出合适的mult和shift值。
2. clocksource的注册和初始化
由上图可见,最终大部分工作会转由__clocksource_register_scale完成,该函数首先完成对mult和shift值的计算,然后根据mult和shift值,最终通过clocksource_max_deferment获得该clocksource可接受的最大IDLE时间,并记录在clocksource的max_idle_ns字段中。clocksource_enqueue函数负责按clocksource的rating的大小,把该clocksource按顺序挂在全局链表clocksource_list上,rating值越大,在链表上的位置越靠前。
3. clocksource watchdog
系统中可能同时会注册对个clocksource,各个clocksource的精度和稳定性各不相同,为了筛选这些注册的clocksource,内核启用了一个定时器用于监控这些clocksource的性能,定时器的周期设为0.5秒:
- #define WATCHDOG_INTERVAL (HZ >> 1)
- #define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)
当有新的clocksource被注册时,除了会挂在全局链表clocksource_list外,还会同时挂在一个watchdog链表上:watchdog_list。定时器周期性地(0.5秒)检查watchdog_list上的clocksource,WATCHDOG_THRESHOLD的值定义为0.0625秒,如果在0.5秒内,clocksource的偏差大于这个值就表示这个clocksource是不稳定的,定时器的回调函数通过clocksource_watchdog_kthread线程标记该clocksource,并把它的rate修改为0,表示精度极差。
4. 建立clocksource的简要过程
在系统的启动阶段,内核注册了一个基于jiffies的clocksource,代码位于kernel/time/jiffies.c:
- struct clocksource clocksource_jiffies = {
- .name = "jiffies",
- .rating = 1, /* lowest valid rating*/
- .read = jiffies_read,
- .mask = 0xffffffff, /*32bits*/
- .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
- .shift = JIFFIES_SHIFT,
- };
- ......
- static int __init init_jiffies_clocksource(void)
- {
- return clocksource_register(&clocksource_jiffies);
- }
- core_initcall(init_jiffies_clocksource);
它的精度只有1/HZ秒,rating值为1,如果平台的代码没有提供定制的clocksource_default_clock函数,它将返回该clocksource:
- struct clocksource * __init __weak clocksource_default_clock(void)
- {
- return &clocksource_jiffies;
- }
然后,在初始化的后段,clocksource的代码会把全局变量curr_clocksource设置为上述的clocksource:
- static int __init clocksource_done_booting(void)
- {
- ......
- curr_clocksource = clocksource_default_clock();
- ......
- finished_booting = 1;
- ......
- clocksource_select();
- ......
- return 0;
- }
- fs_initcall(clocksource_done_booting);
当然,如果平台级的代码在初始化时也会注册真正的硬件clocksource,所以经过clocksource_select()函数后,curr_clocksource将会被设为最合适的clocksource。如果clocksource_select函数认为需要切换更好的时钟源,它会通过timekeeping_notify通知timekeeping系统,使用新的clocksource进行时间计数和更新操作。
Linux时间子系统之一:clock source(时钟源)【转】的更多相关文章
- Linux时间子系统之八:动态时钟框架(CONFIG_NO_HZ、tickless)
在前面章节的讨论中,我们一直基于一个假设:Linux中的时钟事件都是由一个周期时钟提供,不管系统中的clock_event_device是工作于周期触发模式,还是工作于单触发模式,也不管定时器系统是工 ...
- Linux时间子系统之八:动态时钟框架(CONFIG_NO_HZ、tickless)【转】
转自:http://blog.csdn.net/droidphone/article/details/8112948 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 数据结 ...
- Linux时间子系统之(十七):ARM generic timer驱动代码分析
专题文档汇总目录 Notes:ARM平台Clock/Timer架构:System counter.Timer以及两者之间关系:Per cpu timer通过CP15访问,System counter通 ...
- Linux时间子系统(十七) ARM generic timer驱动代码分析
一.前言 关注ARM平台上timer driver(clocksource chip driver和clockevent chip driver)的驱动工程师应该会注意到timer硬件的演化过程.在单 ...
- Linux时间子系统专题汇总
关于Linux时间子系统有两个系列文章讲的非常好,分别是WowoTech和DroidPhone. 还有两本书分别是介绍: Linux用户空间时间子系统<Linux/UNIX系统编程手册>的 ...
- Linux时间子系统之(五):POSIX Clock
专题文档汇总目录 Notes: 本章主要介绍了若干种类的静态时钟,这些时钟都可以通过k_clock表示,注册到posix_clocks中.这些都是静态时钟,可以分为三大类:各种REALTIME时钟.带 ...
- Linux时间子系统之(二):软件架构
专题文档汇总目录 Notes:从框架上讲解了时间子系统,从底向上包括CPU Local TImer.Global Counter.Clock Souce/Clock Events模块管理.Tick D ...
- Linux时间子系统之(四):timekeeping
专题文档汇总目录 Notes:timekeeping模块的狠心数据结构是timekeeper,它维护了系统不同类型时钟的时间值,并且介绍了获取不同类型时钟时间的函数. clocksource切换通过c ...
- Linux时间子系统之(十五):clocksource
专题文档汇总目录 Notes:clocksource基本概念,struct clocksource详解:注册和注销clocksource:内核如何选取clocksource:clocksource相关 ...
- Linux时间子系统之三:时间的维护者:timekeeper
专题文档汇总目录 Notes: 原文地址:Linux时间子系统之三:时间的维护者:timekeeper 本系列文章的前两节讨论了用于计时的时钟源:clocksource,以及内核内部时间的一些表示方法 ...
随机推荐
- JavaScript Array 类型
除 Object类型外,Array 类型算是ECMAScript中最常用的类型了,而且,ECMAScript中的数组和其他多数语言的数组有着非常大的差别,虽然这些数组都是数据的有序列表,但与其他语言不 ...
- Python 开篇及第一个Python程序
本节内容 python 简单介绍 python 2.x 或者python 3.x python 安装 第一个python程序 一.python简单介绍 python的创始人为吉多.范罗苏姆(Guido ...
- BZOJ2005:[Noi2010]能量采集——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2005 Description 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光 ...
- 洛谷 P1291 [SHOI2002]百事世界杯之旅 解题报告
P1291 [SHOI2002]百事世界杯之旅 题目描述 "--在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字.只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽 ...
- [BJOI2018]求和
link 其实可以用$sum(i,j)$表示从$i$到$1$的$k$次方的值,然后就是$lca$的基本操作 注意,能一起干的事情就一起搞,要不会超时 #include<iostream> ...
- cmder 添加到右键菜单
管理员权限打开cmde 输入: cmder /register all 回车,OK
- linux 常见服务端口
Linux服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程(daemons) 来执行的.守护进 ...
- Android Eclipse 开发环境搭建
因为开发工具版本 搭建 环境配置经常出现问题 再次用一篇随笔来做下记录 1 需要的工具jdk-6u45-windows-x64 //http://www.oracle.com/technetwork/ ...
- CSS实现三列布局方法总结
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABYwAAAI7CAYAAABPx9+YAAARJElEQVR4nO3cwWnDQBBA0TioJrXhTl
- 「模板」 FHQ_Treap 区间翻转
「模板」 FHQ_Treap 区间翻转 没有旋转的 Treap 实现区间操作的功能,很好理解,也很好写,只是速度不算太快. 对于要翻转的区间,把整棵 Treap(存有区间 \([1,n]\) 的信息) ...