Linux系统下的单调时间函数

简介: 欢迎转载,转载请注明出处:http://forever.blog.chinaunix.net一、编写linux下应用程序的时候,有时候会用到高精度相对时间的概念,比如间隔100ms。那么应该使用哪个时间函数更准确呢?    1、time        该函数返回的是自1970年以来的秒数,显然精度不够,不能使用    2、gettimeofday        该函数返回的是自1970年以来的秒数和微秒数,精度显然是够了。

欢迎转载,转载请注明出处:http://forever.blog.chinaunix.net

一、编写linux下应用程序的时候,有时候会用到高精度相对时间的概念,比如间隔100ms。那么应该使用哪个时间函数更准确呢?
    1、time
        该函数返回的是自1970年以来的秒数,显然精度不够,不能使用
    2、gettimeofday
        该函数返回的是自1970年以来的秒数和微秒数,精度显然是够了。我想有很多程序员也是用的这个函数来计算相对时间的,如果说系统时间因为ntp等原因发生时间跳变,那么用这个函数来计算相对时间是不是就会出问题了。所以说这个函数也不能使用
    3、clock_gettime
        该函数提供了4种类型CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_PROCESS_CPUTIMEID、CLOCK_THREAD_CPUTIME_ID。从字面意思可以判断出来,CLOCK_MONOTONIC提供了单调递增的时间戳,该函数返回值为自系统启动后秒数和纳秒数,但是该函数没有考虑ntp的情况,所以并不是绝对意义上的单调递增(见二)。
CLOCK_REALTIME is affected by settime()/settimeofday() calls and can also be frequency corrected by NTP via adjtimex().
CLOCK_MONOTONIC is not affected by settime()/settimeofday(), but is frequency adjusted by NTP via adjtimex().With Linux,NTP normally uses settimeofday() for large corrections (over half a second). The adjtimex() inteface allows for small clock frequency changes (slewing). This can be done in a few different ways, see the man page for adjtimex.

CLOCK_MONOTONIC_RAW that will not be modified at all, and will have a linear correlation with the hardware counters.
    4、syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)
        该函数提供了真正意义上的单调递增时间(见三)


二、glibc 中clock_gettime(CLOCK_MONOTONIC)的原理
    查看glibc的代码可以看到这个数值是由内核计算的。

    __vdso_clock_gettime-------->do_monotonic
    这个函数的实现如下:
    

点击(此处)折叠或打开

  1. notrace static noinline int do_monotonic(struct timespec *ts)
  2. {
  3.         unsigned long seq, ns, secs;
  4.         do {
  5.                 seq = read_seqbegin(&gtod->lock);
  6.                 secs = gtod->wall_time_sec;
  7.                 ns = gtod->wall_time_nsec + vgetns();
  8.                 secs += gtod->wall_to_monotonic.tv_sec;
  9.                 ns += gtod->wall_to_monotonic.tv_nsec;
  10.         } while (unlikely(read_seqretry(&gtod->lock, seq)));
  11.         /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
  12.          * are all guaranteed to be nonnegative.
  13.          */
  14.         while (ns >= NSEC_PER_SEC) {
  15.                 ns -= NSEC_PER_SEC;
  16.                 ++secs;
  17.         } 
  18.         ts->tv_sec = secs;
  19.         ts->tv_nsec = ns; 
  20.         return 0;
  21. }

这个代码读取墙上时间,然后加上相对于单调时间的便宜,从而得到单调时间,但是这里并没有考虑ntp通过adjtimex()调整小的时间偏差的情况,所以这个仍然不是绝对的单调递增。
三、内核clock_gettime系统调用
    在kernel/posix-timers.c中内核实现了clock_gettime的系统调用,包括CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_MONOTONIC_RAW、CLOCK_REALTIME_COARSE、CLOCK_MONOTONIC_COARSE、CLOCK_BOOTTIME等类型,这里我们看一下CLOCK_MONOTONIC_RAW的实现
    

点击(此处)折叠或打开

  1. struct k_clock clock_monotonic_raw = {
  2.                 .clock_getres = hrtimer_get_res,
  3.                 .clock_get = posix_get_monotonic_raw,
  4.         };
  5. posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
  6. /*
  7.  * Get monotonic-raw time for posix timers
  8.  */
  9. static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)
  10. {
  11.         getrawmonotonic(tp);
  12.         return 0;
  13. }
  14. /**
  15.  * getrawmonotonic - Returns the raw monotonic time in a timespec
  16.  * @ts: pointer to the timespec to be set
  17.  *
  18.  * Returns the raw monotonic time (completely un-modified by ntp)
  19.  */
  20. void getrawmonotonic(struct timespec *ts)
  21. {
  22.         unsigned long seq;
  23.         s64 nsecs;
  24.         do {
  25.                 seq = read_seqbegin(&xtime_lock);
  26.                 nsecs = timekeeping_get_ns_raw();
  27.                 *ts = raw_time;
  28.         } while (read_seqretry(&xtime_lock, seq));
  29.         timespec_add_ns(ts, nsecs);
  30. }
  31. EXPORT_SYMBOL(getrawmonotonic);
  32. static inline s64 timekeeping_get_ns_raw(void)
  33. {
  34.         cycle_t cycle_now, cycle_delta;
  35.         struct clocksource *clock;
  36.         /* read clocksource: */
  37.         clock = timekeeper.clock;
  38.         cycle_now = clock->read(clock);
  39.         /* calculate the delta since the last update_wall_time: */
  40.         cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
  41.         /* return delta convert to nanoseconds using ntp adjusted mult. */
  42.         return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
  43. }


四、关于wall time和monotonic time
    wall time:xtime,取决于用于对xtime计时的clocksource,它的精度甚至可以达到纳秒级别,内核大部分时间都是使用xtime来获得当前时间信息,xtime记录的是自1970年当前时刻所经历的纳秒数。

    monotonic time: 该时间自系统开机后就一直单调地增加(ntp adjtimex会影响其单调性),它不像xtime可以因用户的调整时间而产生跳变,不过该时间不计算系统休眠的时间,也就是说,系统休眠时(total_sleep_time),monotoic时间不会递增。

    raw monotonic time: 该时间与monotonic时间类似,也是单调递增的时间,唯一的不同是,raw monotonic time不会受到NTP时间调整的影响,它代表着系统独立时钟硬件对时间的统计。
    boot time:  与monotonic时间相同,不过会累加上系统休眠的时间(total_sleep_time),它代表着系统上电后的总时间。
五、总结
    在linux下获取高精度单调递增的时间,只能使用syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)获取!

目录
相关文章
|
2月前
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
222 3
Linux系统禁用swap
|
2月前
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
333 3
|
3月前
|
Ubuntu Linux
计算机基础知识:linux系统怎么安装?
在虚拟机软件中创建一个新的虚拟机,并选择相应操作系统类型和硬盘空间大小等参数。将下载的 ISO 镜像文件加载到虚拟机中。启动虚拟机,进入安装界面,并按照步骤进行安装。安装完成后,可以在虚拟机中使用 Linux 系统。
|
3月前
|
存储 Ubuntu Linux
「正点原子Linux连载」第二章Ubuntu系统入门
在图2.8.2.4中,我们使用命令umount卸载了U盘,卸载以后当我们再去访问文件夹/mnt/tmp的时候发现里面没有任何文件了,说明我们卸载成功了。
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
297 0
Linux系统初始化脚本
|
3月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
235 18
|
2月前
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
283 1
|
2月前
|
监控 安全 Linux
Linux系统提权之计划任务(Cron Jobs)提权
在Linux系统中,计划任务(Cron Jobs)常用于定时执行脚本或命令。若配置不当,攻击者可利用其提权至root权限。常见漏洞包括可写的Cron脚本、目录、通配符注入及PATH变量劫持。攻击者通过修改脚本、创建恶意任务或注入命令实现提权。系统管理员应遵循最小权限原则、使用绝对路径、避免通配符、设置安全PATH并定期审计,以防范此类攻击。
1007 1
|
3月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
1575 10
|
3月前
|
安全 Linux 数据安全/隐私保护
为Linux系统的普通账户授予sudo访问权限的过程
完成上述步骤后,你提升的用户就能够使用 `sudo`命令来执行管理员级别的操作,而无需切换到root用户。这是一种更加安全和便捷的权限管理方式,因为它能够留下完整的权限使用记录,并以最小权限的方式工作。需要注意的是,随意授予sudo权限可能会使系统暴露在风险之中,尤其是在用户不了解其所执行命令可能带来的后果的情况下。所以在配置sudo权限时,必须谨慎行事。
578 0