当前位置: 首页 > news >正文

Linux timekeeping

【概述】

timekeeping模块是一个提供时间服务的基础模块。Linux内核提供各种time line,real time clock,monotonic clock、monotonic raw clock等,timekeeping模块就是负责跟踪、维护这些timeline的,并且向其他模块(timer相关模块、用户空间的时间服务等)提供服务,而timekeeping模块维护timeline的基础是基于clocksource模块和tick模块。通过tick模块的tick事件,可以周期性的更新time line通过clocksource模块可以获取tick之间更精准的时间信息

【初始化】

timekeeping初始化的代码位于timekeeping_init函数中,在系统初始化的时候(start_kernel)会调用该函数进行timekeeping的初始化。

【persistent clock】

系统上电时,timekeeping模块会从persistent clock中读取系统当前的时间值,所谓的persistent clock就是系统断电仍然在运行的时钟,比如典型的x86 CMOS/RTC时钟。

timekeeping_init [kernel/time/timekeeping.c]

……

    read_persistent_wall_and_boot_offset(&wall_time, &boot_offset);

    read_persistent_clock64(wall_time);

    *boot_offset = ns_to_timespec64(local_clock());

read_persistent_clock64函数是架构相关函数,x86架构是读取RTC/CMOS时间,arm架构一般没有persistent时间(omap好像实现了一个),所以就是dummy(sec和nsec都设置为0)。另外,x86的虚拟机还可以用kvmclock来当作persistent clock!

【设置default的clocksource】

在timekeeping初始化的时候,很难选择一个最好的clocksource,因为很有可能最好的那个还没有初始化呢。因此,这里的策略就是采用一个在timekeeping初始化时一定是ready的clocksource,也就是基于jiffies的那个clocksource。clocksource_default_clock定义在kernel/time/jiffies.c,是一个weak symble,如果你愿意也可以重新定义clocksource_default_clock这个函数。不过,要保证在timekeeping初始化的时候是ready的。

timekeeping_init [kernel/time/timekeeping.c]

……

    clock = clocksource_default_clock();

    if (clock->enable)

        clock->enable(clock);

    tk_setup_internals(tk, clock);

【初始化REALTIME、MONITONIC等clock】

timekeeping_init [kernel/time/timekeeping.c]

……

    wall_to_mono = timespec64_sub(boot_offset, wall_time);

    tk_set_xtime(tk, &wall_time); //1

    tk->raw_sec = 0; //2

    tk_set_wall_to_mono(tk, wall_to_mono); //3

  1. 根据从RTC中获取的时间值来初始化timekeeping中的realtime clock,如果没有获取到正确的RTC时间值,那么缺省的realtime(wall time)就是0,即linux epoch1970-01-01 00:00:00)。
  2. monotonic raw clock被设定为从0开始
  3. timekeeper并没有直接保存monotonic clock,而是保存了一个wall_to_monotonic的值,这个值类似offset,realtime clock加上这个offset就可以得到monotonic clock。因此,初始化的时间点上,monotonic clock实际上等于0(如果没有获取到有效的booting time)。当系统运行之后,real time clock+ wall_to_monotonic是系统的uptime,而real time clock+ wall_to_monotonic + sleep time也就是系统的boot time。

这里需要说明2点:

1、linux的墙上时间(wall time)都是基于linux epoch时间的offset(sec、nsec),即使从RTC或UTC中获取的时间是具体的:xx年xx月xx日xx时xx分xx秒,在设置到linux内核wall time(realtime或monotonic)时,都需要转换为基于linux epoch(1970-01-01 00:00:00)的offset。参见函数mktime64 [kernel/time/time.c]!

2、monitonic时间是以上电开始作为0时刻的,所以,上面在设置monotonic的offset(wall_to_mono)的时候,设置为当前的boottime - walltime的值。所以,

wall time + wall_to_mono = boot time。

【获取当前系统时间】

【获取monotonic clock】

ktime_get和ktime_get_ts64

ktime_get

base = tk->tkr_mono.base;

nsecs = timekeeping_get_ns(&tk->tkr_mono);

timekeeping_get_delta

cycle_now = tk_clock_read(tkr);

delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask);

ktime_add_ns(base, nsecs)

一般而言,timekeeping模块是在tick到来的时候更新各种系统时钟的时间值,ktime_get调用很有可能发生在两次tick之间,这时候,仅仅依靠当前系统时钟的值精度就不甚理想了,毕竟那个时间值是per tick更新的。因此,为了获得高精度,ns值的获取是通过timekeeping_get_ns完成的,该函数获取了realtime clock的当前时刻的纳秒值,而这是通过上一次的tick时候的realtime clock的时间值,加上当前时刻到上一次tick之间的delta时间值计算得到的。

ktime_get_ts的概念和ktime_get是一样的,只不过返回的时间值格式不一样而已。

【获取realtime clock】

ktime_get_real和ktime_get_real_ts64

这两个函数的具体逻辑动作和获取monotonic clock的时间值函数是完全一样的。

【获取boottime clock】

ktime_get_boottime和get_monotonic_boottime

boot clock这个系统时钟和monotonic clock有什么不同?monotonic clock是从一个固定点开始作为epoch,对于linux,就是启动的时间点,因此,monotonic clock是一个从0开始增加的clock,并且不接受用户的setting,看起来好象和boot clock是一致的,不过它们之间唯一的差别是对系统进入suspend的处理,对于monotonic clock,它是不记录系统睡眠时间的,因此monotonic clock得到的是一个system uptime。而boot clock计算睡眠时间,直到系统reboot。

说明:内核提供了两个粗粒度的获取realtime和monotonic clock的函数:current_kernel_time、get_monotonic_coarse。这两个函数不会调用clocksource的read函数获取tick之间的delta时间值,而是直接使用上一次tick设置的值。效率会高一点,但是精度就是tick的时间精度。

【clocksource变更】

除了直接调用clocksource的read函数之外,timekeeping和clocksource主要的交互就是change clocksource的操作了。当系统中有更高精度的clocksource的时候,会调用timekeeping_notify函数通知timekeeping模块进行clock source的切换。

int timekeeping_notify(struct clocksource *clock)

{

    struct timekeeper *tk = &tk_core.timekeeper;

    if (tk->tkr_mono.clock == clock) //新的clocksource和旧的一样,不需要切换

        return 0;

    stop_machine(change_clocksource, clock, NULL);

    tick_clock_notify(); //通知tick模块

    return tk->tkr_mono.clock == clock ? 0 : -1;

}

stop_machine就是stop所有cpu,并在每个cpu上执行stop fn——change_clocksource。change_clocksource主要执行的步骤包括:

  1. 调用timekeeping_forward_now函数。就要更换新的clocksource了,就是旧clocksource最后再发挥一次作用。调用旧的clocksource的read函数,将最后的这段时间间隔(当前到上次read)加到real time clock以及monotonic raw clock上去。
  2. 调用tk_setup_internals函数设定新的clocksource,disable旧的clocksource。由于更换了新的clocksource,一般而言,新旧clocksource的工作参数不一样,就要就导致timekeeper的一些内部的数据成员要进行更新,例如NTP interval、multi和shift factor数值等
  3. 调用timekeeping_update函数。由于更新了clocksource,因此timekeeping模块要更新其内部数据。TK_CLEAR_NTP控制clear 旧的NTP的状态数据。TK_MIRROR用来更新shadow timekeeper,主要是为了保持和real timekeeper同步。TK_CLOCK_WAS_SET用在paravirtual clock场景中,这里就不详细描述了。
http://www.dtcms.com/a/426835.html

相关文章:

  • macOS 下安装 zsh、zsh-syntax-highlighting、powerlevel9k、nerd-font
  • CarveMe:代谢模型构建
  • windows显示驱动开发-调试间接显示驱动程序(二)
  • 企业平台网站建设制作一个网站平台
  • LinuxC++——etcd分布式键值存储系统入门
  • 使用arcgis提取评价指标时,导出数据是负数-9999
  • VUE3+element plus 实现表格行合并
  • LinuxC++——etcd分布式键值存储系统API(libetcd-cpp-api3)下载与二次封装
  • Electron vue项目 打包 exe文件2
  • 【开题答辩全过程】以 springboot高校创新创业课程体系的设计与实现为例,包含答辩的问题和答案
  • package.json详解
  • iOS 应用上架全流程解析,苹果应用发布步骤、ipa 上传工具、TestFlight 测试与 App Store 审核经验
  • QGIS + ArcGIS Pro 下载常见卫星影像及 ESRI Wayback 历史影像
  • Hexo搭建/部署个人博客教程
  • 中山 网站建设发布平台是什么
  • Qt操作Windows平板上摄像头
  • 外贸建站哪好asp网站打开很慢的原因
  • rknn yolo11 推理
  • 虚幻基础:容器
  • 开发环境windows安装oracle 19c并连接数据库
  • 虚幻基础:角色攻击
  • 手机上怎么查看网站设计淮安品牌网站建设
  • go协程的前世今生
  • GO学习2:基本数据类型 与 转换
  • 南京网站开发联系南京乐识昆明餐饮网站建设
  • 3D打印技术如何重塑PEM双极板的制造范式?
  • Excel工作表自动追加工具项目总结报告
  • AR技术赋能航空制造:开启智能装配新时代
  • 盟接之桥说制造:源头制胜,降本增效:从“盟接之桥”看供应链成本控制的底层逻辑
  • 网站名称推荐高端网站设计v芯hyhyk1推好