资讯动态

Linux 内核时间体系入门教程——从 CONFIG_HZ 到 hrtimer

发布时间:2026/9/2 17:29:49 来源:尧图企业网站定制
Linux 内核时间体系入门教程——从 CONFIG_HZ 到 hrtimer读者对象刚接触 Linux 内核的嵌入式开发者。读这份文档不需要任何内核时间子系统的前置知识需要的预备知识已全部放在第 1 章。环境背景本文所有代码、结论、实验均基于 RK3588 Linux 5.10.198android12-5.10 分支 busybox 用户态rockchip_linux_defconfigCONFIG_HZ300。其他平台/版本结论基本通用个别数值会不同。如何读新手按章节顺序读有基础的可以直接跳第 4、6 章。每章开头有一句话导读。第 1 章 预备知识导读这一章补齐理解后文必需的四个概念。已经熟悉的读者可以快速跳过但建议至少扫一遍 1.2 的上下文概念它是理解第 6 章的钥匙。1.1 用户态与内核态CPU 的两种身份CPU 有特权级之分ARM 上叫 EL0/EL1x86 上叫 Ring3/Ring0用户态你的应用程序跑的地方。权限受限不能直接碰硬件、不能直接读别的进程的内存。内核态操作系统内核跑的地方。权限全开直接操作硬件。应用程序想做事读文件、发网络包、睡觉必须申请内核代劳这个动作叫系统调用syscall你的应用 内核 │ write(fd, buf, n) │ │ ──────── syscall ────→ │ ext4 文件系统 → 块层 → eMMC 驱动 │ ←────── 返回 ────────── │这个区分直接引出后文的 utime/stime第 5 章CPU 跑你的代码的时间记 utimeCPU 在内核里替你干活的时间记 stime。1.2 中断内核的门铃想象两个查快递的方式轮询每 5 分钟跑下楼看一次有没有快递。简单但大部分白跑。中断在家干活快递员按门铃你才下去。高效事件驱动。硬件设备网卡、触摸屏、定时器都用中断通知 CPU。中断处理分两级硬中断hardirq门铃响了先冲下去签个字——必须快会打断当前正在跑的一切代码期间不能睡眠、不能再被普通代码打断。软中断softirq签字后发现的复杂事情拆包裹、整理发票记到小本本上等稍后安全的时候再处理。这个稍后就是软中断上下文。关键概念上下文context——指当前这段代码是以什么身份在跑上下文谁触发的能否睡眠进程上下文系统调用、内核线程可以睡硬中断上下文硬件中断绝对不能软中断上下文硬中断记账延后的活不能睡眠指主动让出 CPU 等待某个条件比如等 100ms。理解了这张表第 6 章回调跑在哪个上下文的讨论就不再是天书。1.3 定时器与闹钟硬件定时器芯片里真实存在的电路能数数也能到点打铃产生中断。就像一个自带闹钟功能的电子表。软件定时器内核里登记的备忘录——“到 X 时刻请帮我执行函数 F”。它本身不是硬件到期还是要靠硬件闹钟提醒。记住这句话第 6 章会反复用到内核里所有定时器最终都靠同一颗硬件闹钟提醒软件只是登记和回调的代码。1.4 Kconfig 与 defconfig内核的配置系统内核有几千个功能开关全部以CONFIG_开头CONFIG_HZ_300y # 打开300Hz 选项 # CONFIG_HZ_1000 is not set # 关闭1000Hz 选项 CONFIG_HIGH_RES_TIMERSy # 打开高精度定时器支持这些开关定义在Kconfig文件里kernel/Kconfig.hz、kernel/time/Kconfig等编译前由make xxx_defconfig生成最终的.config。改配置 → 重新编译 → 烧写内核是内核开发的基本循环。第 2 章 一切的源头ARM 通用定时器导读先认识硬件软件的一切都是围绕它搭建的。RK3588 用的是ARM 通用定时器arch_timer全芯片共享一个系统计数器每个 CPU 核各带一个自己的比较器这正是第 7 章hrtimer 柜台每个 CPU 一套的硬件根基。它有两个角色计数器counter一个硬件电路在永不停止地数数纳秒级步进不可写、不可清零。相当于一块一直在走的表。比较器comparator可编程的闹钟——设一个目标值计数器数到它就产生一个中断。在内核里这两个功能有两个专业名字硬件功能内核术语用途计数器读数clocksource时钟源回答现在几点了比较器打铃clockevent时钟事件设备回答到时候叫我后面所有内容——jiffies、hrtimer、tick——都是这两个角色的不同租户。第 3 章 两套时间世界导读内核的时间管理分成粗、细两套体系。理解这张图后面的章节都只是展开它。硬件ARM Generic Timer (arch_timer) ┌───────────────────────────────────────────┐ │ ① 免跑计数器 (counter)硬件一直在数 │ │ ② 比较器 (comparator)到点能打中断 │ └──────┬───────────────────────┬────────────┘ 读①│ 配②│ ▼ ▼ clocksource clockevent (oneshot) │ │ ▼ ├────────────────┐ timekeeper时间管家 ▼ ▼ 管墙钟/单调时间, ns tick hrtimer │ jiffies_64 (纳秒, 红黑树) │ 跑到期的 timer │ ▼ scheduler tick ├─ usleep_range() ┌───────────────────┐ (HZ300 → 3.33ms) ├─ clock_nanosleep │ ktime_get() │ ├─ poll/epoll/select 超时 │ ktime_get_real_* │ ← /proc/uptime └─ POSIX timers │ ktime_get_boottime│ ← printk [ 123.456789 ] │ ktime_get_raw │ ← clock_gettime() └───────────────────┘ ══ 粗粒度世界 ══ ══ 细粒度世界 ══ timer wheel (timer.c) hrtimer (hrtimer.c) mod_timer / msleep hrtimer_start / usleep_range 粒度 1 拍 3.33ms 精度 纳秒 └─── 汇率换算: msecs_to_jiffies() ───┘逐块解读左边一条线读计数器① → timekeeper 算出现在是几点纳秒级→ 提供给用户态的clock_gettime()、/proc/uptime等。右边一条线编程比较器②让它到点打中断 → 中断里既喂心跳jiffies也喂高精度闹钟hrtimer。两个世界由同一颗硬件喂所以不会各走各的漂移。3.1 粗粒度世界心跳计数器 jiffiesjiffies 是什么内核的全局心跳计数器。定时器硬件每打一次铃称为一次tick“一拍”它就 1。它记录的是开机以来总共跳了多少拍单位是拍不是秒。它朴素得惊人总共三段代码/* include/linux/jiffies.h —— 声明 */externu64 __cacheline_aligned_in_smp jiffies_64;externunsignedlongvolatile__cacheline_aligned_in_smp __jiffy_arch_data jiffies;/* kernel/time/timer.c —— 定义 */__visible u64 jiffies_64 __cacheline_aligned_in_smpINITIAL_JIFFIES;/* kernel/time/timekeeping.c —— 每次时钟中断自增 */voiddo_timer(unsignedlongticks){jiffies_64ticks;/* 一次 tick加 1 */calc_global_load();}三个要点jiffies不是另一个独立变量链接脚本把jiffies符号直接指到jiffies_64的地址上。32 位平台上unsigned long只有 32 位jiffies恰好盖住jiffies_64的低 32 位在 arm64 这样的 64 位平台上两者就是同一个 64 位变量get_jiffies_64()在 64 位平台直接返回jiffies。volatile是必须的——它被中断异步改写编译器不许把对它的读操作缓存到寄存器里。它是个计数器不是时间。想知道过了多久永远是现在读一次减去之前读一次。换算HZ 是每秒拍数本文环境 HZ300msecs_to_jiffies(1000)→300拍/* 1 秒 */msecs_to_jiffies(5)→2拍/* 注意5/3.331.5 → 向上取整 */jiffies_to_msecs(1)→4ms/* 1 拍 ≈ 3.33ms换算同样向上取整 */彩蛋故意开机 5 分钟就溢出include/linux/jiffies.h/* * Have the 32 bit jiffies value wrap 5 minutes after boot * so jiffies wrap bugs show up earlier. */#defineINITIAL_JIFFIES((unsignedlong)(unsignedint)(-300*HZ))jiffies的类型是unsigned long宽度跟着平台走32 位平台上它就是 32 位数数到顶会回绕wrap归零。归零后5 大数用普通的比较会得出荒谬结论所以内核规定必须用time_after()这类专门处理回绕的宏。内核开发者还故意把初始值设成离回绕只差 5 分钟——在 32 位平台上任何没用time_after()的 bug 开机 5 分钟内就会暴露相当于给全内核打了疫苗。rk3588平台的实情arm64 是 64 位平台jiffies与jiffies_64同体、都是 64 位数到宇宙热寂也回绕不了低 32 位那场5 分钟翻转在这里翻不起浪疫苗只是保留了传统。但time_after()依旧是规定写法——代码要能移植到 32 位平台而且它的语义比较相对拍数差也更明确。驱动里最经典的超时写法unsignedlongtimeoutjiffiesmsecs_to_jiffies(100);/* 记下100ms 后的拍号 */while(hardware_not_ready()){if(time_after(jiffies,timeout))/* 当前拍号超过截止拍号 */return-ETIMEDOUT;udelay(10);}容易认错的假 jiffies东西是不是 jiffies真身/proc/uptime不是ktime纳秒级休眠也计时printk 时间戳[ 123.456789]不是local_clock()纳秒级times()返回值单位像用户态 ABI 固定 CLK_TCK100与内核 HZ 无关loadavg 采样是每 5 秒LOAD_FREQ 5×HZ1 拍采一次驱动超时time_after(jiffies, ...)是真玩家最重要的一句jiffies 是相对心跳不是墙钟时间。它不知道现在是几点系统休眠时它也停跳。想算真实世界时间找 timekeeperktime。3.2 细粒度世界timekeeper 与 ktimetimekeeper 是内核的时间管家它读硬件计数器①换算成纳秒维护几种钟时钟名字特点墙钟CLOCK_REALTIME跟着现实世界走NTP 校时会影响它单调钟CLOCK_MONOTONIC只进不退校时不影响但休眠时不走开机钟CLOCK_BOOTTIME单调 休眠也计时TAICLOCK_TAI单调不吃闰秒用户态的clock_gettime()、/proc/uptime、printk 时间戳全部来自这套体系——和 HZ 完全无关。3.3 NO_HZ闲下来就不打心跳心跳有什么代价每次 tick 中断都要耗 CPU、耗电。但 CPU 睡觉idle的时候心跳毫无用处——没有进程要调度没有账要记。CONFIG_NO_HZ_IDLE即CONFIG_NO_HZy的作用就是CPU idle 时把心跳完全停掉硬件闹钟只在下一个定时器真正到期时才响。这叫 dynticks动态 tick。所以 HZ 的开销公式是忙碌核数 × HZ不是核数 × HZ。RK3588 八核全忙、HZ300 时是 2400 次/秒挂机时接近 0。第 4 章 CONFIG_HZ 详解导读本章回答三个问题——HZ 是什么、它到底影响什么、该怎么选。4.1 它是什么CONFIG_HZ 是心跳频率的配置定义在kernel/Kconfig.hz只有四档选项一拍多长典型用户CONFIG_HZ_10010 ms服务器、NVR如本仓库rk3568_nvr.configCONFIG_HZ_2504 ms折中本仓库机器人配置CONFIG_HZ_3003.33 ms多媒体甜点值本仓库默认rockchip_linux_defconfigCONFIG_HZ_10001 ms低延迟rk3308/px30 defconfig300 这个怪数字的来历它能被 PAL50fps和 NTSC60fps帧率整除是视频/多媒体时代的折中方案。4.2 它的五大职责前提纠正很多人以为 HZ 管系统时间——其实墙钟、uptime、printk 时间戳全走 timekeeperHZ 管的是心跳节奏以及一切按拍计费的东西。职责 1定时器轮的刻度密度内核里大量定时器timer_list见第 6 章以拍为刻度。刻度越密mod_timer()定的闹钟能越准。职责 2睡眠/超时的取整内核的msleep()/schedule_timeout()按拍向上取整调用HZ100HZ300HZ1000msleep(1)实际睡10~20 ms3.33~6.67 ms1~2 ms设 n 拍超时实际睡 n-1~n 拍——挂表时当前拍已经走掉的那一截不计入。一个驱动循环里写msleep(1)轮询HZ300 下比 1000 慢 3 倍。这是 HZ 最常见的隐性变慢来源。顺带一提msleep的实现kernel/time/timer.cvoidmsleep(unsignedintmsecs){unsignedlongtimeoutmsecs_to_jiffies(msecs)1;...}那个 1不是防 0 拍——msecs_to_jiffies()本身向上取整最小就是 1 拍。它防的是短睡如上所述设 n 拍超时实际可能只睡到 n-1 拍出头比请求的毫秒数短1 之后实际睡眠必然覆盖请求时长。职责 3进程 CPU 统计的量化粒度内核采用 tick 记账kernel/sched/cputime.cvoidaccount_process_tick(structtask_struct*p,intuser_tick)每次 tick 看一眼 CPU 正跑在用户态还是内核态给对应账本 1 拍。所以top/ps里 CPU 时间的记账粒度是 1 拍HZ100 时一拍 10ms——一个跑了 5ms 的短进程可能记 0 拍或 1 拍显示 0% 或 100%全看记账时机注意展示给用户态时还要换算成固定 100Hz 的单位见实验 3。职责 4调度节拍响应上限tick 里做抢占检查和负载均衡触发。一个不睡眠、霸占 CPU 的任务“霸王龙任务”最坏要等 1 拍才被调度器巡视到HZ100 → 最坏 10msHZ1000 → 1ms。注意这只影响正在跑的任务被周期性检查这一条路任务唤醒抢占wakeup preemption是事件驱动的不走 tick。职责 5写死在协议/子系统里的 HZ 常数/* include/net/tcp.h */#defineTCP_TIMEWAIT_LEN(60*HZ)/* TIME_WAIT 存活 60 秒 */#defineTCP_RTO_MAX((unsigned)(120*HZ))/* 重传超时上限 120 秒 */#defineTCP_RTO_MIN((unsigned)(HZ/5))/* 重传下限 200ms */这些常数的意图是秒级时长实现是拍数改 HZ 会自动换算真实时长不变但量化粒度变了。4.3 不受 HZ 影响的东西重要东西原因墙钟、date、CLOCK_REALTIMEtimekeeper 纳秒级/proc/uptime、printk 时间戳timekeeper用户态select/poll/epoll/nanosleep超时走 hrtimerusleep_range()、hrtimer_start()走 hrtimerudelay()忙等读硬件计数器不经定时器用户态sysconf(_SC_CLK_TCK)ABI 固定返回 100别被骗4.4 选型性能、功耗还是响应先破除一个误解高 HZ 不会卡顿——卡顿的根源恰恰是低 HZ 的粗粒度。但高 HZ 也不提高峰值性能吞吐反而微降。性能要拆成两个维度看维度HZ100HZ1000吞吐单位时间干完的活略高微降 ~0.5-1%延迟/响应最坏等多久差10ms 粒度好 10 倍代价的具体账目8 核全忙时HZ100HZ300HZ1000tick 中断/秒80024008000忙时 CPU 开销~0.1%~0.3%~1%msleep(1)实际睡10~20 ms3.33~6.67 ms1~2 ms注意是忙时开销——开了 NO_HZ_IDLE 后挂机功耗各档没有区别。高 HZ 的代价是匀速多缴 1% 税平稳且可预测不会产生任何突发卡顿。卡顿的来源排查顺序是调度延迟、内存抖动、IO 阻塞——其中调度巡视太慢只有低 HZ 会贡献。决策经验问自己有没有msleep(1)级别的内核轮询在热路径上、有没有 4ms 的硬性控制环。有 → 1000没有 → 300 白赚省 0.7% CPU纯录像/吞吐设备 → 100。第 5 章 utime 与 stime进程的两本账导读上一章提到记账本章把这本账讲清楚。每个进程的task_struct内核的进程档案里有两个记账字段include/linux/sched.hu64 utime;/* 用户态时间跑你自己的代码花的 CPU */u64 stime;/* 内核态时间内核替你干活花的 CPU */区分标准不是哪个函数而是CPU 当时跑在哪一态你在做记到哪算哈希、memcpy、解码utime调write()写 eMMCCPU 在 ext4/blk/mmc 路径里跑stime大量printf到串口CPU 在 tty 驱动里折腾stime串口慢速输出是 stime 大户mmap后缺页内核分配物理页stime在板上就能看time./myapp# user 即 utimesys 即 stimecat/proc/pid/stat# 第 14、15 字段如果某程序 sys 远大于 user说明它把时间都花在求内核办事上了典型高频小 IO、疯狂 syscall。第 6 章 内核定时器家族公交与专车导读jiffies 世界和 hrtimer 世界的运行机制对比是理解内核时间子系统的最后一层窗户纸。6.1 timer wheel公交车模式内核里数量最大的定时器用timer_list俗称 timer wheel定时器轮。工作方式像公交车定闹钟只是登记到站牌挂进哈希表不编程任何硬件每次心跳tick到站停车检查这一站该到期的全部处理处理在软中断上下文执行kernel/time/timer.c 的run_timer_softirq。tick 硬中断 → raise_softirq(TIMER_SOFTIRQ) → 软中断阶段扫轮盘 → 回调特点便宜几乎零成本登记、量大O(1)、但精度只有 1 拍3.33ms且有软中断调度延迟。6.2 hrtimer专车模式hrtimer高精度定时器像专车登记时挂进红黑树按到期时间排序每次都把硬件闹钟比较器重编程到最早的到期时刻纳秒精度kernel/time/hrtimer.c 的hrtimer_reprogram→tick_program_event闹钟一响回调直接在硬中断里执行hrtimer_interrupt→__run_hrtimer只有回调处理不过来过载时才把剩余的丢给HRTIMER_SOFTIRQ软中断兜底。所以有一个常见误区要纠正❌ “hrtimer 和普通定时器一样依赖软中断实现”✅ timer wheel 的回调 100% 在软中断hrtimer 的回调正常路径在硬中断软中断只是过载兜底以及显式选择HRTIMER_MODE_SOFT的定时器——第 7 章那 4 个 soft 柜台就是给它们留的它们本来就跑软中断。hrtimer 单闹钟轮转CVAL 是绝对刻度等待量随计数器缩小循环 ③→①回调跑完 → 新最左 B 的绝对刻度 6.0ms 写入 CVAL → 实际等待 TVAL 6.0 − now 5.0 1.0ms且随计数器前进自动缩小无需任何人改写 → 1ms 后铃响重复 ②。整棵树无论挂多少颗定时器始终只占这一颗硬件闹钟tick_sched_timer 靠返回 RESTART 每次重挂自己心跳才能每 3.33ms 响一次。6.3 依赖关系是反的更颠覆的一点高精度模式下tick 本身就是一个 hrtimer。/* kernel/time/tick-sched.c */hrtimer_init(ts-sched_timer,CLOCK_MONOTONIC,HRTIMER_MODE_ABS_HARD);ts-sched_timer.functiontick_sched_timer;那个每 3.33ms 响一次、给 jiffies 的心跳本体是架在 hrtimer 之上的。所以层次关系是硬件 arch_timer 比较器真正的硬定时器全系统唯一 ▲ │ 直接重编程纳秒精度 ┌────┴─────┐ │ hrtimer │ ← 地基 └────┬─────┘ │ tick_sched_timer 是其中一个 hrtimer ▼ tick 中断 ──→ jiffies ──→ TIMER_SOFTIRQ ──→ timer wheel6.4 两兄弟对比总表timer wheel公交hrtimer专车组织结构分级哈希轮盘O(1)红黑树O(log n)谁编程硬件不编程搭 tick 便车每次入队重编程比较器精度1 拍3.33ms 软中断延迟硬件计数器精度纳秒回调上下文softirqhardirq兜底才 softirq典型 APImod_timer()、msleep()、schedule_timeout()hrtimer_start()、usleep_range()6.5 API 选择口诀背这四条存时间戳永远用 ktime 族——jiffies 存时间戳有三宗罪回绕32 位平台、休眠停摆、粒度 3.33ms。睡眠不在乎 ±1 拍 →msleep()要准 →usleep_range(最小, 最大)走 hrtimer。驱动定时器ms 级、大量、频繁重挂 →timer_list要精确 →hrtimer。忙等 1msudelay()arch/arm64/lib/delay.c读硬件计数器空转不经过任何定时器子系统能睡则睡忙等是最后手段。第 7 章 hrtimer 都有谁在用导读把 hrtimer 理解成基础设施这一章看看它的客户名单。柜台每个 CPU 一套 8 个 clock basekernel/time/hrtimer.c4 个硬中断版 4 个软中断版分别对应 MONOTONIC / REALTIME / BOOTTIME / TAI 四种时钟。入队时按你指定的 clockid 路由到对应柜台。客户本仓库实际扫描结果grep -r hrtimer_init(类别用户干什么内核地基tick_sched_timer心跳本体第 6 章讲过内核地基CFS/RT/DL 调度器精确抢占、带宽控制周期内核地基软锁狗watchdog.c检测 CPU 卡死内核地基perf 采样PMU 轮转与采样事件的节拍系统调用clock_nanosleep、timer_create、poll/epoll 超时、futex用户态的直接消费协议栈TCP pacing、fq/netem 流量整形µs 级发包节拍qdisc watchdog 同样架在 hrtimer 上协议栈CANbcm/isotp/j1939车载总线时序协议栈TSNtaprio/act_gate工业以太网门控µs 级准时驱动8250 串口、softdog、Mali GPU十几处、Rockchip RGA3/RVE、USB本板子真身在用规律凡是晚 3.33ms 会出事的场景都在 hrtimer 上——调度公平性、发包节拍TCP pacing、TSN 门控、GPU 负载统计。而晚 3.33ms 无所谓的超时保护、轮询延迟都留在 timer wheel 上。TCP 自己就是最好的分界样本pacing 这种 µs 级敏感的活用 hrtimertcp_sock里的pacing_timer而重传/delayed-ACK/TIME_WAIT 这些百毫秒量级的定时器在 5.10 里仍是 jiffies 级的timer_listinet_connection_sock里的icsk_retransmit_timer/icsk_delack_timer——第 4 章职责 5 那几个*HZ常数正是给它们用的。第 8 章 动手实验RK3588 板上可做导读busybox 环境即可完成把理论对号入座。实验 1亲眼看到心跳cat/proc/interrupts|greparch_timer# 等 1 秒再来一次# 忙碌的核每秒大约 300HZ300idle 的核几乎不动NO_HZ 生效# 跑个死循环让 CPU 忙起来对比whiletrue;do:;done实验 2看定时器世界的名册cat/proc/timer_list|head-60# 能看到每个 CPU 的 hrtimer base、最早到期时间# 以及 function: tick_sched_timer —— 印证tick 是个 hrtimer实验 3感受 CPU 记账的量化cat/proc/stat# cpu 开头的行user/system/idle 等单位是 1/100 秒USER_HZ不是内核的拍# 让一个核忙满 1 秒再 cat 一次user 列增量 ≈ 100与 HZ 无关# /proc/stat 与 times() 同属用户态 ABI一律按 100Hz 换算——想看 HZ 本尊回到实验 1 数 arch_timer 中断第 9 章 常见误区 FAQQ1jiffies 是当前时间吗不是。它是开机以来的心跳拍数相对量、粗粒度、休眠会停。存时间戳用 ktime 族。Q2改了 CONFIG_HZ用户态的times()单位会变吗不会。用户态 ABI 固定 CLK_TCK100和内核 HZ 无关。Q3HZ 越大系统越流畅吗响应粒度越细最坏 10ms → 1ms但峰值吞吐微降 ~1%。流畅卡顿问题通常另有元凶内存、IO、调度不是 HZ。Q4HZ1000 会更耗电吗挂机不会NO_HZ_IDLE 停掉了心跳只有忙时多 ~1% CPU 开销带来的功耗。Q5hrtimer 和 timer wheel 谁更高级要全换 hrtimer 吗各司其职。timer wheel 便宜、O(1)适合海量 ms 级超时hrtimer 精确但每颗都要编程硬件。全换 hrtimer 反而更慢。Q6hrtimer 的回调能睡吗不能它在硬中断上下文兜底的软中断也不能睡。要睡请用工作队列workqueue。Q7msleep(1)到底睡多久会不会等于没睡不会。msecs_to_jiffies()向上取整最小 1 拍绝不会取整成 0msleep()的1再保证不短睡第 4 章职责 2。HZ300 下msleep(1)实际睡 3.33~6.67ms——要 1ms 级精度请改用走 hrtimer 的usleep_range()。真正不保证睡眠时长的是自己写schedule_timeout(0)。Q8printk 的时间戳能用来测 jiffies 吗不能它来自local_clock()纳秒级单调钟比 jiffies 精确得多两者是不同体系。Q9TIME_WAIT 是 60 秒改 HZ 会变吗不会TCP_TIMEWAIT_LEN 60*HZ自动换算。变的只是量化精度。Q10怎么确认我的内核 HZ 是多少板上用实验 1——让一个核忙起来看/proc/interrupts里arch_timer每秒增量≈HZ或zcat /proc/config.gz | grep CONFIG_HZ需编译时开了 IKCONFIG_PROC或直接查.config里的CONFIG_HZ_XXX。注意/proc/stat看不出 HZ——它的单位是固定的 USER_HZ100。第 10 章 术语表术语英文一句话解释tick / 拍tick定时器硬件的一次心跳中断HZHZ每秒心跳次数编译期常量jiffiesjiffies全局心跳计数器一拍 1心跳timer tickCPU 忙时的周期性定时中断时钟源clocksource一直走的硬件计数器回答现在几点时钟事件设备clockevent可编程硬件闹钟回答到时候叫我时间管家timekeeper读 clocksource维护墙钟/单调钟等高精度定时器hrtimer纳秒级定时器回调默认跑硬中断定时器轮timer wheeljiffies 级定时器回调跑软中断动态 tickdynticks / NO_HZCPU 空闲时停掉心跳回绕wraparound32 位计数器数到顶归零用户态/内核态user/kernel modeCPU 的两种特权级utime / stimeuser/system time进程的用户态/内核态 CPU 账本硬中断/软中断hardirq/softirq中断的快处理/延后处理两级上下文context当前代码的身份进程/硬中断/软中断睡眠sleep主动让出 CPU 等条件中断上下文禁止附录源码地图本文档引用的关键文件基于rk3588开源仓库 5.10 源码建议按序阅读文件内容kernel/Kconfig.hzHZ 四档选项定义include/linux/jiffies.hjiffies 声明、INITIAL_JIFFIES彩蛋、time_after宏、换算函数kernel/time/timer.cjiffies_64 定义、timer wheel 全部实现、msleep、schedule_timeoutkernel/time/timekeeping.ctimekeeper、do_timer()jiffies 自增处kernel/time/hrtimer.chrtimer 全部实现、8 个 clock base、hrtimer_reprogramkernel/time/tick-sched.ctick_sched_timer——tick 是个 hrtimer的证据kernel/sched/cputime.caccount_process_tick——tick 记账arch/arm64/lib/delay.cudelay忙等的真身arch/arm64/configs/rockchip_linux_defconfig本板当前配置HZ_300、NO_HZ、HIGH_RES_TIMERS本文档由 CONFIG_HZ / jiffies / 内核时间体系的技术讨论整理而成示例与代码行号对应 Linux 5.10.198 源码。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价