linux 时间管理——概念、注意点(一)【转】
转自:http://www.cnblogs.com/openix/p/3324243.html
参考:1、http://bbs.eyeler.com/thread-69-1-1.html
2、《Linxu Kernel Development》3ed_CN p166~p185
3、《Professional Linux Kernel Architecture》1ed_CN p714~p760
4、http://blog.csdn.net/droidphone/article/details/8017604
5、2.6.34
此记录的主要目的记录下如上参考中的一些知识点、基本概念,以及作为后续记录的参考。
对于unicore的内核2.6.32.9,其时间子系统是基于低分辨率周期时钟实现的,但是在此记录及后续的记录中将会谈下“低分辨率动态时钟、高分辨率动态时钟、高分辨率周期时钟”。
---------------------------------------------------------------------------------------------------------------------------------------
内核中的两种定时器:
1、timeout:表示将在一定时间之后发生的事件,但可以且通常会在发生之前取消。
2、timer: 用于实现时序,此类定时器通常都会到期,而且与超时类定时器相比,需要更高的时间分辨率。
timer wheel的实现要点在于:

timer wheel的实现可以自行参考内核代码,网上讲的也很多。
1、void __run_timers(struct tvec_base *base)
在当前第一组tv1的元素全被遍历后(函数也会执行),将会调用cascade函数,主要的功能就在于取下特定tv数组下的某一个数组元素中的链表,然后重新加入前面的各个数组的各个数组元数的链表中。方法比较巧妙,这样每次执行定时函数时只需从tv1上取出过期的节点即可执行,但是我们也需要注意执行cascade的时间也可能会很长。 2、void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
注意其中是如何索引到各个数组的数组元素下标的:
unsigned long idx = expires - base->timer_jiffies;下标
vec = base->tv[1..5].vec + i; 插入哪个链表

低分辨率定时器的重要性在于:
1)处理全局jiffies计数器。该值周期性地增长(如果使用了低分辨率动态时钟,可能不会周期性增长),它是一种特别简单的时间基准。
2)进行各进程统计。
内核中的各种time,注意下struct timekeeper timekeeper:

1)wall time
RTC time
在SOC系统中,RTC可以集成到SOC芯片中,并做为一个单独的电压域,系统掉电时,可由后备电池供电,RTC中的时间信息不会丢失。内核和用户空间通过驱动程序访问RTC硬件来获取或设置时间信息。
xtime
A value representation of the human time of day;日常生活中所见的钟表时间,精度可达纳秒级。
xtime和RTC时间一样,都是人们日常生活所使用的墙上时间,只是RTC时间的精度比较低,大多数情况下只能达到毫秒级的精度,如果是使用外部的RTC芯片,访问速度也比较慢,为此,内核维护了另一个wall time时间:xtime。因为xtime实际上是一个内存变量,它的访问速度非常快,内核大部分时间都是使用xtime来获得当前时间信息。xtime记录的是1970年1月1日到当前时刻所经历的纳秒数。
xtime在正常情况下是递增的,但是用户可以主动向前或向后调整墙上时间,从而修改xtime。
2) monotonic time
A monotonically increasing value that represents the amount of time that the system has been running.
开机后单调递增,它不像xtime可能因用户进行时间调整而产生改变,该时间不计算系统休眠的时间,即系统休眠时,monotonic不会递增。
monotonic时间不可以往后退,系统启动后只能不断递增。内核并没有直接定义一个特定的变量来记录monotonic时间,而是定义了一个变量wall_to_monotonic,记录了墙上时间和monotonic时间之间的偏移量,当需要获得monotonic时间时,把xtime和wall_to_monotonic相加即可。计算monotonic时间要去除系统休眠期间花费的时间,内核用total_sleep_time记录休眠的时间,每次休眠醒来后重新累加该时间,并调整wall_to_monotonic的值,使其在系统休眠醒来后,monotonic时间不会发生跳变。
3)raw_time
monotonic时间虽然不受settimeofday的影响,但会受到ntp调整的影响,但是raw_time不受ntp的影响,它真的就是开完机后就单调地增加。
xtime、monotonic time和raw_time可以通过用户空间的clock_gettime函数获得,对应的ID参数分别是CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_MONOTONIC_RAW。
4)clock source
A representation of a free running counter running at a known frequency, usually in hardware.
xtime、monotonic time、raw time都是基于该时钟源进行计时操作,当有新的精度更高的时钟源被注册时,通过timekeeping_notify函数,change_clocksource函数将会被调用,timekeeper.clock字段将会被更新,指向新的clocksource
5)tick
A periodic interrupt generated by a hardware-timer, typically with a fixed interval defined by HZ: jiffies

对于SMP,内核区分如下两种时钟类型:
1)全局时钟(global clock),负责提供周期时钟,主要用于jiffies更新。
2)每个CPU一个局部时钟(local clock),用来进行进程统计、性能剖析和实现高分辨率定时器。
全局时钟的角色,由一个明确选择的局部时钟承担(tick_setup_device函数中,会首次作出选择)
在设备第一次调用tick_seup_device时(即该时钟设备没有相关的时钟事件设备),内核执行如下操作:

1)如果没有选定时钟设备来承担全局时钟设备的角色,那么将选择当前设备来承担此职责,而tick_do_timer_cpu将设置为当前设备所属的处理器编号(注意,如果放弃职责该如何处理,可以参考tick_do_timer_cpu定义处的注释)。tick_period是时钟周期,单位是纳秒,它根据HZ值设置。
2)该设中设备设置为按周期模式工作。 关于上文中提到的2),什么时候会切换成one shot模式?
关注下hrtimer_run_queues,里面调用了tick_check_oneshot_change来判断是否可以激活高分辨率定时器。此外该函数还检查是否可以在低分辨率系统上启用动态时钟。(如果有一个支持单触发模式的时钟,而且其精度可以达到高分辨率定时器所要求的分辨率,即设置了CLOCK_SOURCE_VALID_FOR_HRES标志,那么tick_check_oneshot_change将通知内核可以使用高分辨率定时器)
留意下,在设备被设置成高分辨率周期时钟、高分辨率动态时钟时的中断处理函数的选择。(tick_handle_periodic、hrtimer_interrupt、tick_nohz_handler)
/*
* tick_do_timer_cpu is a timer core internal variable which holds the CPU NR
* which is responsible for calling do_timer(), i.e. the timekeeping stuff. This
* variable has two functions:
*
* 1) Prevent a thundering herd issue of a gazillion of CPUs trying to grab the
* timekeeping lock all at once. Only the CPU which is assigned to do the
* update is handling it.
*
* 2) Hand off the duty in the NOHZ idle case by setting the value to
* TICK_DO_TIMER_NONE, i.e. a non existing CPU. So the next cpu which looks
* at it will take over and keep the time keeping alive. The handover
* procedure also covers cpu hotplug.
*/
int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT;

动态时钟&WHY
在关注耗电量的系统上,周期性时钟要求系统在一定的频率下,周期性的处于活动状态。因此,长时间休眠是不可能的。引入动态时钟后,只有在有些任务需要实际执行时,才激活周期时钟。否则,会临时禁用周期时钟。对该技术的支持可以在编译时选择,启动此选项的系统也称为无时钟系统(tickless system)
在系统无事所做的idle阶段,我们可以通过停止周期时钟来达到降低系统功耗的目的,只要有进程处于活动状态,时钟事件依然会被周期性地发出。
在内核中,如定义了CONFIG_NO_HZ宏,则说明内核支持动态时钟;但是我们得明白,CONFIG_NO_HZ并不意味着没有HZ的概念(周期性更新系统统计量),主要区别在于当我们配置CONFIG_NO_HZ时说明:
1)系统支持动态时钟。启用动态时钟时,也定义且使用了HZ,因为它是许多计时任务的基本量。动态和周期时钟在表面上没有什么区别,主要的区别在于 进/退 IDLE时的不同处理方法。
2)系统可能需要停止时钟机制(此时将不会再周期性的产生时钟中断,例如系统进入IDLE)或重启时钟机制(系统退出IDLE)。
3)根据2),由于可以暂时停止时钟机制,因此单触发时钟是实现动态时钟的先决条件。(但是请注意,即使时钟设备处于单触发模式,也并不一定启用了动态时钟!例如,在高分辨率模式下,时钟总是基于单触发定时器实现的。)
高分辨率时钟如何实现周期时钟的仿真:
在内核切换到高分辨率模式时,将调用tick_setup_sched_timer来激活时钟仿真层。这将为每个CPU安装一个高分辨率定时器。所需的struct hrtime实例保存在CPU变量tick_cpu_sched中:该定时器的回调函数选择了tick_sched_timer,通过返回HRTIMER_RESTART,定时器将自动重新进入队列,并在下一个时钟到期时激活。
内核需要处理的情形:
1、没有动态时钟的低分辨率系统,总是使用周期时钟。该内核不包括任何对单触发操作的支持。
2、启用了动态时钟特性的低分辨率系统,以单触发模式使用时钟设备。
3、高分辨率系统总是使用单触发模式,无论是否启用了动态时钟特性。
关于宏:
这一项显得“理论、教条”,因为我很少接触SMP、至于龙芯系类也只接触了一小段时间。
1、启用动态时钟:CONFIG_NO_HZ
2、启用高分辨率定时器支持:CONFIG_HIGH_RES_TIMERS
3、支持动态时钟和高分辨率定时器的必要前提:GENERIC_TIME、GENERIC_CLOCKEVENTS
4、支持时钟事件的单触发模式:CONFIG_TICK_ONESHOT,如果启用了动态时钟或高分辨率定时器,则自动选中该项
时钟源(struct clocksource):时间管理的支柱。本质上每个时钟源都提供了一个单调增加的计数器,通用的内核代码只能进行只读访问。不同时钟源的精度取决于底层硬件的能力。clocksource不能被编程、没有事件产生能力。

关于clocksource中几个关键域:
read:时钟源本身不会产生中断,要获得时钟源的当前计数,只能通过主动调用它的read回调函数来获得当前技术值,注意这里只获
得计数值,也就是所谓的cycle,要获得相应的时间,必须要借助clocksource的mult和shift字段进行转换计算。
void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) mult和shift域:因为从clocksource中读到的值是一个cycle计数值,要转换为时间,必须知道驱动clocksource的时钟频率F,但是clocksource并没有保存时钟的频率F,内核使用的方法是:根据时钟的频率和期望的精度,事先计算出两个辅助常数mult和shift,然后使用下公式进行cycle和t的转换:
t = (cycle * mult) >> shift;
但是要保证:F = (1 << shift ) / mult;(一般PLL都是先倍频,再分频,很容易计算)
内核内部使用64位进行该转换计算:
static inline s64 clocksource_cyc2ns(cycle_t cycles, u32 mult, u32 shift)
|---->return ((u64) cycle * mult) >> shift;
问题在于如果mult太大,计算会发生溢出,因此mult值不能太大。内核假设cycle计数值被转换后的最大时间值为:10分钟(600s),原因在于CPU进入IDLE状态后,时间信息不会被更新,只要在10分钟内退出IDLE,clocksource的cycle计数值就可以被正确的转换为相
应的时间,然后系统的时间信息可以被正确的更新。结果不一定是10分钟,该值由clocksource_max_deferment进行计算,并保存在max_idle_ns字段中,tickless的代码需要考虑这个值,以防止在使用动态时钟时,系统保持IDLE状态的时间过长。

时钟事件设备(struct clock_event_device):向时钟增加了事件功能,在未来的某个时刻发生。这种设备也称为时钟事件源(clock event source)。clock_event_device可以被编程,可以工作在周期模式或单次触发模式,系统可以对它进行编程,以确定下次事件触发的时间,clock_event_device主要用于实现普通定时器和高精度定时器,同时也用于产生tick事件,供给进程调度子系统使用。在软件架构上,clock_evetn_device被分为两层,与硬件相关的放在machine层,与硬件无关的通用代码则被集中到了通用时间框架。
时钟设备(struct tick_device):扩展了时钟事件源的功能,各个时钟事件定期触发。但可以使用动态时钟机制,在一定时间间隔内停止周期时钟。
下图引述自:http://blog.csdn.net/droidphone/article/details/8017604

linux 时间管理——概念、注意点(一)【转】的更多相关文章
- Linux时间管理涉及数据结构和传统低分辨率时钟的实现
上篇文章大致描述了Linux时间管理的基本情况,看了一些大牛们的博客感觉自己写的内容很匮乏,但是没办法,只能通过这种方式提升自己……闲话不说,本节介绍下时间管理下重要的数据结构 设备相关数据结构 // ...
- linux时间管理
/etc/sysconfig/clock 该配置文件可用来设置用户选择何种方式显示时间.如果硬件时钟为本地时间,则UTC设为0,并且不用设置环境变量TZ.如果硬件时钟为UTC时间,则要 ...
- linux时间管理 之 jiffies
1.jiffies 又称时钟滴答,是一个全局变量,它的值在系统引导的时候初始化为0,在时钟中断初始化完成后,每次时钟中断发生,在时钟中断处理例程中都会将jiffies的值 +1. jiffies_64 ...
- linux设备驱动归纳总结(七):1.时间管理与内核延时【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(七):1.时间管理与内核延时 xxxxxxxxxxx ...
- 《Linux内核设计与实现》读书笔记(十一)- 定时器和时间管理【转】
转自:http://www.cnblogs.com/wang_yb/archive/2013/05/10/3070373.html 系统中有很多与时间相关的程序(比如定期执行的任务,某一时间执行的任务 ...
- linux下的时间管理概述
2017/6/21 时间这一概念在生活中至关重要,而在操作系统中也同样重要,其在系统中的功能绝不仅仅是给用户提供时间这么简单,内核的许多机制都依赖于时间子系统.但凡是要在某个精确的时间执行某个事件,必 ...
- Linux电源管理(2)-Generic PM基本概念和软件架构【转】
本文转载自:http://www.wowotech.net/pm_subsystem/generic_pm_architecture.html 1. 前言 这里的Generic PM,是蜗蜗自己起的名 ...
- 【Linux开发】linux设备驱动归纳总结(七):1.时间管理与内核延时
linux设备驱动归纳总结(七):1.时间管理与内核延时 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- 5 个在 Linux 中管理文件类型和系统时间的有用命令
对于想学习 Linux 的初学者来说要适应使用命令行或者终端可能非常困难.由于终端比图形用户界面程序更能帮助用户控制 Linux 系统,我们必须习惯在终端中运行命令.因此为了有效记忆 Linux 不同 ...
随机推荐
- laravel 获取 当前url 的方法, 有的是获取 全部url 有的只获取 主页其他 部分
1. 使用 Request 类: $url = Request::getRequestUri(); 2. 使用 $request 对象: public function show(Request $r ...
- hibernate学习(9)——日志,一对一,二级缓存
1.Hibernate中的日志 1 slf4j 核心jar : slf4j-api-1.6.1.jar .slf4j是日志框架,将其他优秀的日志第三方进行整合. 整合导入jar包 log4j 核心 ...
- ASP.NET Web API 2基于令牌的身份验证
基于令牌的认证 我们知道WEB网站的身份验证一般通过session或者cookie完成的,登录成功后客户端发送的任何请求都带上cookie,服务端根据客户端发送来的cookie来识别用户. WEB A ...
- 【入门】 jpa--实体管理器的基本应用
1.新建Jpa项目 2.引入所需的jar 包 3.创建实体类 package com.watchfree.entity; import javax.persistence.Entity; import ...
- 浅析 Magento网站建站空间的选择
对 Magento稍有了解的人都知道,作为一个功能异常强大的网络商城程序,Magento的运行对主机空间的要求是非常高的:很多 Magento建站公司都会推荐 VPS 甚至独立服务器来运行 Magen ...
- Warning C4819
VC工程里有个文件,只有文件里写了汉字,就报警告C4819 Warning C4819:The file contains a character that can ot be represented ...
- XMLtank测试记录
1.首先就是这个分辨率对于高分屏的电脑适应太差了....立马让我有弃的想法..(如图) 2.游戏结束之后每次都要从第一关开始,很不方便.建议加入选关功能. 3.鼠标控制不方便,尤其是左键和右键分别控制 ...
- update kernel 3.10-3.12
安装包下载以及依赖包安装 1.到www.kernel.org下载3.12.48压缩包 2.tar xvf linux-3.12.48.tar.xz 3.sudo yum install ncurses ...
- 使用IIS发布WCF服务
上一篇是Windows服务为宿主的WCF服务,现在用IIS为宿主发布WCF服务. 第一步:肯定是新建一个WCF服务啦[是WCF服务应用程序],然后在解决方案上再次添加一个新项目[我们选择WCF服务库, ...
- 使用Maven构建Java Web项目时,关于jsp中引入js、css文件路径问题。
今天有点闲,自己动手搭建一个Java Web项目,遇到jsp中引入js.css文件时路径不正确的问题,于是在网上查阅了很多资料,最终都无法解决问题,于是,上stackoverflow找到了解决方法,这 ...