Post

脚本计时

脚本计时

脚本实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/csh
 
# 信息:wanlin.wang, 2025/01/23
# 用法:在需要计时的业务脚本末尾加一行,source 本脚本。运行完毕业务脚本后,会打印该脚本运行的elapsed time。
 
set pid = $$
 
set system_boot_time = `awk '/^btime / {print $2}' /proc/stat`
set proc_start_time_ticks = `awk '{print $22}' /proc/$pid/stat`
set clock_ticks_per_sec = `getconf CLK_TCK`
 
@ proc_start_time_secs = $proc_start_time_ticks / $clock_ticks_per_sec
@ start_time = $system_boot_time + $proc_start_time_secs
 
set start_time_human = `date -d @$start_time`
set end_time_human = `date`
set end_time = `date +%s`
 
@ elapsed_time = $end_time - $start_time
@ days = $elapsed_time / 86400
@ hours = ($elapsed_time % 86400) / 3600
@ minutes = ($elapsed_time % 3600) / 60
@ seconds = $elapsed_time % 60
 
echo ""
echo "Summary for PID ${pid}:"
echo "Start time: $start_time_human"
echo "End time: $end_time_human"
echo "Elapsed time: ${days} days, ${hours} hours, ${minutes} minutes, ${seconds} seconds"

关键分析

proc_start_time_ticks

是从 Linux 系统启动(boot)那一刻起,到特定进程启动时所经过的“滴答数”(ticks)。这个值可以在 /proc/[pid]/stat 文件中找到,通常是第 22 个字段。

技术原理:

内核时钟中断 (Timer Interrupts): Linux 内核通过一个硬件定时器周期性地产生中断,这被称为“时钟中断”或“定时器中断”。这些中断是内核进行时间管理、任务调度等操作的基础。

Jiffies: 在 Linux 内核内部,有一个全局变量叫做 jiffies(或者在 64 位系统上是 jiffies_64)。这个变量在系统启动时被初始化为 0,并且每发生一次时钟中断,jiffies 的值就会加 1。因此,jiffies 实际上是系统自启动以来所经历的时钟滴答的总数。它被称为内核的“心跳”。

进程的 starttime: 当一个新进程在 Linux 上启动时,内核会记录下它启动时的 jiffies 值。这个值被存储在进程的 task_struct 结构体中(通常是 real_start_time 或类似字段)。当用户空间程序读取 /proc/[pid]/stat 文件时,内核会从这个 task_struct 结构体中提取相应的值并格式化输出。

单位转换: 历史上,starttime 字段直接以 jiffies 为单位。然而,自 Linux 2.6 版本以来,为了提供更统一和可移植的时间单位,starttime 字段的值通常以 clock ticks 为单位,这里的 clock ticks 与 sysconf(_SC_CLK_TCK) (即 CLK_TCK) 返回的值相关联,而不是直接的内核 HZ。这意味着,为了将其转换为秒,需要除以 CLK_TCK,而不是直接除以内核的 HZ 值。这使得用户空间程序更容易进行时间转换。

总结: proc_start_time_ticks 实际上是内核记录的特定进程在系统启动后,经过了多少个“时钟滴答”才开始运行。它是一个相对值,需要结合系统启动的 epoch 时间和滴答频率来计算出进程的绝对启动时间(epoch time)。

clock_ticks_per_sec

通过 getconf CLK_TCK 命令获取,它返回的是一个系统配置值,表示每秒钟有多少个“时钟滴答”。在 POSIX 标准中,这被称为 _SC_CLK_TCK。

技术原理:

用户空间和内核空间时间单位的桥梁: 虽然 Linux 内核有其内部的 HZ(定时器中断频率)来驱动 jiffies,但为了提供给用户空间一个标准化的、与硬件无关的时间单位,POSIX 标准定义了 CLK_TCK。

sysconf() 函数: CLK_TCK 的值通常是系统在启动时确定的,并通过 sysconf() 系统调用(在 C 语言中)或 getconf 命令行工具暴露给用户空间。

历史背景与目的:

在早期的 Unix 系统中,各种系统资源使用时间(如 CPU 时间、进程启动时间等)都以“时钟滴答”为单位报告。然而,不同系统或不同架构的“时钟滴答”频率可能不同。

为了使这些时间度量具有可移植性,POSIX 标准引入了 CLK_TCK,它定义了每秒的时钟滴答数。这样,应用程序就可以通过将报告的滴答数除以 CLK_TCK 来得到以秒为单位的时间,而无需关心底层内核的实际 HZ 值。

CLK_TCK 的常见值是 100(即每秒 100 个滴答,每个滴答 10 毫秒)或 1000(每秒 1000 个滴答,每个滴答 1 毫秒)。现代 Linux 系统上,为了更高的精度,CLK_TCK 常常是 1000。

总结: clock_ticks_per_sec (CLK_TCK) 是一个系统配置参数,它定义了用户空间应用程序进行时间计算时应使用的每秒时钟滴答数。它作为将内核报告的以滴答为单位的时间(例如 proc_start_time_ticks、utime、stime 等)转换为标准秒数的关键转换因子。

This post is licensed under CC BY 4.0 by the author.

支持创作者

如果本文帮助到你,可以通过以下收款码支持我:

收款码

感谢你的支持!