searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Linux 时间子系统及C库时间函数总结

2023-03-30 05:49:13
26
0

1. Linux 时间子系统

Linux时间系统是一个由多个不同组件构成的复杂系统,它主要包括硬件时钟、系统时钟、时间同步、时间处理等多个部分。以下是基于x86架构Linux时间系统主要的原理和工作流程:时间子系统的核心是Tick层,它的核心是基于硬件设备时钟事件触发的中断hrtimer interrupt。hrtimer会驱动上次的内核功能,比如更新jiffies;读取时钟源的数据并把数据同步到内核的timekeeper数据结构里;唤醒睡眠的进程等等。

1.1时钟源

硬件时钟源通常是一种低功率的晶体振器,通过振荡产生稳定的时钟信号,产生一个单调递增的计数,内核负责把这个计数转化为系统当前的时间点。通常这个计数的更新是由硬件完成的,比如目前主流64位服务器的首选时钟源为更新频率接近cpu的主频的tsc (时间戳计数器),tsc是一个高精度的时钟源,为固定的频率,可以使用rdtsc指令访问。可使用命令cat /sys/devices/system/clocksource/clocksource0/current_clocksource查询当前的时钟源。

除此之外系统还有一些non-stop的低精度时钟源比如硬件时钟寄存器rtc,rtc在下电的时候可以独立持续运行,一般用于启动时恢复初始时间。

1.2 时钟事件

时钟事件通常由底层硬件支持,通常是可编程的,负责在某个时间点触发中断,内核基于定时中断来做CPU调度,同时更新全局时间。通常时钟事件会引发Per-CPU level和全局level的tick更新。

1.3 Tick

Tick是一个逻辑概念,就是周期性的时钟中断,用来作为OS的心跳,它可以驱动scheduler运转,并且统计相关的运行信息。内核编译的时候会指定HZ这个参数,通常为1000,表示在系统中,每个Tick是1/HZ秒,这样把Tick和时间关联起来, Tick的数量由jiffies这个变量来表示。

1.4 Jiffies

Jiffies为Linux核心变量,它被用来纪录系统自开机以来,已经过多少的tick。每发生一次timer interrupt,Jiffies变数会被加1。

2. C库时间函数总结

用户态层面的用户使用时间主要基于c库函数,常用的获取与使用函数总结如下:

2.1 time()获取时间戳

函数定义如下:

time_t time(time_t *calptr);

time_t 是一个unsigned long类型,time函数用来获取日历时间的时间戳,该时间戳是从1970年1月1日0点(00:00:00 UTC, January 1, 1970)到现在经历的秒数。

calptr = NULL时,为得到当前日历时间(从1970-01-01 00:00:00到现在的秒数);

calptr = 时间数值时,用于设置日历时间,其返回值存储在timer中;

2.2 gettimeofday()和clock_gettime()高精度的时间

函数定义如下:

int gettimeofday(struct timeval *tp, void *tzp);。
int clock_gettime(clockid_t clock_id, strcut timespec *tsp);

time函数只能得到秒精度的时间,为了获得更高精度的时间戳,需要其他函数。gettimeofday函数可以获得微秒精度的时间戳,用结构体timeval来保存;clock_gettime函数可以获得纳秒精度的时间戳,用结构体timespec来保存。

两个函数使用的结构体定义如下:

struct timeval
{
    long tv_sec;    //秒
    long tv_usec;   //微秒
};

struct timespec
{
    time_t tv_sec;  //秒
    long tv_nsec;   //纳秒
};

2.3 gmtime()和localtime()时间戳-可视化时间转化

函数定义如下:

struct tm* gmtime(const time_t *timep);
struct tm* localtime(const time_t *timep);

gmtime将time_t格式的时间数值变换成格林威治标准时区时间,没有夏令时。

localtime将time_t格式的时间数值变换成本地时间,考虑到本地时区和夏令时标志;

得到的时间戳不能直观的展示现在的时间,为此需要使用tm结构体来表示成我们日常所见的时间,gmtime 和localtime可以将time_t类型的时间戳转为tm结构体。两者的区别是gmtime转换后的事件是对时间戳基于UTC进行转换;而localtime会基于当前系统的时区进行转换。

tm结构体定义如下:

struct tm
{
    int tm_sec;  /*秒,正常范围0-59, 但允许至61*/
    int tm_min;  /*分钟,0-59*/
    int tm_hour; /*小时, 0-23*/
    int tm_mday; /*日,即一个月中的第几天,1-31*/
    int tm_mon;  /*月, 从一月算起,0-11*/
    int tm_year;  /*年, 从1900至今已经多少年*/ 
    int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/
    int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/
    int tm_isdst; 
};

2.4 mktime()可视化时间-时间戳转化

函数定义如下:

time_t mktime(struct tm *tm);

mktime将tm格式时间转换为自1970年1月1日以来持续时间的秒数

在业务程序中,经常需要对比时间的先后,如果用字符串格式时间进行对比,需要保证格式完全一致,而且转为字符串形式也比较麻烦,因此更多时候用时间戳来进行比较。有的时候就需要将字符串形式的时间或者struct tm表示的时间转化为time_t的时间戳,这个转化就可以通过mktime函数来实现。

2.5 strftime()时间转换函数

函数定义如下:

size_t strftime(char* buf, size_t maxsize, const char *format, const struct tm *tmptr);

我们可以根据format指向字符串中格式,将timeptr中存储的时间信息按照format指定的形式输出到buf中,最多向缓冲区buf中存放maxsize个字符。该函数返回向buf指向的字符串中放置的字符数。

参数解释:

buf:存储输出的时间

maxsize:缓存区的最大字节长度

format:指定输出时间的格式

tmptr:指向结构体tm指针

函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明串 strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列可以参考linux man手册。

 

 

 

0条评论
0 / 1000
Accelerate
3文章数
0粉丝数
Accelerate
3 文章 | 0 粉丝
Accelerate
3文章数
0粉丝数
Accelerate
3 文章 | 0 粉丝
原创

Linux 时间子系统及C库时间函数总结

2023-03-30 05:49:13
26
0

1. Linux 时间子系统

Linux时间系统是一个由多个不同组件构成的复杂系统,它主要包括硬件时钟、系统时钟、时间同步、时间处理等多个部分。以下是基于x86架构Linux时间系统主要的原理和工作流程:时间子系统的核心是Tick层,它的核心是基于硬件设备时钟事件触发的中断hrtimer interrupt。hrtimer会驱动上次的内核功能,比如更新jiffies;读取时钟源的数据并把数据同步到内核的timekeeper数据结构里;唤醒睡眠的进程等等。

1.1时钟源

硬件时钟源通常是一种低功率的晶体振器,通过振荡产生稳定的时钟信号,产生一个单调递增的计数,内核负责把这个计数转化为系统当前的时间点。通常这个计数的更新是由硬件完成的,比如目前主流64位服务器的首选时钟源为更新频率接近cpu的主频的tsc (时间戳计数器),tsc是一个高精度的时钟源,为固定的频率,可以使用rdtsc指令访问。可使用命令cat /sys/devices/system/clocksource/clocksource0/current_clocksource查询当前的时钟源。

除此之外系统还有一些non-stop的低精度时钟源比如硬件时钟寄存器rtc,rtc在下电的时候可以独立持续运行,一般用于启动时恢复初始时间。

1.2 时钟事件

时钟事件通常由底层硬件支持,通常是可编程的,负责在某个时间点触发中断,内核基于定时中断来做CPU调度,同时更新全局时间。通常时钟事件会引发Per-CPU level和全局level的tick更新。

1.3 Tick

Tick是一个逻辑概念,就是周期性的时钟中断,用来作为OS的心跳,它可以驱动scheduler运转,并且统计相关的运行信息。内核编译的时候会指定HZ这个参数,通常为1000,表示在系统中,每个Tick是1/HZ秒,这样把Tick和时间关联起来, Tick的数量由jiffies这个变量来表示。

1.4 Jiffies

Jiffies为Linux核心变量,它被用来纪录系统自开机以来,已经过多少的tick。每发生一次timer interrupt,Jiffies变数会被加1。

2. C库时间函数总结

用户态层面的用户使用时间主要基于c库函数,常用的获取与使用函数总结如下:

2.1 time()获取时间戳

函数定义如下:

time_t time(time_t *calptr);

time_t 是一个unsigned long类型,time函数用来获取日历时间的时间戳,该时间戳是从1970年1月1日0点(00:00:00 UTC, January 1, 1970)到现在经历的秒数。

calptr = NULL时,为得到当前日历时间(从1970-01-01 00:00:00到现在的秒数);

calptr = 时间数值时,用于设置日历时间,其返回值存储在timer中;

2.2 gettimeofday()和clock_gettime()高精度的时间

函数定义如下:

int gettimeofday(struct timeval *tp, void *tzp);。
int clock_gettime(clockid_t clock_id, strcut timespec *tsp);

time函数只能得到秒精度的时间,为了获得更高精度的时间戳,需要其他函数。gettimeofday函数可以获得微秒精度的时间戳,用结构体timeval来保存;clock_gettime函数可以获得纳秒精度的时间戳,用结构体timespec来保存。

两个函数使用的结构体定义如下:

struct timeval
{
    long tv_sec;    //秒
    long tv_usec;   //微秒
};

struct timespec
{
    time_t tv_sec;  //秒
    long tv_nsec;   //纳秒
};

2.3 gmtime()和localtime()时间戳-可视化时间转化

函数定义如下:

struct tm* gmtime(const time_t *timep);
struct tm* localtime(const time_t *timep);

gmtime将time_t格式的时间数值变换成格林威治标准时区时间,没有夏令时。

localtime将time_t格式的时间数值变换成本地时间,考虑到本地时区和夏令时标志;

得到的时间戳不能直观的展示现在的时间,为此需要使用tm结构体来表示成我们日常所见的时间,gmtime 和localtime可以将time_t类型的时间戳转为tm结构体。两者的区别是gmtime转换后的事件是对时间戳基于UTC进行转换;而localtime会基于当前系统的时区进行转换。

tm结构体定义如下:

struct tm
{
    int tm_sec;  /*秒,正常范围0-59, 但允许至61*/
    int tm_min;  /*分钟,0-59*/
    int tm_hour; /*小时, 0-23*/
    int tm_mday; /*日,即一个月中的第几天,1-31*/
    int tm_mon;  /*月, 从一月算起,0-11*/
    int tm_year;  /*年, 从1900至今已经多少年*/ 
    int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/
    int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/
    int tm_isdst; 
};

2.4 mktime()可视化时间-时间戳转化

函数定义如下:

time_t mktime(struct tm *tm);

mktime将tm格式时间转换为自1970年1月1日以来持续时间的秒数

在业务程序中,经常需要对比时间的先后,如果用字符串格式时间进行对比,需要保证格式完全一致,而且转为字符串形式也比较麻烦,因此更多时候用时间戳来进行比较。有的时候就需要将字符串形式的时间或者struct tm表示的时间转化为time_t的时间戳,这个转化就可以通过mktime函数来实现。

2.5 strftime()时间转换函数

函数定义如下:

size_t strftime(char* buf, size_t maxsize, const char *format, const struct tm *tmptr);

我们可以根据format指向字符串中格式,将timeptr中存储的时间信息按照format指定的形式输出到buf中,最多向缓冲区buf中存放maxsize个字符。该函数返回向buf指向的字符串中放置的字符数。

参数解释:

buf:存储输出的时间

maxsize:缓存区的最大字节长度

format:指定输出时间的格式

tmptr:指向结构体tm指针

函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明串 strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列可以参考linux man手册。

 

 

 

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0