【Linux内核|时间子系统】Linux时间子系统(二)timekeeping简介

article/2025/9/12 12:23:35

文章目录

  • 1. timekeeping
  • 2. 计算墙上时间、启动时间差值
  • 3. timekeeper初始化
    • 3.1. 默认时钟源
    • 3.2. tk_setup_internals
    • 3.3. 设置时间
  • 4. timekeeping_update
    • 4.1. tk_update_ktime_data:tkr_mono和tkr_raw设置
    • 4.2. update_fast_timekeeper
    • 4.3. shadow_timekeeper

1. timekeeping

timekeeping是时间子系统用于从clocksource获取时间,维护墙上时间、单调递增时间、启动时间的模块,timekeeping提供了各种时间的获取接口。其核心数据为tk_core,实现了对timekeeper的加锁访问。

/** The most important data for readout fits into a single 64 byte* cache line.*/
static struct {seqcount_raw_spinlock_t    seq;struct timekeeper    timekeeper;
} tk_core ____cacheline_aligned = {.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_core.seq, &timekeeper_lock),
};static struct timekeeper shadow_timekeeper;

timekeeping_init主要就是在对tk_core.timekeeper进行初始化。下面是timekeeping_init函数总体流程

  1. read_persistent_wall_and_boot_offset读取wall_time和boot_offest。默认为0。1
  2. 验证wall_time和boot_offset是否正确,不正确则设置为0
  3. 计算wall_to_mono
  4. 获取锁,开始修改tk
  5. ntp_init(Network Time Protocol)
  6. clocksource_default_clock获取默认clock并enable,clocksource默认为clocksource_jiffies,在probe timer后会切换clocksource
  7. tk_setup_internals、tk_set_xtime、tk_set_wall_to_mono和timekeeping_update设置tk
  8. 释放锁

在这里插入图片描述

2. 计算墙上时间、启动时间差值

wall_time墙上时间:自然时间,也就是真实世界的时间。timekeeper里用xtime表示。

boot_time:系统启动的时间

boot_offset = wall_time - boot_time
wall_time + wall_to_mono = boot_time

read_persistent_wall_and_boot_offset读取时钟,这个函数是一个 __weak的函数,默认设置wall_time和boot_offset为0,如果支持rtc时钟,可以读取rtc时钟里的值。

校验wall_time的正确性,如果时间格式正确,而且不为0,则表示有断电不失效的时钟,则设置persistent_clock_exists为true,否则,wall_time必须为0。

校验完wall_time后,再检查boot_offset是否正确,boot_offset不能比wall_time还要晚。

wall_to_mono,将墙上时间转为单调递增时间。单调递增时间是即从某个时间点开始到现在过去的时间。用户不能修改这个时间,但是当系统进入休眠(suspend)时,时间也不会增加的。更改系统时间也不会对mono时间产生影响。

接下来就是比较重要的初始化timekeeper的部分了。

3. timekeeper初始化

tk_core.timekeeper受自旋锁timekeeper_lock和读写顺序锁tk_core.seq保护。

首先需要获取锁。

ntp_init,ntp(Network Time Protocol,网络时间协议)相关初始化,暂不分析。

3.1. 默认时钟源

clocksource_default_clock用于获取默认时钟源,这是一个 __weak函数,默认使用clocksource_jiffies作为时钟源,精度很低,如果有更精确的时钟源,可以重新实现此函数。这里设置一个时钟源,是为了防止调用获取时间的接口时出现问题。后续有新的时钟源注册时,会替换掉低精度的时钟源。

/** The Jiffies based clocksource is the lowest common* denominator clock source which should function on* all systems. It has the same coarse resolution as* the timer interrupt frequency HZ and it suffers* inaccuracies caused by missed or lost timer* interrupts and the inability for the timer* interrupt hardware to accurately tick at the* requested HZ value. It is also not recommended* for "tick-less" systems.*/
static struct clocksource clocksource_jiffies = {.name            = "jiffies",.rating            = 1, /* lowest valid rating*/.uncertainty_margin    = 32 * NSEC_PER_MSEC,.read            = jiffies_read,.mask            = CLOCKSOURCE_MASK(32),.mult            = TICK_NSEC << JIFFIES_SHIFT, /* details above */.shift            = JIFFIES_SHIFT,.max_cycles        = 10,
};

获取时钟源后,如果该时钟源有enable回调,则需要调用该函数来使能。

3.2. tk_setup_internals

tk_setup_internals来初始化tk_core.timekeeper的一些内部成员。

其中比较中要的是tkr_mono和tkr_raw,使用默认时钟对这两个成员初始化,用于给获取时间的接口提供时钟源,比如ktime_get接口。在后续有更高精度的时钟之后,会进行更新。

3.3. 设置时间

tk_set_xtime墙上时间

根据之前计算出的wall_time设置tk_core.timekeeper的xtime_sec和tkr_mono.xtime_nsec。

tk->raw_sec = 0,这是CLOCK_MONOTONIC_RAW

根据之前计算出的wall_to_mono,调用tk_set_wall_to_mono设置一些offs_real和offs_tai,这些offset在调用时间获取接口时会用到。

static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
{struct timespec64 tmp;/** Verify consistency of: offset_real = -wall_to_monotonic* before modifying anything*/set_normalized_timespec64(&tmp, -tk->wall_to_monotonic.tv_sec,-tk->wall_to_monotonic.tv_nsec);WARN_ON_ONCE(tk->offs_real != timespec64_to_ktime(tmp));tk->wall_to_monotonic = wtm;set_normalized_timespec64(&tmp, -wtm.tv_sec, -wtm.tv_nsec);tk->offs_real = timespec64_to_ktime(tmp);tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tk->tai_offset, 0));
}

4. timekeeping_update

timekeeping_update是最终完成各种时间基准初始化的函数。

/* must hold timekeeper_lock */
static void timekeeping_update(struct timekeeper *tk, unsigned int action)
{if (action & TK_CLEAR_NTP) {tk->ntp_error = 0;ntp_clear();}tk_update_leap_state(tk);tk_update_ktime_data(tk);update_vsyscall(tk);update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);tk->tkr_mono.base_real = tk->tkr_mono.base + tk->offs_real;update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono);update_fast_timekeeper(&tk->tkr_raw,  &tk_fast_raw);if (action & TK_CLOCK_WAS_SET)tk->clock_was_set_seq++;/** The mirroring of the data to the shadow-timekeeper needs* to happen last here to ensure we don't over-write the* timekeeper structure on the next update with stale data*/if (action & TK_MIRROR)memcpy(&shadow_timekeeper, &tk_core.timekeeper,sizeof(tk_core.timekeeper));
}

tk_update_leap_state闰秒调整

4.1. tk_update_ktime_data:tkr_mono和tkr_raw设置

tk->tkr_mono.base

tk->tkr_raw.base

tk->ktime_sec

tk->tkr_mono.base_real = tk->tkr_mono.base + tk->offs_real

4.2. update_fast_timekeeper

除了tkr_mono和tkr_raw两个struct tk_read_base,linux内核还定义了两个struct tk_fast,tk_fast_mono和tk_fast_raw。这两个是用来实现NMI safe的。

/*** struct tk_fast - NMI safe timekeeper* @seq:    Sequence counter for protecting updates. The lowest bit*        is the index for the tk_read_base array* @base:    tk_read_base array. Access is indexed by the lowest bit of*        @seq.** See @update_fast_timekeeper() below.*/
struct tk_fast {seqcount_latch_t    seq;struct tk_read_base    base[2];
};
/** Boot time initialization which allows local_clock() to be utilized* during early boot when clocksources are not available. local_clock()* returns nanoseconds already so no conversion is required, hence mult=1* and shift=0. When the first proper clocksource is installed then* the fast time keepers are updated with the correct values.*/
define FAST_TK_INIT                        \{                            \.clock        = &dummy_clock,            \.mask        = CLOCKSOURCE_MASK(64),        \.mult        = 1,                \.shift        = 0,                \}static struct tk_fast tk_fast_mono ____cacheline_aligned = {.seq     = SEQCNT_LATCH_ZERO(tk_fast_mono.seq),.base[0] = FAST_TK_INIT,.base[1] = FAST_TK_INIT,
};static struct tk_fast tk_fast_raw  ____cacheline_aligned = {.seq     = SEQCNT_LATCH_ZERO(tk_fast_raw.seq),.base[0] = FAST_TK_INIT,.base[1] = FAST_TK_INIT,
};

可以对比一下,访问tkr_mono和tkr_raw时,用的是read_seqcount_begin和read_seqcount_retry,而访问tk_fast_mono和tk_fast_raw用的是raw_read_seqcount_latch和read_seqcount_latch_retry。

具体可以看内核ktime_get_mono_fast_ns和ktime_get_raw_fast_ns等函数的解释。

    update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono);update_fast_timekeeper(&tk->tkr_raw,  &tk_fast_raw);

以tk_fast_mono为例,update_fast_timekeeper是把timekeeper的tkr_mono复制到

tk_fast_mono的base数组,保存两份是为了保证在修改一个时,可以用另一个来获取正确的数值。

4.3. shadow_timekeeper

如果action指定了TK_MIRROR,则将tk_core.timekeeper备份到shadow_timekeeper,shadow_timekeeper可以用于在resume后恢复timekeeper。这个动作需要在最后进行,以确保在下一次更新时不会用过时的数据重写timekeeper。

最后再释放一下锁,这样timekeeping就初始化好了。

在timer_probe时,会注册精度更高的clocksource,这样就可以获取各种时间。


http://chatgpt.dhexx.cn/article/lwWSNvlF.shtml

相关文章

matlab 梯度下降 求偏导,通过计算图求梯度下降中各偏导的推导

通过计算图求梯度下降中各偏导的推导 Author: nex3z 2017-08-30 在 Neural Networks and Deep Learning 课程的 Logistic Regression Gradient Descent 一节以逻辑回归为例&#xff0c;介绍了使用计算图(Computation Graph)求梯度下降中各偏导的方法&#xff0c;但没有给出具体…

matlab|求导数/最值

本博文源于matlab求导数求极值求最值&#xff0c;涉及内容极限命令求导/diff求导/一元函数一阶导数&#xff0c;多阶导数&#xff0c;求参数导数/函数极值和最值/不给定区间求最值 用极限命令求导 例子&#xff1a;求函数3sinx4x^2在x0处的导数 >> syms t; limit((3*…

matlab 梯度下降 求偏导,吴恩达机器学习课程课时12梯度下降算法中参数θ0,θ1求偏导...

最近学习吴恩达的机器学习课程。 看到了线性回归的梯度下降算法。课程中将了一个非常简单的线性回归&#xff1a; 比如给出一些房子的size和对应的price&#xff0c;我们可以建立一个模型(在此模型就是线性回归)&#xff0c; 希望之后在给出任意一个房子的size&#xff0c;可以…

matlab求COPULA偏导,matlab note

Update date&#xff1a;2018-01-05 Matlab Note 1 vine-copula 1.1 xlsread() 打开xlsx里面的数据 S3CE xlsread(电表建模数据.xlsx,S3CE&#xff0c;‘G2:G52’) 1.2常见希腊发音总结 image.png 3.prob() 连乘 由于matlab中的元素是以矩阵为单位,prod(x)就是把x向量中所有元…

matlab求解多元函数的偏导数diff

本博文源于matlab求解多元函数导数。涉及求一阶/求多阶/求向量偏导数/求隐函数导数 多元函数的偏导数 diff(f(x,y,z),变量名)例子 求x^2lny根号z的偏导数 >> syms x >> syms y >> syms z >> du_dx diff(x^2log(y)sqrt(z),x)du_dx 2*x>> du_dz…

matlab实现隐函数求偏导数(impldiff函数)

目录 总述函数说明应用举例例1例2 函数实现 总述 由前面给出的算法&#xff0c;可以编写出如下函数来求解隐函数的偏导数。 函数说明 function dy impldiff(f, x, y, n) %impldiff %隐函数求导 % 调用格式&#xff1a; % f1 impldiff(f, x, y, n) % 其中&#xff1a;f…

matlab偏导数方程,利用Matlab求解不同类型的偏微分方程

来源:新浪了凡春秋的博客 在科学技术各领域中,有很多问题都可以归结为偏微分方程问题。在物理专业的力学、热学、电学、光学、近代物理课程中都可遇见偏微分方程。偏微分方程,再加上边界条件、初始条件构成的数学模型,只有在很特殊情况下才可求得解析解。随着计算机技术的发…

【MATLAB】求偏导数

目录 1、示例1 2、示例2 3、MATLAB求偏导数的应用 1、示例1 syms x y; z=(1+x*y)^y; zx=diff (z,’x’)

MATLAB求解偏导数

MATLAB具有多元函数求解偏导数的功能。 例&#xff1a; 1.函数关于x的二阶偏导数 syms x y >> z x^4y^4-4*x^2*y^2; >> zxx diff(z,x,2)zxx 12*x^2 - 8*y^2 2.函数关于y的二阶偏导数 zyy diff(z,y,2)zyy 12*y^2 - 8*x^2 3.函数二阶混合偏导数 zxy diff(dif…

MATLAB常用求导和求偏导函数

matlab求导命令diff调用格式: diff(函数) &#xff0c; 求的一阶导数&#xff1b;diff(函数&#xff0c; n) &#xff0c;求的n阶导数(n是具体整数)&#xff1b;diff(函数&#xff0c;变量名)&#xff0c;求对的偏导数&#xff1b;diff(函数&#xff0c; 变量名&#xff0c;n)…

性能测试流程(完整版)

一、 规范性能测试实施流程的意义 规范的性能测试实施流程能够加强测试工作流程控制&#xff0c;明确性能测试各阶段应完成的工作&#xff0c;指导测试人员正确、有序的开展性能测试工作&#xff0c;提高各角色在性能能测试中的工作效率。本次分享的性能测试实施流程是性能测试…

性能测试流程相关

1、脚本制作流程 脚本制作方法可参考此链接&#xff1a;性能测试脚本实战_HealerLX的博客-CSDN博客 &#xff08;1&#xff09;抓包工具抓包 &#xff08;2&#xff09;录入到性能测试工具中 &#xff08;3&#xff09;调试脚本直到成功 &#xff08;4&#xff09;加上运行逻辑…

性能测试流程、优化、指标

性能测试流程、优化、指标 1、性能测试的流程 1、确定性能测试的目标 之前做的压测性能标准、产品说明书的性能需求部分、运营人员提出的性能指标、通过生产环境换算出的性能指标等 &#xff08;1&#xff09;接口响应时间不能超过3秒&#xff08;每个接口的响应时间&#…

性能测试流程规范

完整的性能测试流程 下午逛一个测试交流群时&#xff0c;聊起性能测试&#xff0c;然后某位群成员说他们用的loadrunner做性能&#xff0c;当时觉得这话有点偏颇&#xff0c;虽然我也是一个性能测试道路上的摸索前进者。。。 诚然&#xff0c;我们在进行性能测试工作的过程中…

Jmeter完整的性能测试流程图,接口测试步骤

第零:300G全套最新软测视频教程分享 链接:https://pan.baidu.com/s/17jkyGn-Wm-zC6QQLkWjrsw 提取码:o94n 第一:测试相关系统准备 1. 验证基本系统功能后 性能测试在哪个阶段开始介入?通常,最好仅在功能测试完成后系统稳定时才开始介入性能测试. 2. 测试团队的组织…

Jmeter性能测试流程

1.关联真机或者模拟器,设置手动代理,要连在一个网络之下执行。 2.通过接口文档或者Charles进行抓包获取接口以及接口参数 3.通过Jmeter进行压力测试:添加线程组,添加http请求,添加响应断言,添加聚合报告 4.添加http请求 5,添加响应断言

性能测试流程及数据分析

性能测试流程 性能测试的工作三大部分性能测试执行阶段测试的主要策略总结阶段&#xff1a; 性能测试的工作三大部分 性能需求调研&#xff1a; 客户能接受的响应时间&#xff0c;每日单交易处理能力&#xff0c;系统资源利用率&#xff0c;系统环境搭建方式、并发用户数、日交…

浅谈Jmeter性能测试流程

不管是Loadrunner还是jmeter进行性能测试&#xff0c;测试流程基本上都是一样的&#xff0c;限制以Jmeter为例分析测试流程&#xff1a; 一、性能测试需求分析 一般而言&#xff0c;被测对象的性能需求&#xff0c;会在用户需求规格说明说中给出&#xff0c;比如单位时间内的访…

性能测试流程 - 即拿即落地(超级详细)

目录&#xff1a;导读 前言一、制定目的二、适用范围三、测试流程四、四大阶段五、总结 前言 性能测试成熟度级别 救火&#xff08;Firefighting&#xff09;&#xff1a;应用程序发布前很少或从来没有进行过性能测试的情况。所有性能缺陷&#xff08;100%&#xff09;都在生…

完整的性能测试流程

一、准备工作 在什么阶段开展性能测试工作&#xff1f;一般情况下&#xff0c;是在被测系统已完成功能测试、系统趋于稳定的情况下&#xff0c;才会进行性能测试。 组建测试团队 ● 根据被测系统的实际情况&#xff0c;组建一个性能测试团队&#xff0c;团队成员包括&#xff…