概述
Linux uptime的实现
上源码
源码是长这个样子的, 小而美!
static int uptime_proc_show(struct seq_file *m, void *v)
{
struct timespec uptime;
struct timespec idle;
u64 idletime;
u64 nsec;
u32 rem;
int i;
idletime = 0;
for_each_possible_cpu(i)
idletime += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
get_monotonic_boottime(&uptime);
nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC;
idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
idle.tv_nsec = rem;
seq_printf(m, "%lu.%02lu %lu.%02lun",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
(unsigned long) idle.tv_sec,
(idle.tv_nsec / (NSEC_PER_SEC / 100)));
return 0;
}
static int uptime_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, uptime_proc_show, NULL);
}
static const struct file_operations uptime_proc_fops = {
.open = uptime_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init proc_uptime_init(void)
{
proc_create("uptime", 0, NULL, &uptime_proc_fops);
return 0;
}
fs_initcall(proc_uptime_init);
此时使用命令读取uptime是这样的:
cat /proc/uptime
47.69 22.13
这就是刚刚开机不久后的开机时间47秒, CPU空闲22秒
增加调试信息
为了理清楚内核的时间的关系, 加了调试打印, 即get_xtime_and_monotonic_and_sleep_offset() 及其后面的seq_printf
static int uptime_proc_show(struct seq_file *m, void *v)
{
struct timespec uptime;
struct timespec idle;
u64 idletime;
u64 nsec;
u32 rem;
int i;
struct timespec xtime;
struct timespec wtime;
struct timespec stime;
idletime = 0;
for_each_possible_cpu(i)
idletime += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
get_xtime_and_monotonic_and_sleep_offset(&xtime, &wtime, &stime);
seq_printf(m, "xtime: %lu.%02lun",
(unsigned long) xtime.tv_sec,
(xtime.tv_nsec / (NSEC_PER_SEC / 100)));
seq_printf(m, "wtime: %lu.%02lun",
(unsigned long) wtime.tv_sec,
(wtime.tv_nsec / (NSEC_PER_SEC / 100)));
seq_printf(m, "stime: %lu.%02lun",
(unsigned long) stime.tv_sec,
(stime.tv_nsec / (NSEC_PER_SEC / 100)));
do_posix_clock_monotonic_gettime(&uptime);
seq_printf(m, "mtime: %lu.%02lun",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)));
monotonic_to_bootbased(&uptime);
nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC;
idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
idle.tv_nsec = rem;
seq_printf(m, "%lu.%02lu %lu.%02lun",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
(unsigned long) idle.tv_sec,
(idle.tv_nsec / (NSEC_PER_SEC / 100)));
return 0;
}
此时的输出变成了这个样子:
xtime: 1262311849.44
wtime: 3032655555.40
stime: 0.00
mtime: 108.85
108.85 76.50
内核时间维护
- 硬件时钟中断是时间更新的根本来源
- 内核使用全局的一个数据结构来维护时间
static struct timekeeper timekeeper;
删除了无效的结构, 只关注主要的结构成员:
struct timekeeper {
......
/* Current CLOCK_REALTIME time in seconds */
u64 xtime_sec;
/* Clock shifted nano seconds */
u64 xtime_nsec;
/*
* wall_to_monotonic is what we need to add to xtime (or xtime corrected
* for sub jiffie times) to get to monotonic time. Monotonic is pegged
* at zero at system boot time, so wall_to_monotonic will be negative,
* however, we will ALWAYS keep the tv_nsec part positive so we can use
* the usual normalization.
*
* wall_to_monotonic is moved after resume from suspend for the
* monotonic time not to jump. We need to add total_sleep_time to
* wall_to_monotonic to get the real boot based time offset.
*
* - wall_to_monotonic is no longer the boot time, getboottime must be
* used instead.
*/
struct timespec wall_to_monotonic;
/* Offset clock monotonic -> clock realtime */
ktime_t offs_real;
/* time spent in suspend */
struct timespec total_sleep_time;
/* Offset clock monotonic -> clock boottime */
ktime_t offs_boot;
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
......
- **xtime_sec 和xtime_nsec:** 是根本, 记录的是当前的时间相对于1970-01-01 00:00:00 +0000 (UTC)的差值. 硬件时间更新即是此值.
- **wall_to_monotonic:** 记录了一个差值(其实是一个负值), 通过xtime_sec + wall_to_monotonic 可计算出当前的开机时间以来的一个时间值(未记入计算机的时间), 即调用do_posix_clock_monotonic_gettime()返回的结果
- **total_sleep_time: ** 记录了系统的休眠时间, 即通过调用do_posix_clock_monotonic_gettime()返回的结果
总结
其实内核主要维护xtime, wall_to_monotonic 和 total_sleep_time三个值即可完成对系统时间的正确维护, 当然这里没有考虑NTP时间同步的因素, 如果增加了NTP时间同步会繁杂一些.
最后
以上就是爱笑香烟为你收集整理的Linux uptime实现详解的全部内容,希望文章能够帮你解决Linux uptime实现详解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复