我是靠谱客的博主 爱笑香烟,最近开发中收集的这篇文章主要介绍Linux uptime实现详解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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实现详解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部